OpenGL-Qt
OpenGL概念
用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。Open Graphics Library由Khronos组织制定并维护的规范。OpenGL核心是一个C库,同时也支持多种语言的派生。
框架:OpenGL+Qt
没有Qt需要配置第三方库GLFW和GLAD。
GLFW解决操作系统层面的不同,如果窗口、上下文、用户输入都自己做太麻烦:
- 创建窗口,GLFW做
- 定义上下文,GLFW做
- 处理用户输入,GLFW做
GLAD使得代码可以用于不同的OpenGL驱动
-
OpenGL本身只是标准/规范。对于软件和硬件的适配OpenGL不管,由程序猿来做。
-
各个厂家具体实现方式可以不同。
-
没有GLAD,windows下需要通过函数指针调用显卡的函数,但是显卡驱动具体函数的地址只有在运行时才知道。
1
2
3
4
5
6
7//define the function's prototype
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
//find the function and assign it to a function pointer
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");//wglGetProcAddress("glGenBuffers")获取显卡在当前上下文状态下的OpenGL函数glGenBuffers的地址。
//function can now be called as normal
unsigned int buffer;
glGenBuffers(1, &buffer);有GLAD,我们只使用GLAD的固定代码,让GLAD去找显卡的驱动函数地址。
**核心模式(Core-profile)**也叫可编程管线、现代模式、可编程模式,提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。

GPU渲染流程:
- 输入给GPU顶点数据。(可编程)
- GPU将顶点装配成图元,即建立大框架。(不可编程)
- GPU在大框架中插入部分点。(可编程)
- GPU在几何润色的框架基础上生成像素栅格。(不可编程)
- GPU把栅格化的框架着色。(可编程)
- GPU将多个着色的栅格(位置有前有后)框架融合和混合。(不可编程)
非可编程管线即固定管线,2、4、6的步骤的输入输出都以写死;1、3、5的步骤是可编程的管线,其中1、5是必须要写代码的模块,3可以写代码也可以使用默认处理流程。
立即渲染
- 这是早期OpenGL使用的模式(固定渲染管线)。
- OpenGL的大多数功能都被库隐藏起来,容易使用和理解但是效率低。
- 开发者很少能控制OpenGL如何进行计算。
- 从OpenGL3.2以后,推出核心模式。
状态机
- OpenGL自身是一个巨大的状态机(上下文即当前状态)
- 描述该如何操作的所有变量的大集合。
- OpenGL的状态通常被称为上下文(Context)。
- 状态机函数分两种:
- 状态设置函数(State-changing Function)
- 状态应用函数(State-using Function)
我们通过改变一些上下文变量来改变OpenGL状态,从而告诉OpenGL如何去绘图。
对象
一个对象是指一些选项的集合,代表OpenGL状态的一个子集。例如一个对象可以是绘图窗口,其包含若干OpenGL状态,如窗口大小、颜色位数等。可以将一个C风格的结构体视作一个对像。
1 | struct object_name { |
OpenGL上下文是一个超大的状态集合(状态机、结构体)可以包含若干子集(对象、结构体)。
1 | struct OpenGL_Context{ |
当前状态只有一份,如果每次显示不同的效果都要重新配置会很麻烦。这时我们就需要一些小助理(对象),帮忙记录某些状态信息,以便复用。如果我们有10种子集,每个子集有10种不同的状态,那么我们需要100个小助理(对象)。
1 | //创建对象,使用OpenGL自己的uint,可以跨平台 |
Hello World
QOpenGLWidget
QOpenGLWidget提供了三个便捷的虚函数,可以重载,用来重新实现典型的OpenGL任务,不需要GLFW库:
- paintGL: 渲染OpenGL场景,绘画操作(QOpenGLFunctions_X_X_Core里提供的函数指针)都放到该函数中。widget需要更新时调用。
- resizeGL: 设置OpenGL视口、投影等。widget调整大小时调用。
- initializeGL: 设置OpenGL资源和状态。第一次调用resizeGL(),paintGL()之前调用一次。
- 如果需要从paintGL()以外的位置触发重新绘图(例如使用计时器设置场景动画),则应调用widget的update()函数来安排更新。在paintGL()以外的位置调用绘制函数没有意义,绘制图像最终将被paintGL()覆盖。
- 调用paintGL(),resizeGL(),initializeGL()时,widget的OpenGL呈现上下文将变为当前。如果需要从其他位置( 例如在widget的构造函数或自己的绘制函数中)调用标准OpenGL API函数,则必须首先调用makeCurrent()获取当前状态然后update。
QOpenGLFunctions_X_X_Core
QOpenGLFunctions_X_X_Core提供OpenGL X_X版本核心模式的所有功能,是对OpenGL函数的封装,不需要GLAD库, _X_X_表示版本号例如3_3。
- initializeOpenGLFunctions: 初始化OpenGL函数,将QOpenGLFunctions_X_X_Core里的函数指针(例如glClearColor(0.2f, 0.3f, 0.3f, 1.0f);)指向显卡的函数。否则运行空指针报错。
Vulkan概念
Vulkan是一种基于命令缓冲区的底层图形API接口,能够更好地利用现代GPU的强大计算能力,从而获得更高的渲染性能和更低的CPU开销。与OpenGL相比,Vulkan提供了更详细的硬件控制、更高效的内存管理、更灵活的管线状态管理和多线程支持等优势。
图形学api是用gpu加速图形学中的计算过程的。shader是用g pu计算的,c++使用cpu计算的,当需要cpu和gpu交互时需要使用vulkan。



