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 pro
files. 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 widgt
category of QT. The difference between each category of QT is that it inherits from different base classes. The normal one widgt
is 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:
widget
Therefore, the main work is to add controls to our class and implement functions. The main widget
code 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 OpenGL
needs to inherit from QOpenGLWidget
and rewrite two functions initializeGL
[initialize OpenGL environment] and paintGL
[main painting loop]. Compared with the native OpenGL
complex 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 OpenGL
the writing process in QT. There are some mismatches in the code. You can check the official QT OpenGL
example. [I refer to the textures
example]
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 OpenGL
and native , and they cannot be initialized at the same time. OpenGL
I found a solution on the Internet. It is necessary to isolate the native OpenGL
and 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 OpenGL
delayed 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 glad
it cannot be initialized, and glew
it 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:
If you have any questions, please contact us~