OpenGL中环境搭建
近期由于需要做一个GUI展示的OpenGL程序,因此想到用QT来做界面,需要在QT中写OpenGL,配完环境后,在这里总计一下。
QT基础
总体看来,QT的版本较为混乱,有时候傻傻弄不清楚,QT dialog/widget/mainwindow
。又需要有界面,又要有pro
文件,一圈下来,加上网上教程版本混乱,已经凌乱了。后来在同学帮助下,看了一些博客教程,综合了一下,总算把架子搭起来了。本文使用的版本信息如下:
QT版本:QT 5.6.2
VS版本:VS 2013
工程选择:
本文选择的是QT的widgt
类别,QT各个类别的区别在于继承于不同的基类,正常的widgt
是最基础的,不默认含有菜单栏这些东西,需要的话我们自己添加。选择建立工程时不建立UI文件,在编程中发现使用UI文件会较为混乱,不方便控制,因此代码中所有的UI都是由代码控制的。以下是代码结构:
// 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();
}
实例化button的效果:
所以,主要的工作就是往我们的widget
类中添加控件,实现功能即可。主widget
代码如下,继承自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);
};
QT中的OpenGL
QT中为我们把OpenGL进行了封装,使用较原生OpenGL简单
- QT中的OpenGL,已经包含了OpenGL的大部分功能,包含如下头文件
- OpenGLWindow
- QOpenGLWidget
- QOpenGLFunctions
- QOpenGLBuffer
在QT中写OpenGL
需要继承自QOpenGLWidget
,同时重写两个函数initializeGL
【初始化OpenGL环境】和paintGL
【主绘画的循环】。相对于原生的OpenGL
复杂的初始化和绘制过程,十分简洁。以下是头文件和部分源代码。
// .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);
}
以上代码基本展示QT中OpenGL
的编写过程,代码有一些不匹配,可以查看QT官方的OpenGL
例子即可。【我参考的是textures
例子】
QT中使用原生OpenGL
在使用中,发现QT中的OpenGL与原生差异较大,移植代码会有一些问题。所以考虑将原生OpenGL移植到QT中,使用QT的OpenGL进行初始化,但在绘制,shader方面使用原生的OpenGL。
但在实践中发现,QT中的OpenGL
和原生的OpenGL
会出现冲突,无法同时初始化。网上找了解决方案,需要将原生的OpenGL
与QT的OpenGL
进行隔离,不能出现在同一个cpp中,于是将类的声明和定义分离【==原来图方便写在了一起】,主要是shader编译类,模型类。在头文件中声明,定义和初始化OpenGL
延迟到cpp
时,再将头文件引入到主程序中,这样就可以使用原生OpenGL
。
tips:在实际操作时,不知道为何glad
无法初始化,改用glew
才成功。以下是通过的代码:
// 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()
{
}
效果图如下:
如有问题欢迎联系指出~