視錐體


如圖,近截面與遠截面之間構成的這個四棱台就是視錐體,而透視投影矩陣的任務就是把位於視錐體內的物體的頂點X,Y,Z坐標映射到[-1,1]范圍。這就相當於把這個四棱台扭曲變形成一個立方體。這個立方體叫做規則觀察體 (Canonical View Volume, CVV)。如下圖:

變換方法或規則:
如下圖,有一點P,位於視錐體內,設坐標為(x,y,z).分別對x,y坐標和z坐標的變換到[-1,1]的方式進行討論:
1.x,y坐標的變換方式:
(1)連接視點eye與P點與近裁剪面交於P’點
(2)設近裁剪面的寬度為W,高度為H,P’點的x坐標范圍是[-W/2,W/2],y坐標范圍是[-H/2,H/2],然后分別線性映射至[-1,1]內即可。

2.z坐標的變換方式
z坐標的范圍是N至F,需要映射到[-1,1],映射方法暫時按下,不做想法。
透視投影函數形式
void Matrix4X4::initPersProjMatrix(float FOV, const float aspect, float zNear, float zFar)
透視投影矩陣構建函數的參數:
Fov:縱向的視角大小

aspect:裁剪面的寬高比
zNear:近裁剪面離攝像機的距離,圖中的n
zFar:遠裁剪面離攝像機的距離,圖中的f
通過這幾個參數和三角函數的數學知識可以求得近裁剪面的高度,參考上圖:

求得點P在近裁剪面的投影點P’的坐標
根據相似三角形對應邊長度的比率相同,由圖可得

其中

x’,y’的范圍沿原點對稱,只要將他們分別除以W/2,H/2,即可以使范圍位於[-1,1]內。前面已求得W,H,因此:

假設
我們最后需要的坐標點P’’即是
推導矩陣
然后為了自動化的得到這個結果,我們使用矩陣這種數學工具,將一個矩陣乘以一個向量,得到一個新的向量,使得我們所有的運算步驟和運算數據蘊藏在矩陣和乘法中。下面的工作就是尋找到一個矩陣使得:

我們發現求解
很難找出合適的m00、m02,因為左邊x和z是以加法的形式相鄰,右邊z確成為了x的分母。
解決方法:將右邊的以四維列向量表示的坐標每一項乘以z,所以有:

所以可以求得矩陣為


最后求得投影矩陣為

將這樣的矩陣乘以視錐體內的一個頂點坐標,得到一個新的向量,再將這個向量的每個分量除以第四個分量(z),這樣就可以得到頂點映射到規則立方觀察體后的新的坐標。
注意:z坐標的映射方式的獲得,最后我們是為了方便矩陣乘法的操作反向求得了z坐標與cvv中的z坐標的映射方式:

可見兩者的映射並不是線性的,當z越大時,z的變化對z’’的擾動越小
代碼示例:
1 void Matrix4X4::initPersProjMatrix(float FOV, const float aspect, float zNear, float zFar) { 2 const float zRange = zNear - zFar; 3 const float tanHalfFOV = tanf(ToRadian(FOV / 2.0f)); 4 5 elements[0][0] = 1.0f / (tanHalfFOV * aspect); elements[0][1] = 0.0f; elements[0][2] = 0.0f; elements[0][3] = 0.0; 6 elements[1][0] = 0.0f; elements[1][1] = 1.0f / tanHalfFOV; elements[1][2] = 0.0f; elements[1][3] = 0.0; 7 elements[2][0] = 0.0f; elements[2][1] = 0.0f; elements[2][2] = (-zNear - zFar) / zRange; elements[2][3] = 2.0f * zFar*zNear / zRange; 8 elements[3][0] = 0.0f; elements[3][1] = 0.0f; elements[3][2] = 1.0f; elements[3][3] = 0.0; 9 }
