唉,虽然学会了,但是懒得做笔记呀。俗话说好记性不如烂笔头,防止遗忘我还是记一记吧。
一、矩阵
众所周知,三弟3D图形学中很重要的就是线性代数,我们进行各种变换的时候就要用到神奇的矩阵。
(不禁想吐槽一句,这个神奇的东西到底是怎么想出来的。。)
相信矩阵乘法大家都了解,下面讲几种特殊的矩阵。
1.平移矩阵(Translate Matrix)
在讲矩阵之前,先说一个东西:齐次坐标。
为了区分矢量和标量,我们用第四维w来表示,v(x,y,z,w) ,则w=1 => v是空间中的位置,w=0 => v是向量。
那么我们想要在x轴上移动位置v(10,10,10,1),那么相应的平移矩阵就是
1 ,0 ,0 ,10
0 ,1 ,0 ,0
0 ,0 ,1 ,0
0 ,0 ,0 ,1
将它乘上我们的v,根据矩阵乘法得到v'(20,10,10,1),显然是正确的。
如果v是(-1,0,0,0)呢?(代表x轴负方向),根据计算得到(-1,0,0,0),显然是正确的,因为移动方向没有意义,帅呆了!
定义一个平移矩阵:
glm::mat4 myMatrix = glm::translate(glm::mat4(), glm::vec3(10.0f, 0.0f, 0.0f));
把位置和矩阵相乘:
glm::vec4 myVector(10.0f, 10.0f, 10.0f, 0.0f); glm::vec4 transformedVector = myMatrix * myVector; // guess the result
相乘的代码是一样的,下文不表。
2.单位矩阵(The Identity Matrix)
1 ,0 ,0 ,0
0 ,1 ,0 ,0
0 ,0 ,1 ,0
0 ,0 ,0 ,1
它就相当于1,任何数乘上1不会改变,单位矩阵乘上单位矩阵也是一样。
代码:
glm::mat4 myIdentityMatrix = glm::mat4(1.0f);
3.缩放矩阵(Scaling matrices)
x ,0 ,0 ,0
0 ,y ,0 ,0
0 ,0 ,z ,0
0 ,0 ,0 ,1
xyz就是缩放的倍数,多么优美的矩阵。
代码:
glm::mat4 myScalingMatrix = glm::scale(2.0f, 2.0f ,2.0f);
4.旋转矩阵(Rotation matrices)
很复杂的东西,贴代码:
// RotationAngle is in radians x = RotationAxis.x * sin(RotationAngle / 2) y = RotationAxis.y * sin(RotationAngle / 2) z = RotationAxis.z * sin(RotationAngle / 2) w = cos(RotationAngle / 2)
代码:
glm::vec3 myRotationAxis( ??, ??, ??);
glm::rotate( angle_in_degrees, myRotationAxis );
这里不涉及到矩阵,OpenGL已经封装好了。(如此贴心!)
介绍完了矩阵们,接下来要用到他们变换我们的3D世界了。
变换大致是这样的流程:
模型坐标系--×模型矩阵-->世界坐标系--×相机矩阵-->相机坐标系--×透视矩阵-->屏幕坐标系
模型坐标系和世界坐标系:假定(0,0,0,1)是模型的中心点,将它乘上一个平移矩阵,此时它的位置就不是(0,0,0,1),而是另一个位置,此时它就处于世界坐标系。(细品)
相机坐标系:把相机往一个位置移动似乎不好解决(仔细想,因为所有的变换都是为了让物体在屏幕上以一个真实的方式呈现,我们不择手段),所以我们移动世界,把一切顶点移动,幸运的是OpenGL已经为我们实现了!
屏幕坐标系:通过透视变换,我们把3D变成了2D(画家:我恨数学!)!具体实现比较复杂,不细说,但是原理也是通过乘上一个透视变换的矩阵,这个矩阵OpenGL也为我们提供了!(欢呼!)
下面是代码实现:
模型矩阵:(我们把它放到世界原点,所以就用单位矩阵作为模型矩阵)
glm::mat4 Model = glm::mat4(1.0f);
相机矩阵:(使用lookAt函数)
glm::mat4 View = glm::lookAt( glm::vec3(4,3,-3), // Camera is at (4,3,-3), in World Space glm::vec3(0,0,0), // and looks at the origin glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down) );
第一个参数是相机位置(世界坐标系),第二个是相机观察的位置,第三个是向上的方向(用于计算一个交叉积,一定要填对喔!)。
透视矩阵:
glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.0f);
第一个参数代表Fov,视角大小,第二个代表屏幕宽高比,第三个代表近裁剪面(近于这个值的物体将被裁剪,不显示),第四个代表远裁剪面(远于这个值的物体将被裁剪,不显示)。
最后,把这三个矩阵相乘,即可得到顶点们的变换了。
glm::mat4 MVP = Projection * View * Model;
注意顺序!