概述
投影變換完成的是如何將三維模型顯示到二維視口上,這是一個三維到二維的過程。你可以將投影變換看作是調整照相機的焦距,它模擬了爲照相機選擇鏡頭的過程。投影變換是所有變換中最複雜的一個。
視錐體
視錐體是一個三維體,他的位置和攝像機相關,視錐體的形狀決定了模型如何從camera space投影到屏幕上。最常見的投影類型-透視投影,使得離攝像機近的物體投影后較大,而離攝像機較遠的物體投影后較小。透視投影使用棱錐作爲視錐體,攝像機位於棱錐的椎頂。該棱錐被前後兩個平面截斷,形成一個棱臺,叫做View Frustum,只有位於Frustum內部的模型纔是可見的。
透視投影的目的
透視投影的目的就是將上面的棱臺轉換爲一個立方體(cuboid),轉換後,棱臺的前剪裁平面的右上角點變爲立方體的前平面的中心(下圖中弧線所示)。由圖可知,這個變換的過程是將棱臺較小的部分放大,較大的部分縮小,以形成最終的立方體。這就是投影變換會產生近大遠小的效果的原因。變換後的x座標範圍是[-1, 1],y座標範圍是[-1, 1],z座標範圍是[0, 1](OpenGL略有不同,z值範圍是[-1, 1])。
透視投影矩陣推導
下面來推導一下透視投影矩陣,這樣我們就可以自己設置投影矩陣了,就可以模擬神奇的D3DXMatrixPerspectiveLH函數的功能了。那麼透視投影到底做了什麼工作呢?這一部分算是個難點,無論是DX SDK的幫助文檔,還是大多數圖形學書籍,對此都是一帶而過,很少有詳細討論的,早期的DX SDK文檔還討論的稍微多一些,而新近的文檔則完全取消了投影矩陣的推導過程。
我們可以將整個投影過程分爲兩個部分,第一部分是從Frustum內一點投影到近剪裁平面的過程,第二部分是由近剪裁平面縮放的過程。假設Frustum內一點P(x,y,z)在近剪裁平面上的投影是P'(x',y',z'),而P'經過縮放後的最終座標設爲P''(x",y",z")。假設所求的投影矩陣爲M,那麼根據矩陣乘法可知,如下等式成立。
PM=P'',即
先看第一部分,爲了簡化問題,我們考慮YOZ平面上的投影情況,見下圖。設P(x, y, z)是Frustum內一點,它在近剪裁平面上的投影是P'(x', y', z')。(注意:D3D以近剪裁平面作爲投影平面),設視錐體在Y方向的夾角爲Θ。
由上圖可知,三角形OP'Q'與三角形OPQ相似,於是有如下等式成立。
在看第二部分,將P'縮放的過程,假設投影平面的高度爲H,由於轉換後cuboid的高度爲2。所以有
又因爲投影平面的縱橫比爲Aspect,所以
最後看z'',因爲在光柵化之前,我們需要對z座標的倒數進行插值,所以可以將z''寫成z的一次表達式形式,如下
在映射前,z的範圍是[n,f],這裏n和f分別是近遠兩個剪裁平面到原點的距離,在映射後,z''的範圍是[0,1],將數據代入上面的一次式,可得下面的方程組
解這個方程組得到
所以
整理一下得
將X'',y'',z''代入最開始的矩陣乘法等式中得
由上式可見,x'',y'',z''都除以了Pz,於是我們將他們再乘以Pz(這並不該變齊次座標的大小),得到如下等式。
注意這裏,x即Px,y即Py,z即Pz,解矩陣的每一列得到
於是所求矩陣爲
代碼
一般來說,在程序中我們通常給定四個參數來求透視投影矩陣,分別是y方向的視角,縱橫比,近剪裁平面到原點的距離及遠剪裁平面到原點的距離,通過這四個參數即可求出上面的矩陣,代碼如下。
D3DXMATRIX BuildProjectionMatrix(float fov, float aspect, float zn, float zf) { D3DXMATRIX proj; ZeroMemory(&proj, sizeof(proj)); proj.m[0][0] = 1 / (tan(fov * 0.5f) *aspect) ; proj.m[1][1] = 1 / tan(fov * 0.5f) ; proj.m[2][2] = zf / (zf - zn) ; proj.m[2][3] = 1.0f; proj.m[3][2] = (zn * zf) / (zn - zf); return proj ; }
矩陣求解完畢,現在可以用如下代碼試試效果,這和使用D3D函數D3DXMatrixPerspectiveFovLH所得效果是一致的。
D3DXMATRIX proj = BuildProjectionMatrix(D3DX_PI / 4, 1.0f, 1.0f, 1000); g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;
Happy Coding!!!
摘自:http://www.cnblogs.com/graphics/archive/2012/07/25/2582119.html