Qt编程环境下学习《OpenGL编程指南(原书第九版)》(一)

时间:2024-04-04 13:28:12

背景

    因项目的需要,本人开始学习OpenGL的编程知识,所以以《OpenGL编程指南(原书第九版)》作为学习样板。因之前一直用Qt进行项目的开发,深感Qt编程框架对于项目开发的强大和易用。而书上的样本例程采用的GLFW框架,安装和调试仍然需要花费一定的时间进行学习和熟悉,一旦出现问题后,因GLFW框架的资料过少,一旦出现问题后,势必给学习者带来负担。因此,我尝试用Qt来学习书中的例子程序,并做相应的修改。(文中的每一个程序,都经过了作者的实际编译和运行)。

运行环境如下:

Win10家庭中文版(64位)

显卡GeForce MX250

16G RAM

Qt版本号 5.12.3(Visual Studio 2017 编译器)

第一章

书中的内容我就不赘述了,本文主要着重说明Qt下程序的修改重点,文尾将附上完整的程序。

我们利用Qt建立一个桌面Application框架,新建一个QOpenGLWidget的类来进行OpenGL的操作。MainWindow类创建初始化代码中,加入相应的界面创建代码:

    OpenGLWidget* openGLWidget = new OpenGLWidget(this);

    QVBoxLayout* centralLayout = new QVBoxLayout();

    centralLayout->addWidget(openGLWidget);

this->ui->centralWidget->setLayout(centralLayout);

以上代码非常简单,主要修改的代码位于OpenGLWidget类,首先看下头文件:

/*

        Created By APYang 2019/11/5

*/

#include <QWidget>

#include <QOpenGLWidget>

#include <QOpenGLFunctions>

#include <QOpenGLExtraFunctions>

#include <QOpenGLShaderProgram>

#include <QOpenGLFunctions_4_5_Core>

#define BUFFER_OFFSET(offset) ((void *)(offset)

 

const GLuint NumVertices = 6;

 

class OpenGLWidget : public QOpenGLWidget,protected QOpenGLFunctions

{

 

    QOpenGLShaderProgram *program;

    GLuint programId;

 

    enum VAO_IDs{Triangles, NumVAOs};

    enum Buffer_IDs{ArrayBuffer, NumBuffers};

    enum Attrib_IDs{vPosition = 0};

 

    GLuint VAOs[NumVAOs];

    GLuint Buffers[NumBuffers];

 

public:

    explicit OpenGLWidget(QWidget *parent = 0);

 

protected:

    void initializeGL();

    void paintGL();

    void resizeGL(int w, int h);

    void initVbo();

};

 

说明:

  1. 在include 区域,我们引入了QOpenGLFunctions_4_5_Core,因为不引入这个头,书上的函数就没法使用,默认是OpenGL1.1的API。
  2. OpenGLWidget类的四个方法,其中initializeGL()放初始化代码、paintGL()完成绘制功能、resizeGL()用于窗口大小变化后的重绘、initVbo()用于初始化顶点。

 

接下来是OpenGLWidget类实现:

 

OpenGLWidget::OpenGLWidget(QWidget *parent)

{

 

}

 

 

 

void OpenGLWidget::initializeGL()

{

 

 

    initializeOpenGLFunctions();

 

 

    program = new QOpenGLShaderProgram(this);

 

    if(!program->addShaderFromSourceCode(QOpenGLShader::Vertex, "#version 450 core\n"

                                         "layout (location =0) in vec4 vPosition;\n"

                                         "void main(void)\n"

                                         "{gl_Position =  vPosition;}")){

        return;

    }

    if(!program->addShaderFromSourceCode(QOpenGLShader::Fragment,"#version 450 core\n"

                                         "layout (location = 0) out vec4 fColor;\n"

                                         "void main(void)\n"

                                         "{fColor = vec4(0.5,0.4,0.8,1.0);}")){

        return;

    }

    if(!program->link()){

        return;

    }

    if(!program->bind()){

        return;

    }

 

    programId = program->programId();

    initVbo();

}

void OpenGLWidget::resizeGL(int w, int h)

{

    glViewport(0, 0, w, h);

}

 

void OpenGLWidget::paintGL()

{

    QOpenGLFunctions_4_5_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();

    if (!f){

        qWarning()<<"Could not obtain required OpenGL context version";

        exit(1);

    }

    float black[] = {0.0f,0.0f,0.0f,0.0f};

    f->glClearBufferfv(GL_COLOR,0,black);

    f->glBindVertexArray(VAOs[Triangles]);

    f->glDrawArrays(GL_TRIANGLES, 0, NumVertices);

}

void OpenGLWidget::initVbo(){

    QOpenGLFunctions_4_5_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();

    if (!f){

        qWarning()<<"Could not obtain required OpenGL context version";

        exit(1);

    }

 

    GLfloat vertex[NumVertices][2] = {

        {-0.9f,-0.9f},

        {0.85f, -0.9f},

        {-0.9f, 0.85f},

        {0.9f,-0.85f},

        {0.9f, 0.9f},

        {-0.85f, 0.9f},

    };

 

    f->glCreateVertexArrays(NumVAOs,VAOs);

 

    f->glCreateBuffers(NumBuffers,Buffers);

    f->glNamedBufferStorage(Buffers[ArrayBuffer], sizeof(vertex), vertex,0);

 

    f->glBindVertexArray(VAOs[Triangles]);

    f->glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);

 

    f->glVertexAttribPointer(vPosition, 2, GL_FLOAT,GL_FALSE,0, BUFFER_OFFSET(0));

    f->glEnableVertexAttribArray(vPosition);

 

}

其中需要说明的要点:

  1. API的获取需要使用QOpenGLFunctions_4_5_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>()来进行,当然你也可以用其他不同的版块接口。
  2. 着色器代码的加载和编译,我们直接用Qt的相关类进行了处理,很是方便。(下一章,我们将直接用原生API进行加载、链接和编译)。

运行结果如下:

Qt编程环境下学习《OpenGL编程指南(原书第九版)》(一)