透視投影的推導

概述

投影變換完成的是如何將三維模型顯示到二維視口上,這是一個三維到二維的過程。你可以將投影變換看作是調整照相機的焦距,它模擬了爲照相機選擇鏡頭的過程。投影變換是所有變換中最複雜的一個。

視錐體

視錐體是一個三維體,他的位置和攝像機相關,視錐體的形狀決定了模型如何從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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章