OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动

OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵 实现3维观察移动

文章目录

  • OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵 实现3维观察移动
  • 前言
  • 1 物体的变换矩阵
    • 1.1 位移矩阵
    • 1.2 缩放矩阵
    • 1.3 旋转矩阵
          • 遗留的问题:四元数如何定义 如何使用
    • 1.4 矩阵的顺序
  • 2 观察矩阵
  • 3 透视矩阵
  • 4 合起来就完成了
  • 5 总结


前言

我们上次介绍了坐标系,向量,矩阵,介绍了他们的一些基础计算。我们下面开始就要开始逐渐涉及这些计算来实现3D效果,我们接下来会介绍物体的变换矩阵(缩放,旋转,位移),介绍透视矩阵、观察矩阵。如果篇幅允许,我们将在代码上进行实现,最终实现一个空间中的三角形面片(我们可以自由移动视角观察这个三角形)
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第1张图片

我们把一个对象坐标系下的模型(这里为长方体)变到我们看到的图像,需要以上一些步骤(这些步骤的顺序不要变换)。
1,模型在对象坐标系下进行缩放(为了放到世界坐标系时为正确大小)
2,进行旋转(这里图画的有点不对,这个有点点类似透视图了)
3,位移(放到世界坐标系下的正确位置,这里是把其向右移动了一点)
4,观察(之前的三步是把物品摆放到了世界坐标系下正确的位置和姿态,而这一步是根据摄像机的位置计算图像的样子,这里之前在矩阵乘法的时候提到过)
5,透视(不论之前怎么算,得到的都是正交投影,我们怎么也看不到正方体的侧面,但是增加了透视之后,由于视线在正方体的中心偏左,所以我们就可以看到侧面了)

下面是透视和正交投影的区别:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第2张图片
左图:在透视下红色都被黑色挡住了,而正交投影下红色露出来了。
右图:透视下红色的顶部露出来了,底部被遮挡。正交投影下红色顶部被遮挡,底部露出来了。

1 物体的变换矩阵

1.1 位移矩阵

之前的3*3矩阵
还记得咱们之前在矩阵乘法中提到的坐标系变换吗(见上图),你会注意到这里的矩阵是33的,如果我们想实现把物体的位置进行改变仅仅通过这里的33矩阵并不能实现,我们要对其进行扩充,来看看我们怎样巧妙的对它进行改进。
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第3张图片
我们并没有做很多复杂的计算,只是在矩阵中加了一行和一列,并对应在向量上多了一个分量(该分量如果为1,表示该坐标为一个点的坐标。如果为0,表示该坐标为一个向量的坐标。我们这里把竖着写的一列矩阵都称为向量,虽然这里它最后一个分量是1,但是我们仍叫它向量,只是叫的顺口,这并不意外着它带有方向)。
在添加了一行和一列之后,你会发现ABC的值被加到了结果的XYZ分量中去,我们实现了位移操作。其诀窍在最后那个分量的1,因为有这个1才会使得ABC能够加到最后的结果中去。如果最后一个分量是0,那么ABC将不会加到最终的结果中去,这也正对应了向量的位移是不影响向量本身的(因为位移不会改变方向)。
我们给出仅做位移的矩阵:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第4张图片

1.2 缩放矩阵

也很简单,我们把对角线上的数值进行修改,就能得到每个点的缩放(每个点的缩放其实就是物体的缩放),见下图的演示:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第5张图片

这里我们给出仅做缩放的矩阵:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第6张图片

1.3 旋转矩阵

一般物体的旋转我们把它分解成绕X绕Y绕Z轴分别做旋转,最后合并起来形成最终的旋转。
这里我们以绕X轴旋转为例,求一下绕X轴旋转的矩阵是什么:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第7张图片
这里的求证并不严谨,没有涉及钝角旋转的正负号问题,但我们就不单独求证了,与此同时绕Y绕Z的旋转矩阵我们也不一个一个证明了,直接给出旋转矩阵
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第8张图片
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第9张图片
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第10张图片
如果你想让向量绕某一特定方向来旋转可以参考罗德里格斯旋转公式:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第11张图片
下面是证明:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第12张图片

说了这么多,这种绕XYZ轴用欧拉角进行旋转有两个比较严重的问题,第一个是欧拉角的旋转并不能做插值,比如说:旋转15度的矩阵乘上旋转25度的矩阵,其两者的和除以2,并不等于旋转20度的矩阵。这使得一些计算比较麻烦。第二个问题是万向节锁死,有些时候旋转到某一特定角度,会使两个轴相互重合,导致绕两轴的旋转效果相同。
这两个问题使得很多的飞机驾驶游戏不能使用欧拉角进行旋转(因为那会涉及到负责的旋转场景),解决它的办法是采用四元数(这里我们就不介绍了,我也不太懂)。

遗留的问题:四元数如何定义 如何使用

1.4 矩阵的顺序

我们之前说过矩阵乘法不满足交换律,我们这里就可以自己来验证,看看如果不管矩阵的顺序,我们将得到什么样的不同结果。
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第13张图片
由于缩放、旋转等很多的变换都是围绕原点进行的,这使得先进行位移和后进行位移产生的结果是不一样的(侧面证明了矩阵乘法不符合交换律),所以我们计算的时候要注意顺序,通常情况下是先缩放,再旋转,最后位移,才能得到我们想要的结果。

通过三种变换矩阵我们现在已经可以把模型缩放旋转后放到世界坐标系的正确位置上去了。接下来就要根据摄像机的位置和朝向来定义观察矩阵了。

2 观察矩阵

在介绍观察矩阵之前,我们要提一下,OpenGL的标准化空间摄像机是朝向Z轴的反方向的,如果你还记的之前的图中,箭头并没有指向摄像机看向的方向,而是其相反方向(即Z轴的反方向)。
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第14张图片
如果想把当前世界坐标系下的坐标转换为摄像机所在的视图坐标系的坐标,我们需要知道其XYZ轴的方向,其中Z轴的方向就是看向的位置减去摄像机的位置,如果我们给出X轴方向(即屏幕上的垂直方向,注意要保证XZ相互垂直),那么就可以通过叉乘得到Y轴的方向。
我们把XYZ轴的单位向量放到矩阵中,就得到了观察矩阵:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第15张图片
当然了,如果把摄像机的空间位置考虑进去,那就有:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第16张图片
假如我们想通过移动鼠标来改变摄像机的角度(就像很多3D游戏一样),可以把鼠标水平上移动设置为绕X轴旋转,把鼠标垂直方向的移动设置为绕Y轴的旋转,最后叉乘得到Z轴。这样就实现了,鼠标控制视角的目的(具体后面会有相关的代码实现)。

3 透视矩阵

透视矩阵应该是本节最难的一个矩阵,因为我们要把正交投影变成透视投影,透视投影并不是简单的对图形进行一个缩放,而是要把范围内的点或向量计算到对应的标准化坐标系下,详见下图:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第17张图片
其实就是把BC平面之间(棱台中的)的内容先压缩到B’C’之间(长方体中的),之后把B’C’之间的内容移动压缩到标准化坐标系下的立方体中去,得到最终传给屏幕的数据

这里要注意一下,OpenGL标准的输出是XY分别从-1到+1这样一个区域,这意味着,不论你的屏幕比例是多少,OpenGL都会把-1到+1这样一个区域的内容拉伸后传给屏幕(如果你想在16:9的屏幕上显示内容,那么你需要先传给一个水平压缩后的图像,再在窗口设置时选择16:9 OpenGL就会自动把压缩后的图像再拉伸回去,得到正确的图像)
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第18张图片
下面来具体计算透视投影矩阵:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第19张图片
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第20张图片
书上的还跟这里有一点不一样,但是这里的比较好理解。其实你可以直接套用就行。
我还是给出书上的矩阵吧:
OpenGL超级宝典(第7版)笔记17 位移、旋转、缩放、观察、透视矩阵,三维空间的观察移动_第21张图片
你可能会问,我们求出了透视矩阵,但是我们要除以的那个z怎么办,不用担心,OpenGL在最终计算顶点位置的时候会自动的让向量除以最后一个分量(也就是自动除以在第四个分量中记录的Z的值)。

4 合起来就完成了

最后我们按照从左到右的顺序依次将:缩放矩阵、旋转矩阵、位移矩阵、观察矩阵、透视矩阵、最后是向量相乘起来,得到的最终结果就是我们的三维世界中的图像。
要注意顺序不要错哦(矩阵乘法不满足交换律哦)
如果你已经迫不及待的想要进行渲染了,那我提醒你一下,你在将矩阵传入的时候可以先把那一大堆矩阵先乘起来,得到的结果在送到vs中计算顶点位置,不要每个顶点都算一遍那一大堆矩阵的乘法。

我们后面的会向大家提供我们的实现代码,不要着急~

5 总结

这篇我们介绍了缩放矩阵、旋转矩阵、位移矩阵、观察矩阵、透视矩阵,我们介绍了这个流程中每个矩阵的用处,以及简单的推导了一下矩阵是如何来的,下一篇我们将把这些计算添加到我们自己的c++类中去(如果你已经有库可以实现的话,那就跳过它),我们暂时逃离了可怕的数学,回归到代码中去了~
我们下一篇见~~

关于书籍的问题
如果你手中没有该书,我还是建议你购买一本,毕竟书本毕竟更加严谨专业,我这里难免遗漏一些细节,主要是提供实例,并做一个消化,将很混乱的流程为大家理清,但这笔记一定是通俗的,是对新手友好的(当然有时候你需要在某些方面自己努努力,比如后面出现的基本线性代数的内容,还有C语言或是c++的基础知识,虽然我可能也不太懂O(∩_∩)O,慢慢来吧)。

别被吓住
刚开始的时候很容易被OpenGL的巨长的函数和超级复杂的流程吓到,其实并没有那么可怕,只要对这样或那样的流程熟悉之后,一切都变得相当简单(当然如果你能提出一个更好的流程那就更好了,当我们把很多基础的工作做完,我们会不断的提出新问题新点子,用新的技术来实现它,最终完成OpenGL的学习)

虽然我也不知道后面将是怎样的道路,但至少努力学习是没错的。

我看过的相关内容
以下并不是全看完了,大部分看了15%就看不下去了,实在是没看懂。(本人没什么计算机编程基础,算是野生程序员吧,很多内容都不能标准表述,望见谅)
如果你对opengl的工作有了一定的了解,我一开始也是从这里开始的,但是仍然有很多的不懂的,最后至今为止,我杂糅了很多的网站内容包括LearnOpenGL、极客学院、哔哩哔哩的闫令琪计算机图形学(闫令琪又开202课程了,可以围观一下)、哔哩哔哩的傅老师的OpenGL课程、OpenGL编程指南"也称为红宝书"、OpenGL超级宝典"也称为蓝宝书"、当然还有很多的csdn文章O(∩_∩)O这就不介绍了,等用到是时候我在放链接吧O(∩_∩)O

这里面闫令琪的图形学比较易懂也很基础推荐可以作为开始(如果你是学OpenGL需要马上用,应该可以跳过,但是其中的内容很是很重要,这会让马上要涉及变换透视的章节更加易懂,推荐大家看看),之后是蓝宝书或是极客学院翻译的教程比较推荐,这两个还是比较适合你我这样的新手的。
这里不推荐看的是红宝书,这本书我看了有点类似于字典那样的工具书,不太适合新手上手学,而且讲的也并不是很通俗易懂(可能是我的书版本比较老吧…)

加油
当然如果你对我有信心,我也会持续更新(虽然前路漫漫),跟大家一同进步(虽然很可能没人看(╥╯^╰╥),无所谓了,当然如有错误还请大家指正∠(°ゝ°),哪里不懂我会尽力解决,哪里说的不好也可以指出我会及时修改~)

我们下篇见~~

你可能感兴趣的:(OpenGL笔记,c++,opengl)