QT5 内嵌OpenGL 第一个三角形

找了网上的博客,照着做了,发现其中有不少坑,特此记录,与君共勉。
传送门

1 在新建qt widget application 之后,开始进入正式内容

2 新建c++类,类名为OpenGLWidget,基类为QOpenGLWidget,勾选Include QWidget
QT5 内嵌OpenGL 第一个三角形_第1张图片

3 编辑OpenGLWidget类,代码如下

openglwidget.h

#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H

#include 
#include 
#include 
#include 

class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    OpenGLWidget();

protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w, int h);
    void initVbo();
private:
    GLint matrixLocation;
    GLint vertexLocation;
    GLint colorLocation;
    GLint programId;

    int vVerticesLen;
    int triIndexLen;
    int colorsLen;

    GLuint verVbo;
    GLuint indexVbo;
    GLuint colorVbo;
    QOpenGLShaderProgram* program;

    GLfloat* vertex;
    GLuint* triIndexs;
    GLfloat* colors;

    //GL_FLOAT_MAT4 projection;
    QMatrix4x4 projection;
};

#endif // OPENGLWIDGET_H

openglwidget.cpp

#include "openglwidget.h"

OpenGLWidget::OpenGLWidget()
{
}

void OpenGLWidget::initializeGL()
{


    //调用内容初始化函数
    initializeOpenGLFunctions();

    //三角形顶点坐标
    vertex = new GLfloat[6]{
                -0.5f,0,
                0.5f,0,
                0,0.5f
            };

    //三角形顶点索引
    triIndexs =new GLuint[3] {0, 1, 2};

    //三角形顶点颜色
    colors= new GLfloat[12]{1.0f, 0.0f, 0.0f, 1.0f,
                        0.0f, 1.0f, 0.0f, 1.0f,
                        0.0f, 0.0f, 1.0f, 1.0f
                       };

    program = new QOpenGLShaderProgram(this);
    if(!program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/fragmentShader.frag")){
        return;
    }
    if(!program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/vertexShader.vert")){
        return;
    }

    if(!program->link()){
        return;
    }
    if(!program->bind()){
        return;
    }

    // 获取shaderprogram的id号,然后可以通过id号获取一些属性...
    programId = program->programId();

    // 从shaderprogram里面获取变量标识
    matrixLocation = glGetUniformLocation(programId, "matrix");
    vertexLocation = glGetAttribLocation(programId, "vPosition");
    colorLocation = glGetAttribLocation(programId, "vColor");

    initVbo();
}

void OpenGLWidget::initVbo(){
    // 计算获得数组长度
    //vVerticesLen = sizeof(vertex)/sizeof(GLfloat);
    //triIndexLen = sizeof(triIndexs)/sizeof(GLuint);
   // colorsLen = sizeof(colors)/sizeof(GLfloat);
    vVerticesLen = 6;
    triIndexLen = 3;
    colorsLen = 12;
    qDebug() << vVerticesLen << " " << triIndexLen << " " << colorsLen;
    // 初始化顶点buffer并装载数据到显存
    glGenBuffers(1, &verVbo);
    glBindBuffer(GL_ARRAY_BUFFER, verVbo);
    glBufferData(GL_ARRAY_BUFFER, vVerticesLen * sizeof(GLfloat), vertex, GL_STATIC_DRAW);

    // 初始化索引buffer并装载数据到显存
    glGenBuffers(1, &indexVbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, triIndexLen * sizeof(GLuint), triIndexs, GL_STATIC_DRAW);

    // 初始化颜色buffer并装载数据到显存
    glGenBuffers(1, &colorVbo);
    glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
    glBufferData(GL_ARRAY_BUFFER, colorsLen * sizeof(GLfloat), colors, GL_STATIC_DRAW);
}

void OpenGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        // shader传入模型视图矩阵 projection可以理解为建立了一个坐标系空间,可以再这个空间内设置图形
        glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, projection.data());

        // shader绑定并启用颜色数组buffer
        glBindBuffer(GL_ARRAY_BUFFER,colorVbo);
        glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(colorLocation);
        // 颜色值rgba,所以每四个float值作为一个颜色值,如果只是希望rgb,取三个值作为颜色值即可!


        // shader绑定并启用顶点数组buffer
        glBindBuffer(GL_ARRAY_BUFFER, verVbo);
        glVertexAttribPointer( vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(vertexLocation);

        // shader绑定并顶点索引数组buffer - 索引无需启用
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indexVbo);
        glDrawElements(GL_TRIANGLES, triIndexLen, GL_UNSIGNED_INT,0);

        // 解绑buffer、关闭启用顶点、颜色数组
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDisableVertexAttribArray(vertexLocation);
        glDisableVertexAttribArray(colorLocation);
}

void OpenGLWidget::resizeGL(int w, int h)
{
    //当窗口大小改变时,调整界面坐标显示高度和宽度
    glViewport(0, 0, w, h);

    // 模型矩阵重置
    projection.setToIdentity();
    // 透视投影
   // qreal aspect = qreal(w) / qreal(h ? h : 1);
   // projection.perspective(60.0f, aspect, 1.0f, 100.0f);
    // 增加了模型矩阵,需要做一定偏移量,保证物体刚开始渲染出来时可以被看到!
   // projection.translate(0.0f, 0.0f, -2.0f);
}

4 在MainWindow的构造函数中新建OpenGLWidget对象,并插入ui中,代码如下

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "openglwidget.h"
#include "QVBoxLayout"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    OpenGLWidget* openGLWidget = new OpenGLWidget();
    //为了便于让OpenGLWidget自动填充父窗口,这里为父窗口设置了一个布局
    QVBoxLayout* centralLayout = new QVBoxLayout();
    centralLayout->addWidget(openGLWidget);
    this->ui->centralWidget->setLayout(centralLayout);
}

MainWindow::~MainWindow()
{
    delete ui;
}

5 这里会用到两个shader文件,一个是顶点shader vertexShader.vert ,一个是片元shader fragmentShader.frag。
代码如下:
vertexShader.vert

#version 330 core
uniform mat4 matrix;
in vec4 vPosition;
in vec4 vColor;
out vec4 fColor;

void main(void)
{
    fColor = vColor;
    gl_Position = matrix * vPosition;
}

fragmentShader.frag

#version 330 core
in vec4 fColor;
out vec4 fragColor;
void main(void)
{
    //gl_FragColor = fColor;
    fragColor = vec4(1,0,0,1);
}

6 我之前是直接在qt中新建glsl文件,然后它的默认位置是与pro文件同一目录下,然后使用”vertexShader.vert”,会报错:unable to open file “vertexShader.vert”。
之后再各种搜索之后发现别人给出的建议是,采用资源文件的方式来访问这两个shader文件,不会出错。
具体的步骤就是:
在qt中新建资源文件,然后添加前缀,添加文件的方式,将这两个文件添加到资源文件中。比如这里vertexShader.vert位于默认位置,那么先添加前缀 /shader,然后添加文件vertexShader.vert。这样就可以使用路径 “:/shader/vertexShader.vert” 来访问该文件了

你可能感兴趣的:(OpenGL,QT)