OpenGL development in QT starts

Environment Construction in OpenGL

Recently, because I need to make an OpenGL program for GUI display, I want to use QT as an interface, and I need to write OpenGL in QT. After configuring the environment, I will sum it up here.

QT Basics

Overall, the version of QT is more confusing, and sometimes it is not clear QT dialog/widget/mainwindow. It also needs to have an interface and profiles. After a circle, plus the confusion of the online tutorial version, it is already messy. Later, with the help of my classmates, I read some blog tutorials, synthesized it, and finally put up the shelf. The version information used in this article is as follows:
QT version: QT 5.6.2
VS version: VS 2013

Project selection:
This article selects the widgtcategory of QT. The difference between each category of QT is that it inherits from different base classes. The normal one widgtis the most basic. It does not contain the menu bar by default. If necessary, we can add it ourselves. If you choose not to create a UI file when building a project, it is found in programming that using the UI file will be confusing and inconvenient to control, so all the UI in the code is controlled by the code. Here is the code structure:

// main.cpp
// main是主入口,QApplication是生成一个QT应用,widget是继承自Qwidget的子类,具有show函数,实例化后将会产生一个窗口,同时我们也可以在main函数中实例化多个窗口,将会有多个界面,比如实例化一个button。
#include "widget.h"
#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
// 主窗口
    Widget w;
    w.show();
// 实例化一个button
    QPushButton q;
    q.show();
    return a.exec();
}

The effect of instantiating the button:
write picture description here

widgetTherefore, the main work is to add controls to our class and implement functions. The main widgetcode is as follows, inherited from QWeidget:

class Widget : public QWidget
{
    Q_OBJECT// 一个宏,声明为QT的object,方便传参

public:
    Widget(QWidget *parent = 0);
    ~Widget();    
    Q_OpenGL *q_widget_1;
    Q_OpenGL *q_widget_2;
    QGridLayout * main_layout;
    QPushButton * q_pushbutton_1;
    QPushButton * q_pushbutton_2;
    QMenuBar * q_menubar;
    QMenu * q_menu;
    QStatusBar * q_status;
    QLabel * q_label;

public slots:
    void triggerMenu(QAction * qa);
};

OpenGL in QT

QT encapsulates OpenGL for us, which is simpler to use than native OpenGL

  • OpenGL in QT already contains most of the functions of OpenGL, including the following header files
    • OpenGLWindow
    • QOpenGLWidget
    • QOpenGLFunctions
    • QOpenGLBuffer

Writing in QT OpenGLneeds to inherit from QOpenGLWidgetand rewrite two functions initializeGL[initialize OpenGL environment] and paintGL[main painting loop]. Compared with the native OpenGLcomplex initialization and drawing process, it is very simple. Below are the header files and part of the source code.

// .h
class Q_OpenGL:public QOpenGLWidget,protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit Q_OpenGL(QWidget *parent = 0);
    ~Q_OpenGL();
    void initializeGL();// 初始化
    void paintGL();// 主绘制
    void setUp();
    void compileShader();
    QOpenGLShaderProgram *program;
    Shader * shader;
    Model * model;
};

// .cpp
// 初始化OpenGL
void Q_OpenGL::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    setUp();
    compileShader();    

}
// 编译shader
void Q_OpenGL::compileShader()
{
    std::ifstream vs("E:\\Documents\\Qt\\qtWindows\\normal.vs");
    std::string vertexCode;
    std::string fragmentCode;
    if (vs.is_open())
    {
        std::string line;
        while (getline(vs, line)) {
            vertexCode.append(line);
            vertexCode.append("\n");
        }
        vs.close();
    }
    vs.open("E:\\Documents\\Qt\\qtWindows\\normal.fs");
    //qDebug()<<"8989"<<endl;
    if (vs.is_open()) {
        std::string line;
        while (getline(vs, line)) {
            fragmentCode.append(line);
            fragmentCode.append("\n");
        }
        vs.close();
    }
    qDebug() << "hhhh" << endl;
    QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
    vshader->compileSourceCode(vertexCode.c_str());
    QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
    fshader->compileSourceCode(fragmentCode.c_str());
    program = new QOpenGLShaderProgram;
    program->addShader(vshader);
    program->addShader(fshader);
    //program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
    //program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
    program->link();
    program->bind();
    //program->setUniformValue("texture", 0);
}
// 传递数据到VBO
void Q_OpenGL::setUp()
{
    int coords[3][2] = { -1, -1, 0, 1, 1, -1 };
    QVector<float> vertData;
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 2; ++j)         
            vertData.append(coords[i][j]);
    vbo.create();
    vbo.bind();
    vbo.allocate(vertData.constData(), vertData.count() * sizeof(float));
}

// 主绘制函数
void Q_OpenGL::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
    //program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
    program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 2, 2 * sizeof(float));
    //program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 0 * sizeof(GLfloat));
    //program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

The above code basically shows OpenGLthe writing process in QT. There are some mismatches in the code. You can check the official QT OpenGLexample. [I refer to the texturesexample]

Using native OpenGL in QT

In use, it is found that the OpenGL in QT is quite different from the native one, and there will be some problems in porting the code. So consider porting native OpenGL to QT, use QT's OpenGL for initialization, but use native OpenGL for drawing and shader.

But in practice, it is found that there will be conflicts in QT OpenGLand native , and they cannot be initialized at the same time. OpenGLI found a solution on the Internet. It is necessary to isolate the native OpenGLand QT ones OpenGL, and they cannot appear in the same cpp, so the class declaration and definition are separated [== the original diagram is conveniently written together], mainly the shader compilation class, Model class. When the declaration, definition and initialization are OpenGLdelayed in the header file cpp, the header file is introduced into the main program, so that the native can be used OpenGL.

Tips: In actual operation, I don't know why gladit cannot be initialized, and glewit is successful to use it instead. Here is the code passed:

// shader.h
#ifndef SHADER_H
#define SHADER_H
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

class Shader
{
public:
    unsigned Program;
    Shader(const char* vertexPath, const char* fragmentPath);
    ~Shader();
    void Use();
    void setBool(const std::string &name, bool value) const;
    void setInt(const std::string &name, int value) const;
    void setFloat(const std::string &name, float value) const;
    void setVec2(const std::string &name, const glm::vec2 &value) const;
    void setVec2(const std::string &name, float x, float y) const;
    void setVec3(const std::string &name, const glm::vec3 &value) const;
    void setVec3(const std::string &name, float x, float y, float z) const;
    void setVec4(const std::string &name, const glm::vec4 &value) const;
    void setVec4(const std::string &name, float x, float y, float z, float w) const;
    void setMat2(const std::string &name, const glm::mat2 &mat) const;
    void setMat3(const std::string &name, const glm::mat3 &mat) const;
    void setMat4(const std::string &name, const glm::mat4 &mat) const;
};

#endif

// shader.cpp,只列出部分
//#include <glad/glad.h>
#define GLEW_STATIC
#include <gl/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "shader.h"
using namespace std;

Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
{

}

Shader::~Shader()
{

}

void Shader::Use()
{
    glUseProgram(this->Program);
}

// model.h
#pragma once
#include "shader.h"
class Model
{
public:
    void setUp();
    void draw(Shader *);
    unsigned VAO;
    unsigned VBO;
};

// 更新后的qtOpenGL
#ifndef Q_OPENGL_H
#define Q_OPENGL_H

#include <QOpenGLWindow>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include "shader.h"
#include "model.h"

QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram);
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)

class Q_OpenGL:public QOpenGLWidget,protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit Q_OpenGL(QWidget *parent = 0);
    ~Q_OpenGL();
    void initializeGL();
    void paintGL();
    void setUp();
    void compileShader();
    QOpenGLShaderProgram *program;
    Shader * shader;
    Model * model;
};

#endif // Q_OPENGL_H

// QOpenGL实现
#include "q_opengl.h"
#include <QOpenGLBuffer>
#include <QMouseEvent>
#include <QOpenGLShaderProgram>
#include <QFile>
#include <QVector>
#include <fstream>
#include <string>
#include <iostream>

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

}

void Q_OpenGL::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);   
    shader = new Shader("E:\\Documents\\Qt\\qtWindows\\normal.vs", "E:\\Documents\\Qt\\qtWindows\\normal.fs");
    model = new Model();
    model->setUp();
}

void Q_OpenGL::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    model->draw(shader);
}

Q_OpenGL::~Q_OpenGL()
{

}

The effect diagram is as follows:
write picture description here

If you have any questions, please contact us~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325769029&siteId=291194637