其他分享
首页 > 其他分享> > 基于Qt的OpenGL(三):QOpenGLShaderProgram和GLSL

基于Qt的OpenGL(三):QOpenGLShaderProgram和GLSL

作者:互联网

QOpenGLShaderProgram是对ShaderProgram编译过程的封装,不管是加载SourceCode还是SourceFile,采用Qt的封装都是非常棒的。如果不封装,就会像下图一样,先把代码写入字符串,没有颜色标识,而且每行还得有换行符,非常麻烦。因此我们希望能像普通的C++代码一样编写Shader,好在Qt已经帮我们封装好了
在这里插入图片描述

为了在QT中正常加载并编辑shader文件:在工具->选项 中设置编码规则为UTF-8。

在这里插入图片描述

//类.h文件
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
class myopenglwidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    enum Shape{None,Rect,Circle,Triangle};
    explicit myopenglwidget(QWidget *parent = nullptr);
    ~myopenglwidget();
    void drawShape(Shape shape);
    void setWirefame(bool wireframe);
protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();
private:
    Shape m_shape;
    QOpenGLShaderProgram sharedprogram;
};
#endif // MYOPENGLWIDGET_H
//类.cpp文件
#include "myopenglwidget.h"
//创建VAO和VBO对象,并赋予ID
unsigned int VBO,VAO,EBO;
float vertices[] = {
    0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    -0.5f, 0.5f, 0.0f,
};
unsigned int indices[] = {
    0, 1, 3,
    1, 2, 3
};
myopenglwidget::myopenglwidget(QWidget *parent) : QOpenGLWidget(parent)
{
}
myopenglwidget::~myopenglwidget()
{
    makeCurrent();//调用当前状态 不用管为什么,加就好了
    glDeleteBuffers(1,&VBO);
    glDeleteBuffers(1,&EBO);
    glDeleteVertexArrays(1,&VAO);
    doneCurrent();//改变当前状态 不用管为什么,加就好了
}
void myopenglwidget::drawShape(myopenglwidget::Shape shape)
{
    m_shape = shape;
    update();
}
void myopenglwidget::setWirefame(bool wireframe)
{
    makeCurrent();
    if(wireframe)
        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
    else
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
    update();
    doneCurrent();

}
void myopenglwidget::initializeGL()
{
    initializeOpenGLFunctions();
    glGenVertexArrays(1,&VAO);
    glGenBuffers(1,&VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    sharedprogram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/shapes.vert");
    sharedprogram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/shapes.frag");
    bool success = sharedprogram.link();
    if (!success)
        qDebug()<<"error";
    glGenBuffers(1,&EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
    glBindVertexArray(0);
}
void myopenglwidget::resizeGL(int w, int h)
{
}
void myopenglwidget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    sharedprogram.bind();
    glBindVertexArray(VAO);
    switch(m_shape){
    case Rect:
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        break;
    default:
        break;
    }
}
//shapes.frag
#version 330 core
out vec4 FragColor;
void main()
{
    FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}
//shapes.vert
#version 330 core\n
layout (location = 0) in vec3 aPos;
void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
}

GLSL:OpenGL Shading Language

一个典型的shader程序应该是这样的

nt nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);//nrAttributes≥16

GLSL的基础知识

vec2 vect = vec2(0.1, 0.2);
vec2 res = vec4(vect, 0.3, 0.0);//(0.1, 0.2, 0.3, 0.0)
vec2 res2 = vec4(res.xyz, 0.5);//(0.1, 0.2, 0.3, 0.5)
vec2 res3 = vec4(res.xxx, 0.7);//(0.1, 0.1, 0.1, 0.7)

GLSL如何使用

顶点着色器接收的是一种特殊形式的输入,否则就会效率低下

//myopenglwidget.cpp
#include "myopenglwidget.h"
//创建VAO和VBO对象,并赋予ID
unsigned int VBO,VAO,EBO;
float vertices[] = {
    0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    -0.5f, 0.5f, 0.0f,
};
unsigned int indices[] = {
    0, 1, 3,
    1, 2, 3
};
myopenglwidget::myopenglwidget(QWidget *parent) : QOpenGLWidget(parent)
{
}
myopenglwidget::~myopenglwidget()
{
    makeCurrent();//调用当前状态 不用管为什么,加就好了
    glDeleteBuffers(1,&VBO);
    glDeleteBuffers(1,&EBO);
    glDeleteVertexArrays(1,&VAO);
    doneCurrent();//改变当前状态 不用管为什么,加就好了
}
void myopenglwidget::drawShape(myopenglwidget::Shape shape)
{
    m_shape = shape;
    update();
}
void myopenglwidget::setWirefame(bool wireframe)
{
    makeCurrent();//调用当前状态
    if(wireframe)
        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
    else
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
    update();
    doneCurrent();//改变当前状态
}
void myopenglwidget::initializeGL()
{
    initializeOpenGLFunctions();
    sharedprogram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/shapes.vert");
    sharedprogram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/shapes.frag");
    bool success = sharedprogram.link();
    if (!success)
        qDebug()<<"error";
    glGenVertexArrays(1,&VAO);//顶点数组用来存数据的结构
    glGenBuffers(1,&VBO);//缓冲区用来存放顶点数据
    //绑定VBO和VAO对象
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    //为当前绑定到数据的缓冲区对象开辟一个新的数据空间,如果数据不为空,则数据从内存传到显存
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
    sharedprogram.bind();
    GLint posLocation = 2;
    sharedprogram.bindAttributeLocation("aPos",posLocation);//绑定变量aPos的位置
    //告知显卡如何解析传过去的数据,该过程会被VAO偷偷记录
    glVertexAttribPointer(posLocation,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//第0个属性、三个值、浮点型、不需要标准化,步长,偏移量
    //开启VAO管理的第一个属性值,因为默认所有属性都是关闭的
    glEnableVertexAttribArray(posLocation);
    //小助理可以休息了,养成好习惯,因为以后有很多的小助理
    glBindBuffer(GL_ARRAY_BUFFER,0);
    //绑定VEO对象
    glGenBuffers(1,&EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
    glBindVertexArray(0);
}
void myopenglwidget::resizeGL(int w, int h)
{
}
void myopenglwidget::paintGL()//绘制都在这里面,别的地方只是进行一个触发
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    sharedprogram.bind();
    glBindVertexArray(VAO);
    switch(m_shape){
    case Rect:
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        break;
    default:
        break;
    }
}
//shapes.vert
#version 330 core
in vec3 aPos;
out vec4 vertexColor;
void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
    vertexColor = vec4(1.0, 0.5, 0.2, 1.0);
}

标签:GLSL,myopenglwidget,void,0.5,shape,Qt,GL,着色器,QOpenGLShaderProgram
来源: https://blog.csdn.net/qq_42308217/article/details/120597612