1. 程式人生 > >opoengl 投影矩陣的推導

opoengl 投影矩陣的推導

原文:http://blog.csdn.net/wangdingqiaoit/article/details/39010077

OpenGL學習腳印: 投影矩陣的推導

寫在前面

               本節內容翻譯和整理自http://www.songho.ca songho的部落格《OpenGL Projection Matrix》內容,以供自己和初學者熟悉投影矩陣推導過程。

通過本節,你可以瞭解到:

  •  投影矩陣計算的階段
  •  透視投影和正交投影的矩陣推導
本節的要點就在於:   閱讀時,自己拿筆推導一遍。

1.概覽

計算機螢幕是2維的,OpenGL渲染的3D場景必須以2D形式的影象投影到螢幕上。GL_PROJECTION 矩陣就是用來設定投影變換的。首先,它將所有頂點從眼座標(

照相機座標)轉換到裁剪座標系下。然後,這些裁剪座標通過透視除法,即除以裁剪座標中w分量,轉換到歸一化裝置座標系(NDC)

                                                                                                                               
                                                                                                      一個由視錐裁剪的三角形

因此,我們要記住,裁剪(視錐剔除frustum culling)NDC轉換都整合到了GL_PROJECTION 矩陣。接下來的部分描述了怎麼樣通過left, right, bottom, top, near and far 這6個界限引數來構造投影矩陣。

注意:

   視錐剔除是在裁剪座標系中進行的,並且恰好在透視除法之前進行。裁剪座標xc, yc 和 zc 通過與wc比較來進行測試。 如果某個座標值比Wc小或者比Wc大,那麼這個頂點將被丟棄。然後,OpenGL會重新在裁剪進行的地方構造多邊形的邊緣。

補充內容:

實際上,眼座標系下座標在乘以投影矩陣後,裁剪測試和透視除法都是由GPU來執行的。而後面這兩個過程處理的裁剪座標系資料都是由投影矩陣變換的。

1. 裁剪測試也即視錐剔除

-Wc < Xc,Yc,Zc < Wc

2. NDC透視除法

Xn = Xc / Wc  Yn = Yc / Wc   Zn = Zc / Wc

這裡需要注意的是,我們在構造16個引數的投影矩陣的同時,不僅要考慮到裁剪,還要考慮到透視除法的過程。這樣,最終的NDC座標才會滿足:

-1 < Xn,Yn,Zn < 1

2.透視投影

在透視投影中,在眼座標下截頭椎體(a truncated pyramid frustum)內的3D點被對映到NDC下一個立方體中;x座標從[l,r]對映到[-1,1],y座標從[b,t]對映到[-1,1],z座標從[n,f]對映到[-1,1]。

注意:

     眼座標系使用右手座標系,而NDC使用左手座標系。這就是說,眼座標系下,在原點處的照相機朝著-Z軸看去,但是在NDC中它朝著+Z軸看去。因為glFrustum() 僅接受正的nearfar距離,我們在構造GL_PROJECTION 矩陣時,需要取其相反數。眼座標系和NDC座標系如下圖所示:


OpenGL,眼座標下3D點被投影到近裁剪面(即投影平面)。下圖展示了眼座標系下點(xe, ye, ze) 如何投影到近裁剪面上的 (xp, yp, zp) 的。(左側是視錐的俯檢視,右側是視錐的側檢視,拿出右手構成右手座標系,然後比劃比劃就出來了)

根據三角形的相似性,由俯檢視可得出:

由側檢視可以得出:

補充: xp 和yp其實是一箇中間值,我們要找的是(Xc, Yc, Zc)和 (Xn, Yn, Zn)之間的關係,但是可以利用:

這一關係做過渡,後面利用xp和yp,對映到NDC中xn和yn的線性關係就利用到了 xp 和yp。這一點很重要。

注意,這裡 xp 和yp 都依賴於ze,他們與 -ze成反比。換句話說,他們都被 -ze相除。這個事構造GL_PROJECTION    矩陣最初的線索。在眼座標通過乘以 GL_PROJECTION    來轉換時,裁剪座標系仍然是一個齊次座標系。通過對裁剪座標進行透視除法得到最終的NDC座標。下圖解釋了這個過程:


因此我們可以把裁剪座標系下的w分量設為-ze,那麼GL_PROJECTION矩陣第4行變為(0, 0, -1, 0),如下圖(求出了投影矩陣第4行):


下現在我們把xp和yp,對映到NDC中xn和yn,他們之間是線性關係: [l, r] ⇒ [-1, 1]和[b, t] ⇒ [-1, 1].

線性關係如下圖所示:

則可以推匯出:

細節部分有刪節,這個推導過程使用的就是簡單的y=kx+b線性關係推導,同理利用[b, t] ⇒ [-1, 1]可推得:

將上面的 xp 和yp帶入求得:

注意這裡Xn和Yn已經是NDC中的座標了,通過這兩個座標可以求出GL_PROJECTION 的前兩行來,書寫如下(求出了投影矩陣第1,2,4行):

現在怎麼求出第3行呢?

找出zn與找出xnyn不同,因為 ze總是被投影近裁剪面-n上。但是我們需要唯一的Z值進行裁剪和深度測試。另外,我們還能夠unproject即反向變換(inverse transform)。因為Z值不依賴於x或者y,因此我們借用w分量來找出 zn 和 ze之間的關係。

因此我們可以這樣指定第3行:

在眼座標下We等於1,因此上式變為:

我們使用(ze, zn)的關係(-n, -1)和 (-f, 1)來求解出係數A,B;

細節部分有刪節,使用消元法即可求出:

我們求出了A和B,那麼ze和zn關係如下式:

最終的投影矩陣如下式:

這個公式對應的是一般的視錐,如果視錐是對稱的,即r = -l ,t= -b,那麼有:

z-fighting

在繼續之前,我們來看看錶示ze和zn關係的式3.這是一個有理函式,並且ze和zn之間不是線性關係。這意味著,在近裁剪面的精度很高,而遠裁剪面則很小。如果[-n, -f]範圍變得大寫,就會引起深度精度問題,即z-fighting。在遠裁剪面附近,ze的小變化根本不影響zn值。近裁剪面和遠裁剪面之間的n和f舉例,應該儘可能小,來減少深度快取的精度問題。可參考下圖來幫助理解。


3.正交投影

構造正交投影的矩陣簡單很多。所有的是眼座標下xe, ye 和ze,都被線性的對映到NDC中。我們需要做的就是講長方體視景體縮放為規範視見體,然後移動到原點。如下圖所示:

xe和xn之間對映關係為例,[l,r]=>[-1,1],則可以推導如下:

y,z也有類似推導,這裡省略,最後得出投影矩陣為:

如果視錐是對稱的話,即r = -l ,t= -b的話,則可以簡化為:

到這裡透視投影和正交投影矩陣推導完畢。