Qt中使用OpenGL(五)
在构建三维世界时,我们不可能为所有我们想要画的东西都编写顶点坐标和纹理坐标,所以就引入了模型的概念
模型的基类
一般情况下,构建一个三维世界我们会使用模型这个概念。一个模型可以理解为一个物体,比如一个茶壶、一个人、一棵树,他们都可以是一个模型,我们只需要指定这些模型的位置和旋转角度,乃至大小,就可以构建出简单的三维世界。
在OpenGL 中,想要画出一个东西,至少需要两个东西:顶点和纹理。我们需要在绘制的时候激活不同的纹理,然后绘制模型。
所以一个模型需要以下内容:
- 顶点信息(位置坐标和纹理坐标)
- 纹理(可能有多个纹理)
- 在三维世界中的变换(即模型矩阵,对模型进行缩放、旋转、平移)
- VAO, VBO, shader
基本模型类架构如下所示
1 | |
模型类继承 QOpenGLFunctions_4_5_Core,是为了方便使用 OpenGL 的函数。成员变量都为 protected,因为这是作为模型基类,具体实现细节要交给继承的类来做。
可以做的只有如何保存纹理以及生成模型矩阵
1 | |
具体如何初始化、如何绘制、如何 update ,目前无法知道,但是:
- init 函数要在三维窗口的 initializeGL() 函数中使用,用于创建和填充缓存
- paint 函数要在三维窗口的 paintGL() 函数中使用,用于具体绘制
- 投影矩阵和视图矩阵要通过外部传入参数
- update 函数与模型自身逻辑相关,比如旋转等
创建色子模型
色子模型的类声明较为简单
1 | |
m_vertexBuffer 是一个临时缓存,用于将顶点转化为顶点缓存需要的格式
m_vertexCount 记录了临时缓存中保存的顶点数量,如果缓存中的顶点数量比较少,就需要重新初始化缓存,如果缓存中顶点数量较多,那么久不需要重新初始化缓存。
构造函数
在色子的构造函数中,初始化色子的顶点信息,加载纹理和 shader
1 | |
init 函数
在 init 函数中,创建各种缓存
1 | |
paint 函数
在 paint 函数中,对色子进行绘制
1 | |
使用色子模型
在三维窗口的声明中,我们使用 QVector<Model *> m_models 来保存色子模型(为了通用性,所以使用父类)
1 | |
在 OpenGLWidget 的构造函数中对 camera 及 timer 进行初始化与连接
1 | |
在 initializeGL 函数中,我们只需要创建对象,并调用他们的初始化函数,然后推入 m_models 即可
1 | |
在绘制的时候,遍历 m_models,然后调用 paint 函数
1 | |
为了控制色子旋转,在计时器结束时,修改每个色子模型的 rotate 矩阵
1 | |
三维窗口的控制函数按照 Camera类中的即可
1 | |