3d模型经过世界坐标变换、相机坐标变换后,下一步需要投影变换。投影变换的目的就是要把相机空间转换到标准视图空间,在这个空间的坐标都是正规化的,也就是坐标范围都在[-1,1]之间,之所以转换到这个空间是为了后续操作更方便。
下面的讨论都是以列向量来表示,这样在变换操作时,采用的是矩阵左乘法,如果采用的是行向量的话,那就相反,矩阵右乘法即是向量在左边乘以变换矩阵。采用哪种表示并不影响结果,只需要把该种表示下得出的变换矩阵转置一下,就是采用另外一种表示模式需要的结果。
常见的投影有两种,正交投影和透视投影,正交投影相对来说更简单,所以先来看看正交投影。
最简单的正交变换矩阵
1 0 0 0
0 1 0 0
0 0 0 1
这个正交变换是不可逆变换,变换后x和y保留,z变成了0,在实际应用中,更常见的情况是限定x、y、z在一定的范围内的进行投影变换,比如x[l,r],y[b,t],z[n,f]。那么要把这段空间中的点变换到-1和1之间,只要完成两个变换,首先把坐标轴移到中心,然后进行缩放就可以了。采用列向量的话,那就是缩放矩阵乘以平移矩阵。
2/(r-l) 0 0 0 1 0 0 -(r+l)/2 2/(r-l) 0 0 -(r+l)/(r-l)
0 2/(t-b) 0 0 x 0 1 0 -(b+t)/2 = 0 2/(t-b) 0 -(t+b)/(t-b)
0 0 2/(f-n) 0 0 0 1 -(n+f)/2 0 0 2/(f-n) -(f+n)/(f-n)
0 0 0 1 0 0 0 1 0 0 0 1
透视投影类比于我们人眼系统,看一个物体,会有远小近大的效果。在转换到相机空间后,相机是这个空间的原点,和正交投影体是一个长方体或者立方体不同,透视投影体是一个锥体被近平面截取掉头部剩下的空间。假定仍然采用上面的坐标表示。在透视投影下,空间上面的任何一点P投影到近平面上某点q,通过三角几何学我们可以得到 qx=px*n/pz ,y点同理。假定直接投影到近平面,则该矩阵很简单,用Ma表示下面的矩阵
1 0 0 0
0 1 0 0
0 0 1 0
0 0 1/n 0
则齐次空间某点(x,y,z ,1)被该矩阵转换后变成了 (x ,y z, z/n) ,除以z/n,则变成了(nx/z,ny/z,n ,1) 正好吻合上面的公式。
但是我们知道投影变换需要把坐标变换到-1和1之间,假定先不考虑z轴的变换,在x轴和y轴上面经过上述变换后,已经投影在近平面了,假设近平面xy在[l,r] 和[b,t]之间了,因此只需要和上面的正交投影一样,进行平移和缩放操作就可以了,平移矩阵Mb为
1 0 0 -(l+r)/2
0 1 0 -(t+p)/2
0 0 1 -(f+n)/2
0 0 0 1
以及缩放矩阵Mc
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 2/(f-n) 0
0 0 0 1
McXMbXMa
得到的矩阵为
2/(r-l) 0 -(r+l)/(n*(r-l)) 0
0 2/(t-b) -(t+b)/(n*(t-b)) 0
0 0 j k
0 0 1/n 0
j k 为未知数,这个矩阵也可以同时乘以n,则变为
2n/(r-l) 0 -(r+l)/(r-l) 0
0 2n/(t-b) -(t+b)/(t-b) 0
0 0 j k
0 0 1 0
为了求解 J k,我们需要把z变换到-1 和1
因此当z=n时为-1, z=f时 为1
(j*n+k)/n= j+k/n=-1;
同理 j+k/f=1;
得到 k=2f*n/(n-f)
j=-(n+f)/(n-f)
代入上面的矩阵,就得出通用的正交变换矩阵。
而且在一般情况下 r=-l ,b=-t
因此上述矩阵可以简化为
n/r 0 0 0
0 n/t 0 0
0 0 -(n+f)/(n-f) 2f*n/(n-f)
0 0 1 0
n/r 和 n/t可以进一步简化成水平半视角和垂直半视角的三角函数来表示,而水平视角和垂直视角和透视窗口的宽高比有是成正比的,最终上面两行可以用宽高比和某个半视角的余切来表示。
这是在列向量情况下得出的投影矩阵,如果采用行向量,只需要把上面的矩阵转置一下即可。