Qt+OpenGL——第一个三角形

在使用纯C++进行OpenGL开发的时候,需要使用额外的库(例如:GLFW、GLAD等),但是使用Qt进行OpenGL开发时将不再需要安装额外的库,自Qt5.4以后Qt便有了QOpenGLWidget类使我们方便的进行开发。

初学OpenGL在求助前辈后得到一个国外大神编写的OpenGL教程,由国内大神进行了翻译(网址在文末给出)。但是大神是用的纯C++进行的开发,所以并不是很适合Qt+OpenGL的模式。那么如何根据大神的代码进行修改变成适合Qt的代码呢?

 

1、创建自定义OpenGLWidget并继承自QOpenGLWidget以及QOpenGLFunctions_3_0(此处根据需要采用的OpenGL版本进行调整,为了跟教程一致故笔者采用3.0版本);

2、实现QOpenGLWidget的三个纯虚函数initializeGL()、paintGL()、resizeGL(int w,int h)以及初始化functions。代码如下:

//openglwidget_glfw.h文件
#ifndef OPENGL_GLFW_H
#define OPENGL_GLFW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_0>
#include <QObject>
#include <QWidget>


class OpenGL_GLFW:public QOpenGLWidget,protected QOpenGLFunctions_3_0
{
    Q_OBJECT
public:
    explicit OpenGL_GLFW(QWidget *parent = nullptr);
    ~OpenGL_GLFW();

protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w,int h);

private:
    unsigned int shaderProgram;
};

#endif // OPENGL_GLFW_H
//openglwidget_glfw.cpp
#include "opengl_glfw.h"
#include <QDebug>

float vertices[] = {
    -0.5f,-0.5f,0.0f,
    0.5f,0.5f,0.0f,
    0.0f,0.5f,0.0f
};

//顶点着色器源码
const char *vertexShaderSource = "#version 330 core\n"
                                 "layout (location = 0) in vec3 aPos;\n"
                                 "void main()\n"
                                 "{\n"
                                 "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                                 "}\0";

//片段着色器源码
const char *fragmentShaderSource = "#version 330 core\n"
                                   "out vec4 FragColor;\n"
                                   "void main()\n"
                                   "{\n"
                                   "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
                                   "}\n\0";

OpenGL_GLFW::OpenGL_GLFW(QWidget *parent):
    QOpenGLWidget(parent)
{

}

OpenGL_GLFW::~OpenGL_GLFW()
{

}

void OpenGL_GLFW::initializeGL()
{
    initializeOpenGLFunctions();
}

void OpenGL_GLFW::paintGL()
{

}

void OpenGL_GLFW::resizeGL(int w, int h)
{
    glViewport(0,0,w,h);
}

3、教程中的定义着色器部分以及编译链接着色器只需要执行一次,故我们放在initializeGL中,代码如下:

void OpenGL_GLFW::initializeGL()
{
    initializeOpenGLFunctions();

    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);//创建顶点着色器
    glShaderSource(vertexShader,1,&vertexShaderSource,NULL);//参数2为需要编译的着色器源码的数量
    glCompileShader(vertexShader);

    int  success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);//检查着色器编译是否成功
    if(!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);//获取错误消息
        qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog;
    }

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//创建片段着色器
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    success = -1;
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);//检查着色器编译是否成功
    if(!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);//获取错误消息
        qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog;
    }

    shaderProgram = glCreateProgram();//创建程序对象
    glAttachShader(shaderProgram,vertexShader);//附加着色器到程序对象上
    glAttachShader(shaderProgram,fragmentShader);//附加着色器到程序对象上
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);//检查程序对象编译是否成功
    if(!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::SHADERPROGRAM::COMPILATION_FAILED\n" << infoLog;
    }

    glUseProgram(shaderProgram);//激活程序对象
    glDeleteShader(vertexShader);//删除顶点着色器
    glDeleteShader(fragmentShader);//删除片段着色器

}
}

4、绘制代码放入paintGL中,代码如下:

void OpenGL_GLFW::paintGL()
{

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    float vertices[] = {
        -0.5f, -0.5f, 0.0f, // left
        0.5f, -0.5f, 0.0f, // right
        0.0f,  0.5f, 0.0f  // top
    };

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    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);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);

    glUseProgram(shaderProgram);
    glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
    glDrawArrays(GL_TRIANGLES, 0, 3);

}

代码运行结果如下:

笔者Qt版本:5.8.0

完整代码:https://download.csdn.net/download/juicyactivegilbert/11184953

参考网址:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/

发布了28 篇原创文章 · 获赞 4 · 访问量 7395

猜你喜欢

转载自blog.csdn.net/JuicyActiveGilbert/article/details/90294280