Qt中使用OpenGL(四)
如何画一个骰子
整理顶点
一个骰子是有六个正方形组成。

根据骰子纹理资源,不再使用(0,0)为左下角和(1,1)为右上角,而是使用和图片相同的左上角为(0,0),右下角为(1,1)。(因为需要人工处理这些坐标映射,所以使用和图片相同的坐标系统比较节省脑子)
骰子每个面的安排如下:1在前面,6在后面,2在右侧,5在左侧,3在上面,4在下面
1 | |
绘制六个矩形
每次按照两个三角形的方法来绘制六个矩形,循环六次,每次 4 个点。
1 | |
加载纹理
1 | |
因为在设计纹理坐标时,和图片坐标保持了一致,所以此时不用镜像。
三维变换
因为模型是三维的,而显示器只能显示一张图片,所以可以通过一系列的数学计算,将三维空间的一个物体,映射到一个二维平面,当我们观察这个二维平面时,可以有一种我们是在三维空间的某一个位置观察它的错觉。
实际在用的时候,只需要定义三个矩阵,然后让顶点依此乘以矩阵就可以了。
1 | |
这里定义了三个 uniform 变量,分别叫做 投影矩阵,视图矩阵和模型矩阵。
- 投影矩阵负责让你看到的画面符合近大远小的透视规律,并且保证无论窗口的宽高比是多少,看到的画面都不会变形
- 视图矩阵负责模拟一个摄像机的镜头,让你可以在三维空间的某一个位置去观察另一个位置
- 模型矩阵负责让你绘制模型的时候,可以对它进行缩放、平移、旋转的操作
在 Qt 中,这些矩阵可以通过 QMatrix4x4 类进行表示
1 | |
投影矩阵
1 | |
setToIdentity() 函数保证接下来的所有矩阵运算都会在一个单位矩阵上进行。
perspective() 函数就可以构建出一个基于窗口大小的近大远小的投影矩阵了:
- 第一个参数表示用什么样的视角来进行投影。可以理解为看到的画面的视野有多大。人眼在头部不动的情况下,视野大概是 60 度。(这里的角度是指纵向视野的角度,不对横向视野进行限制,窗口越宽,看到的内容就会越多,但是靠近边缘的部分变形也会越严重)
- 第二个参数是窗口的横纵比。
- 第三、四个参数是离摄像机多近到多远范围内的物体要被显示。超出这个范围顶点物体将无法显示。
视图矩阵
视图矩阵用于模拟摄像机,所以可以用 QMatrix4x4 类的 lookAt 函数来设置视角。
1 | |
lookAt 函数:
- 第一个参数表示你的眼睛在哪里
- 第二个参数表示你的眼睛看向了哪里
- 第三个参数表示你的头顶朝向是哪里
模型矩阵
模型矩阵用于让绘制的模型可以缩放、旋转和平移。
1 | |
rotate 函数表示绕某个轴进行一定角度的旋转,这里的角度是指具体的角度,如果每次都首先调用 setToIdentity 清零,则旋转的角度不会累加。
如果希望模型可以一直转下去,可以设置一个定时器,以 60 帧/秒的频率修改 m_angle 的值,每帧 +1,到了 360 度就归零。
Qt 中自带定时器,可以在构造函数中开启一个定时器
1 | |
然后在定时器事件中修改旋转角度和矩阵
1 | |
最后调用 repaint() 函数告诉 OpenGL 重新绘制
应用矩阵
设置了这些矩阵后,就可以告诉 OpenGL 这些矩阵的存在了。调用 shader 的对应函数就可以
1 | |
最终 paintGL 函数如下
1 | |
展示效果如下
