有沒有想過這樣的問題,計算機是如何把3維的模型顯示到2維的屏幕上?照相機又是如何把3維的世界記錄成2維的照片的?
發現了嗎?世界被降維了!而投影矩陣(
Projection Matrix
)就是進行這步降維的關鍵,它就像是一張二向箔,將3維的世界變成一幅幅壯麗的二維畫卷.......
有多種類型的投影,比如說正交投影(
Orthographic Projection
)、透視投影等(Perspective Projection
) 。
人的眼睛使用的是
透視投影,在這種投影下,同樣大小的物體放在近處就會顯得比放在遠處大。
在這里使用OpenGL里對透視投影矩陣的定義來介紹
。
透視投影矩陣要解決一個問題:一個三維坐標上的點,它在一個二維平面(像平面)上的坐標是多少?
相機是小孔成像模型,所有被采集到的光線都要通過光心這一點,於是光心(紅點)和原始三維點(藍點)的連線所交於像平面(藍線)的點(黃點)就是最終要成像的點。像平面距離光心的距離為n。如下圖,假設相機是朝Z軸的負方向看的,並且Z軸穿過光心和像平面的中心。
哎,有讀者嫌棄我畫的圖太丑,其實我也是這么覺得的,沒那么多時間畫圖(好像有時間就能畫好似的....)。下面就用參考資料里的圖吧。
細心的讀者會發現圖中多個一個平面,距離光心得距離是f,這個平面的意義在於z的值小於-f的點都不會投射到像平面上。至於為什么要多這個far平面嘛.....大家看到最后就會明白了。<( ̄︶ ̄)>
好了,如圖所示,根據相似三角形原理,就可以求出一個三維點(xe,ye,ze)在像平面上的坐標(xp,yp)。
另外,根據opengl的實現,需要將坐標轉化成 NDC(normalized device coordinates) ,簡單來說,就是定義一定范圍的坐標范圍,這個范圍形成一個類似錐型的區域(frustum),將這個區域內的坐標按照3個坐標軸的方向映射成[-1,1]的值,最終形成一個立方體。
如圖所示,例如z=-n的平面被映射成z=-1,z=-f的平面被映射成z=1。
原先的x坐標從[l,r] 被映射成x坐標為[-1,1]
原先的y坐標從[b,t] 被映射成y坐標為[-1,1]。
現在我們需要把這些坐標的變化寫成矩陣的形式,寫成矩陣 M
projection
。
但是
像平面上的坐標(x
p
,y
p
)的計算公式中是有除法的,這樣的話就沒辦法寫成線性的矩陣運算的形式了。沒關系,我們可以使用3維點的
齊次坐標(Homogeneous Coordinates) 來運算。
最終就可以獲得NDC坐標(發現沒?除法出現了!):
需要構造出M
projection
因為最后需要除的數是-Ze, 所以需要保證W
clip的值為-Ze, 於是 M矩陣的最后一行應該為[0 0 -1 0].。
其次,要保證除x和y要被線性映射成[-1,1]。
先設計一個線性方程:
當x
p = r 時 x
n=1
求解出
又:
看上是不是就可以寫成矩陣形式了?
同理可以獲得y方向上的坐標轉換公式,就得到了前兩行矩陣:
接下來就只剩下第三行需要求解了。
我們知道z的值是不依賴x和y的,於是第三行的前兩個元素為0,設另外兩個值為A、B:
最終得到的坐標為:
齊次坐標下的w是等於1的,所以等式變為:
要求解A、B怎么辦?找兩個點代入進去呀。
這兩個點為(-n, -1) 和 (-f, 1)。於是:
解得
最終,得到了完整的投影矩陣:
注意到沒!Z
e和Z
n的關系不是線性的!
在接近near平面時精度高,在接近far平面時精度低,如果far和near相距較大時,就會產生深度精度問題(z-fighting),所以在滿足需求的情況下,far和near要盡可能接近。
好了,世界就這樣被二維化了,Enjoy it!
參考資料
http://www.songho.ca/opengl/gl_projectionmatrix_mathml.html

