本篇并不是纯数学上的介绍,而是从实际应用的角度来想大家介绍向量矩阵的内容,所以说并不会十分枯燥,我们采用先介绍计算的细节和过程,然后介绍我们将在哪些地方用到它们,所以当大家看到复杂的计算时候不要抵触,这样或那样复杂的计算(比如矩阵乘法)都是为了能够实现各种各样的效果,并不是为了为难大家。
因为这并不是纯数学上的教学,所以我们并不会解释例如矩阵是怎么发明的,矩阵背后到底是什么(其实是多元一次方程组O(∩_∩)O)等等“数学”上的问题,我们只要知道怎么计算、一般要在哪里用就行了。
如果你想学习权威的数学上的内容,可以参考线性代数的书籍(但其实很多线性代数的知识我们并不会用到),教科书就行。
由于渲染都是在三维空间中展开,所以我们的所有点的坐标都是三维坐标,在OpenGL中有四大坐标其中包括:
1 对象坐标系(对于每个模型都会在建模的时候建立一个自己的坐标系,这是为了方便建模)
2 世界坐标系(当所有建模完成后要把这些模型放到一起,而这个坐标系就是世界坐标系)
3 视图坐标系(由于我们看到的画面是从一个特定的摄像机位置看过去的,所以会根据摄像机所建立的坐标系,用于将摄像机看到的画面处理出来)
4 裁剪和标准化坐标系(由于很多显示设备的不同,显示的大小比例都有所不同,并不是所有的物体都在我们的视线内,所以我们需要对这些坐标系进行标准化的转换,统一的进行缩放,这里用到的就是裁剪和标准化坐标系)
虽然说在数学上的向量是有起点和方向两个要素的,但是我们在OpenGL中并不考虑向量的起点,我们都认为向量的起点是原点,如果知道向量的两个顶点位置,那么只需要把终点位置减去起点位置就得到了向量的坐标。
对于坐标系来说都有一组基础的向量,分别指向XYZ轴的正方向(分别为i,j,k),而且它们的长度都为1,由于XYZ轴之间两两相互垂直,这组向量组成了一个正交体系,每个向量都可以由i、j、k来表示,比如下图:
ijk的相互垂直非常重要,当前我们很多的错误可能就来自于坐标系ijk并不相互垂直的问题。
向量的长度(略)
点乘
首先是点乘,a、b两个向量点乘得到的是一个标量(即不带方向的量),具体是把两个向量的长度相乘并成上夹角的余弦值,在坐标上来说就是把两个的xyz值分别相乘后相加。
如果当a或b是单位向量(长度为1的向量)时,那么点乘的结果就是向量在单位向量方向上的投影的长度。
点乘也非常的常用,比如说在求投影的时候(上面介绍过了),比如说在比较两个向量的夹角大小的时候(比如说,比较我们的视线和反射光的夹角大小,由此来设置反射光斑有多大)
其上面的虚线为直接反射到眼睛里的光线,实线为反射后没有直接进入眼睛的光线,如果我们只接收进入眼睛的反射光,那么光滑表面的反射光斑的大小只是一个像素,几乎看不到反射光斑,如果我们加入一个可以容忍的角度值,让那些虽然不能直接进入眼睛的光线也显示为反射光(比如实线),这样我们才能得到一个有一定面积的光斑。这里我们就是通过将反射光和视线做点乘,并除以两者的长度,得到夹角的余弦值决定可容忍的角度值(即光斑的大小)
叉乘
刚才的点乘是乘以余弦值,而叉乘是乘以正弦值,同时叉乘得到的结果不是标量,而是垂直于当前两个向量的新向量,可以用右手定则判断(右手系下为右手定则,左手系下为左手定则,下图显示的是右手系下的情况)。
(勘误:a叉乘b的结果的y值是-azbx+axbz)
如果你是第一次看到这个叉乘的公式那么你一定头都要大了(这公式有点长,其实有简单的记忆方法),但是它是相当常用的东西,比如说判断一个点是否在三角形内(无论是不是三维空间中的三角形)。
反射
由于入射角等于出射角,所以简简单单把向量分解一下就可以算出反射后的向量方向(这里就用到了点乘)
折射
不知道我这里的算式和书上的是否等价,但是我们暂时还用不到折射公式,(可能到之后半透明物体的着色才会涉及)。(由于打公式太费劲了,我就手写了)
直观的看,矩阵就是一系列排列整齐的数字,其本事是源于多元一次方程组。矩阵把多元一次方程组的大量字符省略掉转而使用矩阵来运算,其虽源于多元一次方程组,但是从矩阵基础上得到的很多计算方法其实已经“脱离”了多元一次方程组本身。
从计算机的角度看,矩阵的出现省去了复杂的式子计算,取而代之的是简单的加减乘除和数据的移动,其更加适合计算机去计算结果。
我们可以先带大家看看矩阵的样子(从三元一次方程组抽象出来的矩阵与向量相乘),你可以看到系数的相对位置没有变化,只是把其中的变量xyz抽离了出来。(你当前完全可以把矩阵当做是多元一次方程组的另一种表示方法)
如果你看完之后有点懵,那很正常,作为一种新的表示方法的确很难让人接受。
矩阵乘法
矩阵乘法是我们在矩阵运算中使用的最多的运算之一,也是我们之后马上要用到的运算,大家一定要弄清楚是如何计算的,千万不要弄混了。
首先澄清一点虽然我上一个图的xyz下面标注的是向量,但是我们也可以把它看做是只有一列的矩阵,矩阵乘法的规则一样适用于向量。
首先,想要进行矩阵乘法需要满足一个条件:第一个矩阵的列的数量要等于第二个矩阵的行的数量。(这意味着矩阵乘法不满足交换律)(顺便提一下:矩阵乘法满足结合律)
矩阵乘法的结果是一个矩阵,它的行数等于第一个矩阵的行数,它的列数等于第二个矩阵的列数。
你可能会好奇这里为什么有个小人和床,其实是为了方便大家记忆,我们把A想象成床,把B想象成小人,那么进行矩阵乘法的要求就是小人的高度要和床的长度一样(人太高了躺不下去,床太长了有点浪费O(∩_∩)O),这样就记得更清楚了。
具体的矩阵乘法规则是:结果矩阵中第 i 行第 j 列的数值是取A的第 i 行和B的第 j 列做点乘得到的。例子如下:
小人他又来了,既然已经知道了要求的值,确定了行数和列数,那肯定要在床(A矩阵)上取一行、在人(B矩阵)上取一列才可以啊~,这就是为什么矩阵乘法有一个先行的条件,因为如果AB不满足之前的条件那么点乘就无法进行。
说了这么多,这个矩阵乘法有什么用呢?
我先想到的是坐标系转换。假如说当前坐标下有向量a,其坐标为(ax,ay,az)那么假如当前坐标系发生了旋转(比如摄像机的朝向发生了旋转),那么之前的向量在新坐标系下的坐标就会发生改变(毕竟只是摄像机改变了朝向,本事物品的位置并没有改变),那么新坐标就需要重新计算,这里就用到了矩阵乘法。
如果我们不管矩阵,直接计算新坐标系下的向量坐标(ax’,ay’,az’),先计算ax’,ax’应该等于之前的向量坐标点乘上新坐标系的i’向量(即新坐标i向量在原坐标系下的坐标),同理ay’应该等于之前的向量坐标(ax,ay,az)点乘上新坐标系的j’向量,同理az’也一样。(这是因为ax’ay’az’就是向量在新坐标系下XYZ轴上的投影)
如果你把ijk的三个分量分别放到矩阵的前三行,并且和a向量做矩阵乘法,你会惊人的发现这不正是在做坐标系变换吗!
也就是说如果我们想把当前的坐标变成另一个坐标系下的坐标,那么只需要提供i’j’k’的坐标就行了,让每一个顶点或是向量都和i’j’k’的矩阵做乘法,就得到了新坐标系下的坐标了,我们再把新坐标系下的坐标投影到我们的屏幕上,我们就得到了一个3D上的视角移动。
所以我们不断移动摄像机的角度、位置,其实就是在不断的改变矩阵中的数值,计算机通过这些数值计算新画面的样子,这使得我们的游戏看上去是3D的(其实显示的只是一连串二维的画面,毕竟屏幕只显示二维图像)
其他
还有一些有关矩阵的转置(行和列翻转,第n行变成第n列,第m列变成了第m行),单位矩阵(对角线上的数都是1,其他都是0),矩阵的逆(矩阵的逆乘上矩阵本身得到的结果是单位矩阵),正交矩阵,我们就不再细说了都是比较简单的概念,可以自己去看看,或是到了使用的时候再看看也可以。
(虽然有些算起来挺难的,有些定理也比较难证明,但我们只需要拿来用就行了)
我们这次介绍了坐标系,向量,矩阵,介绍了他们的一些基础计算。我们下面开始就要开始逐渐涉及这些计算来实现3D效果,我们接下来会介绍物体的变换矩阵(缩放,旋转,位移),介绍透视矩阵、观察矩阵。如果篇幅允许,我们将在代码上进行实现,最终实现一个空间中的三角形面片(我们可以自由移动视角观察这个三角形)
我们下一篇见~~
关于书籍的问题
如果你手中没有该书,我还是建议你购买一本,毕竟书本毕竟更加严谨专业,我这里难免遗漏一些细节,主要是提供实例,并做一个消化,将很混乱的流程为大家理清,但这笔记一定是通俗的,是对新手友好的(当然有时候你需要在某些方面自己努努力,比如后面出现的基本线性代数的内容,还有C语言或是c++的基础知识,虽然我可能也不太懂O(∩_∩)O,慢慢来吧)。
别被吓住
刚开始的时候很容易被OpenGL的巨长的函数和超级复杂的流程吓到,其实并没有那么可怕,只要对这样或那样的流程熟悉之后,一切都变得相当简单(当然如果你能提出一个更好的流程那就更好了,当我们把很多基础的工作做完,我们会不断的提出新问题新点子,用新的技术来实现它,最终完成OpenGL的学习)
虽然我也不知道后面将是怎样的道路,但至少努力学习是没错的。
我看过的相关内容
以下并不是全看完了,大部分看了15%就看不下去了,实在是没看懂。(本人没什么计算机编程基础,算是野生程序员吧,很多内容都不能标准表述,望见谅)
如果你对opengl的工作有了一定的了解,我一开始也是从这里开始的,但是仍然有很多的不懂的,最后至今为止,我杂糅了很多的网站内容包括LearnOpenGL、极客学院、哔哩哔哩的闫令琪计算机图形学(闫令琪又开202课程了,可以围观一下)、哔哩哔哩的傅老师的OpenGL课程、OpenGL编程指南"也称为红宝书"、OpenGL超级宝典"也称为蓝宝书"、当然还有很多的csdn文章O(∩_∩)O这就不介绍了,等用到是时候我在放链接吧O(∩_∩)O
这里面闫令琪的图形学比较易懂也很基础推荐可以作为开始(如果你是学OpenGL需要马上用,应该可以跳过,但是其中的内容很是很重要,这会让马上要涉及变换透视的章节更加易懂,推荐大家看看),之后是蓝宝书或是极客学院翻译的教程比较推荐,这两个还是比较适合你我这样的新手的。
这里不推荐看的是红宝书,这本书我看了有点类似于字典那样的工具书,不太适合新手上手学,而且讲的也并不是很通俗易懂(可能是我的书版本比较老吧…)
加油
当然如果你对我有信心,我也会持续更新(虽然前路漫漫),跟大家一同进步(虽然很可能没人看(╥╯^╰╥),无所谓了,当然如有错误还请大家指正∠(°ゝ°),哪里不懂我会尽力解决,哪里说的不好也可以指出我会及时修改~)
我们下篇见~~