跳轉到內容

Cg 程式設計/頂點變換

來自華夏公益教科書,開放的書籍,開放的世界

頂點著色器和可程式設計圖形管道中後續階段最重要的任務之一是將圖元(例如三角形)的頂點從原始座標(例如在 3D 建模工具中指定的座標)變換到螢幕座標。雖然可程式設計頂點著色器允許以多種方式變換頂點,但一些變換通常在頂點著色器之後的固定功能階段執行。因此,在程式設計頂點著色器時,瞭解哪些變換必須在頂點著色器中執行尤為重要。這些變換通常作為統一引數指定,並透過矩陣向量乘法應用於輸入頂點位置(和法線向量)。在具有輸入引數 vertex : POSITION 的頂點著色器中,標準變換可以透過此矩陣向量積計算

   mul(UNITY_MATRIX_MVP, vertex)

Unity 的內建統一引數 UNITY_MATRIX_MVP 將標準頂點變換指定為 4x4 矩陣。(但是,在 Unity 中,建議使用函式 UnityObjectToClipPos(vertex) 執行此變換,該函式也適用於立體投影和投影到 360 影像等。)

雖然這對於點和方向來說很簡單,但正如“應用矩陣變換”一節中所述,對於法線向量來說就不那麼簡單了。

這裡,我們將首先概述座標系以及它們之間的變換,然後討論各個變換。

相機類比:1. 定位模型,2. 定位相機,3. 調整縮放,4. 裁剪影像

概述:相機類比

[編輯 | 編輯原始碼]

用相機類比來思考變換頂點的整個過程非常有用,如右圖所示。步驟和相應的頂點變換是

  1. 定位模型 - 模型變換
  2. 定位相機 - 觀察變換
  3. 調整縮放 - 投影變換
  4. 裁剪影像 - 視口變換

前三個變換在頂點著色器中應用。然後,透視除法(可以認為是投影變換的一部分)在頂點著色器之後的固定功能階段自動應用。視口變換也在此固定功能階段自動應用。雖然固定功能階段中的變換無法修改,但其他變換可以被這裡描述的其他型別的變換所取代。但是,瞭解傳統的變換很有用,因為它們允許充分利用裁剪和對變化變數的透視正確插值。

以下概述顯示了各種座標系之間頂點變換的順序,幷包括表示變換的矩陣

物件/模型座標 具有語義的頂點輸入引數(特別是語義 POSITION
模型變換: 模型矩陣 (在 Unity 中:unity_ObjectToWorld
世界座標
觀察變換: 觀察矩陣 (在 Unity 中:UNITY_MATRIX_V
觀察/眼睛座標
投影變換: 投影矩陣 (在 Unity 中:UNITY_MATRIX_P
裁剪座標 具有語義 SV_POSITION 的頂點輸出引數
透視除法 (除以 w 座標)
歸一化裝置座標
視口變換
螢幕/視窗座標

請注意,模型、觀察和投影變換在頂點著色器中應用。透視除法和視口變換在頂點著色器之後的固定功能階段應用。接下來的部分將詳細討論所有這些變換。

模型變換

[編輯 | 編輯原始碼]

模型變換指定從物件座標(也稱為模型座標或區域性座標)到公共世界座標系的變換。物件座標通常特定於每個物件或模型,並且通常在 3D 建模工具中指定。另一方面,世界座標是場景中所有物件的公共座標系,包括光源、3D 音訊源等。由於不同的物件具有不同的物件座標系,因此模型變換也不同;即,必須對每個物件應用不同的模型變換。

模型矩陣的結構

[編輯 | 編輯原始碼]

模型變換可以用 4×4 矩陣表示,我們將其表示為模型矩陣 (在 Unity 中:unity_ObjectToWorld)。它的結構是

     

是一個 3×3 矩陣,表示 3D 空間中的線性變換。這包括任何旋轉、縮放和其他不太常見的線性變換的組合。t 是一個 3D 向量,表示 3D 空間中的平移(即位移)。t 結合在一個方便的 4×4 矩陣中。從數學上來說,模型矩陣表示仿射變換:線性變換加上平移。為了使這種方法起作用,所有三維點都由具有第四座標為 1 的四維向量表示

當我們將矩陣乘以這樣的點時,三維線性變換和平移的組合將在結果中顯示出來

  

除了第四個座標(它應該是點位的 1),結果等於

在頂點著色器中訪問模型矩陣

[edit | edit source]

模型矩陣 可以定義為一個統一引數,使其在頂點著色器中可用。但是,它通常與檢視變換矩陣組合形成模型檢視矩陣,然後將其設定為統一引數。在一些 API 中,矩陣可作為內建的統一引數使用,例如 Unity 中的 unity_ObjectToWorld。(另請參見 “應用矩陣變換”部分。)

計算模型矩陣

[edit | edit source]

嚴格來說,Cg 程式設計師不必擔心模型矩陣的計算,因為它以統一引數的形式提供給頂點著色器。實際上,渲染引擎、場景圖和遊戲引擎通常會提供模型矩陣;因此,頂點著色器的程式設計師不必擔心計算模型矩陣。然而,在某些情況下,在開發圖形應用程式時必須計算模型矩陣。

模型矩陣通常透過組合物件的初等變換的 4×4 矩陣來計算,特別是平移、旋轉和縮放。具體來說,在層次場景圖的情況下,將物件的全部父組(父級、祖父母等)的變換組合起來形成模型矩陣。讓我們看一下最重要的初等變換及其矩陣。

表示向量 t 的平移的 4×4 矩陣是

表示沿軸縮放因子為、沿軸縮放因子為、沿軸縮放因子為 的 4×4 矩陣為

表示繞歸一化軸 旋轉角度為 的 4×4 矩陣為

繞特定軸的旋轉可以很容易地推匯出特殊情況。例如,這些情況對於實現尤拉角旋轉是必要的。但是,尤拉角有多種約定,這裡不會討論。

一個標準化的四元數 對應於繞著角度為 的軸進行旋轉。旋轉軸的方向可以透過對 3D 向量 進行歸一化來確定。

還有其他基本的變換,但對模型矩陣的計算而言並不那麼重要。這些或其他變換的 4x4 矩陣透過矩陣乘積進行組合。假設矩陣 以此特定順序應用於一個物體。( 可能代表從物體座標系到父組座標系的變換; 代表從父組到祖父母組的變換; 代表從祖父母組到世界座標系的變換。)那麼組合的矩陣乘積是

請注意,矩陣因子的順序很重要。還要注意,這個矩陣乘積應該從右(向量被乘的地方)讀到左,即 首先應用,而 最後應用。

檢視座標系的示意圖。

檢視變換

[edit | edit source]

觀察變換對應於放置和定向相機(或觀察者的眼睛)。 但是,看待觀察變換的最佳方式是,它將世界座標轉換為位於座標系原點的相機的檢視座標系(也稱為眼睛座標系),(按慣例)指向軸(在OpenGL中),以及軸(在Direct3D中),並放在平面,即向上方向由正軸給出。

在頂點著色器中訪問檢視矩陣

[edit | edit source]

與模型變換類似,觀察變換由一個4×4矩陣表示,稱為檢視矩陣。 它可以定義為頂點著色器的統一引數(在 Unity 中:UNITY_MATRIX_V); 但是,它通常與模型矩陣組合形成模型檢視矩陣(在 Unity 中:UNITY_MATRIX_MV)。 由於模型矩陣先應用,正確的組合是

(另請參見部分“應用矩陣變換”。)

計算檢視矩陣

[edit | edit source]

與模型矩陣類似,Cg 程式設計師不必擔心檢視矩陣的計算,因為它是以統一引數的形式提供給頂點著色器的。 但是,在開發圖形應用程式時,有時有必要計算檢視矩陣。

這裡,我們簡要總結了如何從相機的t位置、檢視方向d和世界向上向量k(全部以世界座標表示)計算檢視矩陣。 這裡,我們將限制在OpenGL的右手座標系中,其中相機指向軸。(Direct3D 有些符號變化。)這些步驟很簡單

1. 計算(在世界座標中)檢視座標系的軸的方向z,作為負歸一化的d向量

2. 計算(同樣在世界座標中)檢視座標系的軸的方向x,透過

3. 在世界座標系中計算檢視座標系 軸的方向 y

使用 xyzt,可以輕鬆確定逆檢視矩陣 ,因為該矩陣將原點 (0,0,0) 對映到 t,並將單位向量 (1,0,0)、(0,1,0) 和 (0,0,1) 對映到 xy,z。因此,後面的向量必須位於矩陣 的列中。

然而,我們需要矩陣 ;因此,我們必須計算矩陣 的逆。請注意,矩陣 的形式為

其中 是一個 3×3 矩陣,t 是一個 3D 向量。這種矩陣的逆矩陣是

在本例中,矩陣 是正交的(因為它的列向量是歸一化的並且相互正交),因此 的逆矩陣就是它的轉置,即第四步是計算

  

雖然推匯出這個結果需要一些線性代數知識,但最終的計算只需要基本的向量和矩陣運算,並且可以輕鬆地在任何常見的程式語言中實現。

文藝復興時期的透視繪畫:“男人畫魯特琴”由阿爾布雷希特·丟勒創作,1525 年

投影變換和透視除法

[edit | edit source]

首先,投影變換決定投影的型別,例如透視或正交。透視投影對應於具有縮短效果的線性透視,而正交投影是不具有縮短效果的正交投影。縮短效果實際上是透過透視除法實現的;但是,控制透視投影的所有引數都在投影變換中設定。

從技術角度來說,投影變換將檢視座標轉換為裁剪座標。(場景可見部分之外的所有圖元部分都在裁剪座標中被裁剪掉。)它應該是頂點著色器中應用於頂點的最後一個變換,在頂點以語義 SV_POSITION 輸出引數返回之前。然後,這些裁剪座標透過 **透視除法** 轉換為歸一化裝置座標,這只是將所有座標除以第四個座標。(歸一化裝置座標之所以被稱為這個名字,是因為它們的值在場景可見部分的所有點的 -1 到 +1 之間。)

在頂點著色器中訪問投影矩陣

[edit | edit source]

與模型變換和檢視變換類似,投影變換也由一個 4×4 矩陣表示,稱為投影矩陣 。它通常被定義為頂點著色器的統一引數(在 Unity 中:UNITY_MATRIX_P)。

計算投影矩陣

[edit | edit source]

與模型檢視矩陣類似,Cg 程式設計師不必擔心投影矩陣的計算。但是,在開發應用程式時,有時需要計算投影矩陣。

這裡,我們展示了三種情況下的投影矩陣(所有情況都是針對 OpenGL 約定,即相機指向檢視座標中的負 軸)

  • 標準透視投影(對應於 OpenGL 2.x 函式 gluPerspective
  • 斜透視投影(對應於 OpenGL 2.x 函式 glFrustum
  • 正交投影(對應於 OpenGL 2.x 函式 glOrtho
角度 的說明,它指定了 *y* 方向上的視場。
以下是近裁剪平面和遠裁剪平面在 的示意圖。

標準透視投影的特點是

  • 一個角度 ,它指定了 方向上的視野,如右圖所示,
  • 到近裁剪平面的距離 和到遠裁剪平面的距離 ,如下一圖所示,
  • 近裁剪平面上中心矩形的寬高比

與視點和裁剪平面一起,這個中心矩形定義了視錐體,即對於特定投影變換可見的 3D 空間區域。視錐體外的所有基本圖形和所有基本圖形的部分都被裁剪掉。近裁剪平面和遠裁剪平面是必要的,因為深度值以有限精度儲存;因此,不可能覆蓋無限大的視錐體。

使用引數 ,透視投影的投影矩陣

  

斜透視投影的引數。

斜透視投影的特點是

  • 與標準透視投影情況相同,到裁剪平面的距離
  • 座標 (右)、(左)、(上)和 (下),如相應圖形所示。這些座標決定了視錐體前矩形的位置;因此,可以使用縱橫比 和視野角度 以外,指定更多視錐體(例如,偏心)。

給定引數 ,斜視投影的投影矩陣

正投影的引數。

右圖說明了正投影,它沒有透視縮短。引數與斜視投影的情況相同;但是,視錐體(更準確地說,是視體積)現在是一個盒子,而不是一個截斷的金字塔。

使用引數 ,和 ,正交投影的投影矩陣 是:

視口變換的示意圖。

視口變換

[edit | edit source]

投影變換將檢視座標對映到裁剪座標,然後透過裁剪座標的第四個分量進行透視除法,對映到歸一化裝置座標。在歸一化裝置座標(ndc)中,檢視體積始終是一個以原點為中心的方框,方框內的座標介於 -1 和 +1 之間。然後,該方框透過視口變換對映到螢幕座標(也稱為視窗座標),如相應圖形所示。此對映的引數是視口(螢幕上渲染的矩形)的左下角座標 ,以及它的寬度 和高度 ,以及遠近裁剪平面的深度 。(這些深度介於 0 和 1 之間)。在 OpenGL 和 OpenGL ES 中,使用兩個函式設定這些引數

glViewport(GLint , GLint , GLsizei , GLsizei );

glDepthRangef(GLclampf , GLclampf );

視口變換矩陣並不重要,因為它在固定功能階段自動應用。但是,為了完整起見,這裡列出它。

進一步閱讀

[編輯 | 編輯原始碼]

傳統的頂點變換在Nvidia 的 Cg 教程第 4 章中也進行了簡要說明。

傳統的 OpenGL 變換在“OpenGL 4.1 Compatibility Profile Specification”第 2.12 節中進行了詳細描述,該規範可以在Khronos OpenGL 網站上獲得。Dave Shreiner 編著的“OpenGL Programming Guide”一書的第 3 章(關於檢視)對頂點變換進行了更易懂的描述。該書由 Addison-Wesley 出版。(舊版可在網上獲得)。

< Cg 程式設計

除非另有說明,本頁上的所有示例原始碼均歸屬公共領域。
華夏公益教科書