在網上看了很多關於在三維世界中怎么把一個頂點經過一步步變化,最終呈現在我們的屏幕上的。
其實很多博客或者書籍已經講的很清楚了,那為什么我還要特別再寫一次博客來闡述自己觀點呢?(這里只針對那些學習webgl時,想徹底了解清楚空間過程的同學而言)
因為在我一開始對三維不是很懂的情況下,看了很多書和博客,覺得他們寫的已經很牛逼了,而且讓我受益匪淺,但是隨着知識量的不斷增加 ,我意識到一個問題,那就是我好像理解缺點什么,或者說有的地方的理解甚至是錯的,比如說一個問題,也是我記錄這篇文章的主要目的,以前我對三維空間的坐標變化理解是這樣的:
模型坐標----(模型矩陣,即吧模型坐標系下的坐標變換到世界坐標系下的坐標的過程,其他矩陣也是一樣,比如視圖矩陣就是把世界坐標系下的坐標變換到視圖坐標系下的坐標的過程)----世界坐標 ---- 視圖矩陣----投影矩陣----屏幕坐標
基本書上(webgl編程指南)或者網上90%的博客都是這樣講的,這是可以的,但是是不嚴謹的,因為從投影矩陣到屏幕坐標的轉換過程,是不需要你進行處理的,這部分是渲染管線自己執行的。
如果不是因為在工作中遇到一些奇奇怪怪的參數和新的東西,以及和同事的討論中,發現好多概念根本不懂, 我也不會懷疑自己的理解。所以我找到了webgl的祖宗opengl去一探究竟。
以下是opengl中完整的對三維空間變換的介紹,很有價值:
另外我補充一點,webgl編程指南中之所以會省略一部分細節不去講,並不是說webgl里面有錯,而是那部分細節,不在可編程渲染管線范圍內(就是說我們可以自己編寫代碼參與到渲染的部分,大概包括,定義頂點位置, 編寫頂點着色器和片元着色器。)所以,webgl並沒有細講。
在使用 OpenGL 的應用程序中,當我們指定了模型的頂點后,頂點依次會變換到不同的 OpenGL 空間中:
- 世界空間
- 模型空間(也稱為對象空間)
- 視圖空間(也稱為視點空間、攝像機空間)
- 裁剪空間
- 標准設備坐標空間
- 窗口空間
在經過這一系列的空間變換之后,頂點才會被顯示在屏幕上。
世界空間(World Space)
世界空間相對於其他坐標空間來說是固定不變的。所以,它也被用作空間變換的參考系。我們把它的坐標系稱為世界坐標系。在沒有特別說明的情況下,我們用來描述一個幾何對象(點、向量或坐標)的數值數據,都是基於世界坐標系來設定的。
世界坐標系用矩陣來表示就是一個單位矩陣。
模型空間(Model Space)
模型空間,也稱為對象空間。如果把世界空間比作現實世界的話,那么模型就好比一座房子或者房子里的一個人等等。假設以人的重心為原點,正面向前的方向為 z-軸,頭頂的方向為 y-軸,左側方向為 x-軸來構建一個坐標系。我們可以用這個坐標系來描述這個人自身的模型空間。這個坐標系也稱為模型坐標系(或對象坐標系)。
模型坐標系並不是絕對的,如果以人的鼻尖為原點,頭頂的方向改為 z-軸,正面向前的方向為 y-軸,右側方向為 z-軸來構建其模型坐標系。這個模型坐標系同樣可以用來描述這個人自身的模型空間。只不過用不同坐標系來描述時,描述出來的數據不一定相同。
一般來說,我們都是基於世界坐標系來描述模型坐標系的。在這種情況下,世界坐標系可以看作是模型坐標系的父坐標系:
其中,黑色的坐標系為世界坐標系;灰色的坐標系為模型坐標系。
模型變換(模型-世界變換)
默認情況下模型坐標系的原點位於世界坐標系的原點,並且坐標軸的方向與世界坐標系的坐標軸一致。我們可以通過一系列的縮放、旋轉和平移,將模型以任意角度擺在任意位置上。這種情況下,模型上的頂點以及模型自身的坐標系都會相對世界坐標系發生了變化。
模型變換的實質就是將模型上的頂點在模型空間中的描述,轉換為在世界空間中的描述。假設有一個模型坐標系表示為矩陣 M(基於世界坐標系來描述),一個頂點在該模型坐標系上的坐標表示為列向量 D。 那么,該頂點在世界坐標系中的坐標 D‘,有如下變換關系:M·D = D’。M 也稱為模型矩陣。模型矩陣本質上是一系列縮放、旋轉和平移矩陣的復合矩陣。
視圖空間(View Space)
視圖空間,也稱為視點空間或攝像機空間。它是以攝像機(或者觀察者)的角度來定義的一個空間。視圖空間可以通過視圖坐標系(也稱為視點坐標系或攝像機坐標系)來描述。從攝像機的角度來看,視圖坐標系 x-軸和 y-軸的正方向分別指向攝像機右方和上方,而 z-軸的負方向則指向攝像機的鏡頭指向。在透視投影中,攝像機位於視圖坐標系的原點。所以 z 坐標為正的模型位於攝像機的背后,攝像機無法拍到它;而在正交投影中,攝像機被認為是位於在視圖坐標系 z-軸正方向上的無窮遠處。
透視投影中,攝像機與視圖坐標系的位置關系圖
正交投影中,攝像機與視圖坐標系的位置關系圖
與模型坐標系類似,我們一般也會基於世界坐標系來描述視圖坐標系的。所以在這種情況下,世界坐標系可以看作是視圖坐標系的父坐標系:
其中,黑色的坐標系為世界坐標系;藍色的坐標系為視圖坐標系。
視圖變換(世界-視圖變換)
默認情況下,視圖坐標系位於世界坐標系的原點,並且坐標軸的方向與世界坐標系的坐標軸一致。我們可以通過一系列的縮放、旋轉和平移,將攝像機以任意角度擺在任意位置,以方便我們的拍攝。當攝像機的位置、角度發生變化時,拍攝到的場景也會發生變化(也就是說空間中的模型相對於視圖坐標系來說都發生了變化)。
視圖變換的實質就是將某個頂點在世界空間中的描述,轉換為在視圖空間中的描述。假設有一個頂點在在世界坐標系中的坐標表示為列向量 D‘,一個視圖坐標系表示為矩陣 V(基於世界坐標系來描述的),那么該頂點在視圖坐標系 V 中的坐標 D,有如下變換關系:V·D = D’(道理和模型變換類似)。設 V 的逆矩陣為 V’,可以推導出變換關系 V‘·D‘ = D,V’ 也被我們稱為視圖矩陣。
模型視圖矩陣(Model-View)
為了渲染一個模型,我們通常會先將它從模型空間變換到世界空間,然后再從世界空間變換到視圖空間。這兩個過程都有對應的變換矩陣:模型矩陣和視圖矩陣。我們可以將這兩個矩陣結合起來用一個復合矩陣來表示,這樣的一個復合矩陣我們稱為模型視圖矩陣。通過模型視圖矩陣,我們可以將模型上的頂點從模型空間直接變換到攝像機的視圖空間。這樣做有兩個好處:
-
假如在世界空間中有許多模型,並且每個模型包含許多頂點。那么用一個復合矩陣把單個模型的所有頂點一次性變換到視圖空間,比對所有頂點都做兩次矩陣變換要高效得多。
-
因為一個空間可以是無限大的,所以將頂點從模型空間變換到世界空間中,所做的變換常常需要用到不同的精度去計算,這主要依賴於頂點離世界坐標的原點有多遠。同樣的,當我們再把頂點從世界空間變換到視圖空間時,所做變換的精度也需要依賴於頂點到攝像機的距離有多遠。對那些距離攝像機很近的頂點采用高精度是合適的,但對於距離攝像機很遠的頂點同樣采用高精度則會產生精度損失。想象一下,當模型與攝像機離得很近,並且兩者又離世界坐標系的原點很遠時,變換兩次容易產生精度損失。用復合矩陣可以有效減少精度損失,提高結果的精確性。
裁剪空間(Clip Space)
不難理解,攝像機是無法同時拍攝到場景內所有的東西的。每個攝像機都會定義一個視景體,視景體決定了攝像機可以看到的空間。完全位於視景體內的模型將會被保留;完全位於視景體外的模型將被剔除;而與視景體裁剪平面相交的模型則會被裁減(即保留在視景體內的部分,剔除在視景體外的部分)。這個決定模型是保留還是剔除的過程,我們稱之為裁剪。
視景體指的是空間中的一塊區域,它由六個平面包圍而成,這些平面被統稱為裁剪平面。其中,有兩塊平面比較重要,它們都垂直都於攝像機的鏡頭指向,離攝像機比較近的那塊被稱為近裁剪平面,而離攝像機比較遠的那塊則被稱為遠裁剪平面。這兩塊平面決定了攝像機可以看到的深度范圍。
透視投影的視景體示意圖
正交投影的視景體示意圖
對於不同的投影,其對應視景體的形狀也有所不同。比如正交投影的視景體是一個長方體。而透視投影的視景體則是一個平截頭體(像一個頂部被平截掉的金字塔)。如果我們直接使用視景體所定義的空間來進行裁剪,那么對不同的視景體就要采用不同的處理過程,特別是判斷一個頂點是否處於一個平截頭體內是比較麻煩的。因此,我們采用更加通用的裁剪空間來描述不同視景體所定義的空間。在裁剪空間中,我們可以用統一的方式來處理不同視景體的裁剪。
裁剪變換
將一個頂點從視圖空間變換到裁剪空間的過程叫作裁剪變換,我們可以通過一個裁剪矩陣(也稱為投影矩陣)來實現該變換。這里有個迷惑點,雖然裁剪矩陣也叫投影矩陣,但其實它並沒有進行真正的投影工作,只是在為投影做准備工作,真正的投影工作發生在下一階段的變換中。
透視投影的裁剪變換
透視投影的視景體為一個平截頭體,我們可以通過下面幾個參數來定義該平截頭體:近裁剪平面、遠裁剪平面在視圖坐標系中的 z 坐標:near、far,近裁剪平面上下兩條邊在視圖坐標系中的 y 坐標:top、bottom,還有近裁剪平面左右兩條邊在視圖坐標系中的 x 坐標:left、right。
我們可以根據以上這些已知的參數,來給出透視投影的裁剪矩陣:
對於視圖空間坐標為 (x, y, z, 1) 的頂點,經過透視裁剪矩陣變換后的結果如下:
該結果表示頂點在裁剪空間中的坐標。我們可能注意到了,此時頂點的 w 分量不再是 1 了,而是變換前 z 分量的取反結果。雖然我們在裁剪空間之前,就使用齊次坐標來表示空間中的幾何對象(點、向量或坐標系),而且 w 分量一直是固定的:點位置的 w 分量為 1,向量的 w 分量表示為 0。在變換到裁剪空間之后,我們將賦予齊次坐標的 w 分量更加豐富的含義:作為一個臨界值來判斷一個經過裁剪變換后的頂點是否位於景視體內。如果變換后的坐標值 x、y、z 均在區間 [-w, w] 內,則表明該頂點在視景體內。否則,表明該頂點不在視景體內,將會被拋棄。
正交投影的裁剪變換
正交投影的視景體為一個長方體,平截頭體的參數概念對於長方體來說同樣適用。現在,我們根據這些已知的參數,來給出正交投影的裁剪矩陣:
對於視圖空間坐標為 (x, y, z, 1) 的頂點,經過正交裁剪矩陣變換后的結果如下:
很明顯,當變換前的 x 坐標在 right 與 left 之間時,變換后的 x 坐標在區間 [-1, 1] 內。對於 y 和 z 坐標同理可證。也就是說,如果變換后的坐標值 x、y 、z 均在區間 [-1, 1] 內,則表明該頂點在視景體內。而且這里的 w 為 1,所以其裁剪的判斷規則與透視投影中是一致的。
裁剪空間使用同一套空間標准來描述不同視景體所定義的空間(通過執行不同的裁剪矩陣變換),把不同視景體的裁剪方式進行了統一。除此之外,裁剪空間也為后面真正的投影工作提供了方便。
標准設備坐標空間(NDC Space)
如今,顯示屏幕的分辨率多不勝數,我們很難在每一種分辨率上都能把頂點顯示在正確的位置上。
為了解決這個硬件適配的問題,我們在頂點被渲染到屏幕上之前,將其變換到標准設備坐標空間中。標准設備坐標空間采用一種無量綱的單位坐標來代替設備坐標,直到頂點被輸出到屏幕時,單位坐標才會轉換為具體的設備坐標。標准設備坐標系的 x、y、z 軸的范圍被定義為 [-1, 1]。這樣可以將應用程序與具體的顯示設備隔離開來,應用程序無需關心顯示設備的分辨率,增加了應用程序的可移植性。
對於正交投影,任意頂點在裁剪空間的坐標值 x、y 、z 均在區間 [-1, 1] 內,這種情況下無需任何變換,裁剪空間本身也是標准設備坐標空間。
對於透視投影,我們只需要對頂點在裁剪空間的坐標執行齊次坐標標准化,使其 w 分量變為 1。對應的 x、y、z 也將會縮小到范圍 [-1, 1] 內。這種情況下,標准化的過程其實也是將頂點從裁剪空間坐標變換到到標准設備坐標空間的過程。
而且,因為標准化前的 w 分量與頂點到攝像機的距離成正比。所以,頂點離攝像機越遠則 w 越大,w 越大則在標准化時 x、y、z 被縮得越小,這樣就達到了透視收縮和投影的效果。所以,標准化的過程也是真正的投影過程。
窗口空間(Windows Space)
窗口空間,實際上指的就是顯示屏幕或屏幕上某塊區域(比如屏幕桌面上的窗口)的空間。窗口空間不僅取決於屏幕的分辨率或窗口的大小,也取決於窗口的位置。因為在標准設備坐標空間中,任意頂點的坐標值都在范圍 [-1, 1] 內。所以,無論窗口空間是什么樣的,我們都能很好的把頂點的標准設備坐標映射到具體的屏幕或屏幕的指定顯示區域上。