1. 开发布景
大多数人学习OpenGL估量都是从LearnOpenGL这个网站开始的吧,这个教程运用的是VS Studio + glfw + glad的开发办法。
好吧,我之前也是这么做的,可是OpenGL本身是C风格的API, 假如用面向对象的思想其写,略微有一些麻烦,而且在调试参数的时候不太便利。
后来我在Review LearnOpenGL的时候就想换一种开发办法学习:
计划一: ImGui + OpenGL
- 长处:ImGui集成了glfw环境,能够完成一些简单的控件来修改参数,便利检查实时效果,就如下图。
- 缺陷:我懒得去学习一门新的ui库=。=
参考教程:ImGui+OpenGL教程
计划二: Qt+OpenGL
Qt-OpenGL的几个优势:
- Qt内嵌了opengl的相关环境,不需要咱们自己来搭建,这对小白来说是很友好的。
- Qt和opengl都具有优良的跨平台特性,运用Qt做opengl开发可谓是强强联合。
- Qt能够轻松的控制窗口的各种处理事情以及窗口属性。
- Qt供给了opengl函数的C++封装,使得opengl本来的C风格API能够经过C++的面向对象技能来完成。
- Qt供给了非常完善的官方文档,有助于咱们把握QtOpenGL的各种细节。
缺陷:
- Qt对OpenGL的封装导致代码和Qt结构耦合,很难抽离出来作为独立SDK,这在一些团队中可能不会考虑
由于个人对Qt熟悉一些,所以后来都是用Qt作为OpenGL学习的开发测验环境。
2. Qt+OpenGL开发
Qt中运用OpenGL一般有两种办法:
- 封装成Widget嵌套在其他页面中
- 作为独立Window运用
2.1 第一种:作为Widget嵌套运用
在Qt5.4之前,能够自定义一个类,承继自QGLWidget来完成,后来推出了### QOpenGLWidget这个类简化了流程。
QOpenGLWidegt
创立opengl窗口只需新建类承继于QOpenGLWidegt,再完成QOpenGL供给的三个虚函数,就能够完成opengl窗口的创立。
- initializeGL()—树立OpenGL的资源和状况。在第一次调用resizeGL()或paintGL()之前调用一次
- resizeGL()—设置OpenGL视口,投影等。每逢调整Widget的巨细时(第一次显示窗口Widget时会调用它,由于所有新创立Widget都会自动获得调整巨细的事情)。
- paintGL()—烘托OpenGL场景,需要更新Widget时就会调用。
QOpenGLExtraFunctions
QOpenGLExtraFunctions类承继于QOpenGLFunctions,相较于QOpenGLFunctions,额外供给了对OpenGL ES 3.0、3.1和3.2 API的跨平台访问,假如咱们需要在类中运用opengl函数,只需要使类承继于QOpenGLExtraFunctions。
以如下代码为例:
#ifndef OPENGL_TOOLS_QGL_WIDGET_HPP
#define OPENGL_TOOLS_QGL_WIDGET_HPP
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
class QGL_Widget : public QOpenGLWidget, QOpenGLFunctions{
Q_OBJECT
public:
using QOpenGLWidget::QOpenGLWidget;
explicit QGL_Widget(QWidget* parent = nullptr) : QOpenGLWidget(parent)
{
}
void initializeGL() override
{
initializeOpenGLFunctions();
glClearColor(0.2f, 0.1f, 0.8f, 0);
};
void resizeGL(int w, int h) override
{
};
void paintGL() override
{
};
};
#endif //OPENGL_TOOLS_QGL_WIDGET_HPP
调用如上窗口:
QGL_Widget *gl_widget = new QGL_Widget(this);
gl_widget->setGeometry(QRect(0,00,400,300));
gl_widget->show();
2.2 作为Window独立显示
Qt6中供给了QOpenGLWindow作为一个gl独立窗口,注意在Qt5和Qt6中稍有不同,建议运用最新的Qt6开发。
咱们创立一个类集成自QOpenGLWindow和QOpenGLFunctions,来完成一个绘制三角形的窗口
SimpleTriangleWindow.h
#ifndef OPENGL_TOOLS_SIMPLETRIANGLEWINDOW_H
#define OPENGL_TOOLS_SIMPLETRIANGLEWINDOW_H
#include <QOpenGLWindow>
#include <QOpenGLFunctions>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
class SimpleTriangleWindow : public QOpenGLWindow, protected QOpenGLFunctions
{
Q_OBJECT
public:
SimpleTriangleWindow()
{
}
~SimpleTriangleWindow()
{
}
protected:
void initializeGL()
{
}
void initShader()
{
}
void resizeGL(int w, int h)
{
};
void paintGL()
{
};
};
#endif //OPENGL_TOOLS_SIMPLETRIANGLEWINDOW_H
创立VAO、VBO、着色器程序:
private:
//着色器程序
QOpenGLShaderProgram program;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
在初始化办法:
void initializeGL()
{
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST); //敞开深度测验
glClearColor(0.0,0.0,0.0,0.0);
//创立vao.vbo
m_vao.create();
m_vbo.create();
//shader加载
initShader();
float _vertex[] = {
0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
};
m_vao.bind();
m_vbo.bind();
m_vbo.allocate(_vertex,sizeof(_vertex));
program.bind();
program.setAttributeBuffer("vPos",GL_FLOAT,0,3,0);
program.enableAttributeArray("vPos");
program.release();
m_vao.release();
}
initShader()是着色器加载程序,这里没有对着色器代码做修改
void initShader()
{
// Compile vertex shader
if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/resource/shader/vshader.glsl"))
close();
// Compile fragment shader
if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/resource/shader/fshader.glsl"))
close();
// Link shader pipeline
if (!program.link())
close();
// Bind shader pipeline for use
if (!program.bind())
close();
}
着色器代码:
#version 330 core
void main()
{
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
#version 330 core
in vec3 vPos;
void main()
{
gl_Position = vec4(vPos, 1.0);
}
到此初始化作业已经完成,在paintGL中绘制:
void paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_vao.bind(); //启用VAO
program.bind(); //启用Shader
glDrawArrays(GL_TRIANGLES,0,3); //用三个点画一个三角形
program.release(); //开释Shader
m_vao.release(); //开释VAO
};
最终效果:
咱们从上述代码能够看到在Qt的环境中开发OpenGL有许多和传统API不一样:
- Qt供给了
QOpenGLVertexArrayObject
类来创立办理VAO对象 -
QOpenGLBuffer
用来创立办理VBO/IBO/EBO对象 -
QOpenGLShaderProgram
类来加载、办理着色器程序
对着色器参数修改也非常便利:
m_program->bind();
m_program->setAttributeBuffer("vPos", GL_FLOAT, 0, 3, 0);
m_program->enableAttributeArray("vPos");
整体代码非常简练,流程比原生API要明晰许多,可是问题也在这里,关于不熟悉Qt GL Api的人来说,刚开始很难熟悉,即时熟悉了之后的开发也会限制在Qt结构中, 非常不利于扩展。
关于详细运用Qt-OpenGL教程,能够参考如下系列:
- Qt+OpenGL简单入门教程
- learn opengl with Qt
后续我不太想在Qt中进行OpenGL开发,限制性太大,据我所知,许多公司在实践开发中,即时挑选了Qt结构,也不会挑选Qt的OpenGL API开发,而是自己封装一套接口或许运用的其他反方库。长处就是可扩展性好,和Qt结构解耦,在移植的时候价值更小。