跳轉到內容

GLSL 程式設計/頂點變換

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

頂點著色器和之後在 OpenGL (ES) 2.0 管道 中的階段中最重要的一項任務是,將圖元(例如三角形)的頂點從原始座標(例如在 3D 建模工具中指定的座標)變換到螢幕座標。雖然可程式設計的頂點著色器允許以多種方式變換頂點,但一些變換是在頂點著色器後的固定功能階段執行的。因此,在程式設計頂點著色器時,瞭解哪些變換必須在頂點著色器中執行尤為重要。這些變換通常以統一變數的形式指定,並透過矩陣-向量乘法應用於傳入的頂點位置和法向量。雖然對於點和方向來說這是直觀的,但對於法向量來說就不那麼直觀了,如 “應用矩陣變換”部分 中所述。

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

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

概述:相機類比

[編輯 | 編輯原始碼]

將變換頂點的整個過程想象成一個相機類比,如右圖所示,步驟和相應的頂點變換是

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

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

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


物件/模型座標 頂點著色器的輸入,即屬性中的位置
模型變換:模型矩陣
世界座標
觀察變換:觀察矩陣
觀察/眼睛座標
投影變換:投影矩陣
裁剪座標 頂點著色器的輸出,即 gl_Position
透視除法(除以 gl_Position.w
歸一化裝置座標
視口變換
螢幕/視窗座標 片段著色器中的 gl_FragCoord


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

模型變換

[編輯 | 編輯原始碼]

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

實際上,它會將物件從原點“推開”,並可以選擇對其應用旋轉。

模型矩陣的結構

[編輯 | 編輯原始碼]

模型變換可以用一個 4×4 矩陣表示,我們將其表示為模型矩陣 . 它的結構是

     

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

當我們將矩陣乘以這樣的點 時,三維線性變換和平移的組合會體現在結果中。

  

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

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

[edit | edit source]

模型矩陣 可以定義為一個統一變數,以便在頂點著色器中使用。然而,它通常與檢視變換矩陣結合起來形成模型檢視矩陣,然後將其設定為統一變數。在一些版本的 OpenGL(ES)中,在頂點著色器中可以使用內建的統一變數 gl_ModelViewMatrix。(另見 “應用矩陣變換”部分。)

計算模型矩陣

[edit | edit source]

嚴格來說,GLSL 程式設計師不必擔心模型矩陣的計算,因為它以統一變數的形式提供給頂點著色器。事實上,渲染引擎、場景圖和遊戲引擎通常會提供模型矩陣;因此,頂點著色器的程式設計師不必擔心計算模型矩陣。然而,在現代版本的 OpenGL 和 OpenGL ES 或 WebGL 中開發應用程式時,必須計算模型矩陣。(OpenGL 3.2 之前的版本、新版本 OpenGL 的相容性配置檔案以及 OpenGL ES 1.x 提供了計算模型矩陣的函式。)

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

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

表示按因子 沿 軸縮放、按因子 沿 軸縮放,以及按因子 沿 軸縮放的 4×4 矩陣是

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

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

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

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

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

檢視座標系的示意圖。

檢視變換

[編輯 | 編輯原始碼]

視點變換對應於放置和定向相機(或觀察者的眼睛)。然而,思考視點變換的最佳方式是它將世界座標轉換為相機的檢視座標系(也稱為眼睛座標系),該相機放置在座標系的原點,指向 **負** 軸,並放置在 平面上,即向上方向由正 軸給出。

此步驟將整個世界旋轉朝向相機,相機始終從原點看向一個固定位置。

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

[edit | edit source]

與模型變換類似,視點變換由一個 4×4 矩陣表示,稱為檢視矩陣 。它可以定義為頂點著色器的統一變數;但是,它通常與模型矩陣 結合形成模型檢視矩陣 。(在某些版本的 OpenGL (ES) 中,頂點著色器中提供了一個內建的統一變數 gl_ModelViewMatrix。)由於模型矩陣首先應用,所以正確的組合是

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

計算檢視矩陣

[edit | edit source]

與模型矩陣類似,GLSL 程式設計師不必擔心檢視矩陣的計算,因為它以統一變數的形式提供給頂點著色器。但是,在開發現代版本的 OpenGL 和 OpenGL ES 或 WebGL 中的應用程式時,有必要計算檢視矩陣。(在舊版本的 OpenGL 中,這通常透過一個名為 gluLookAt 的實用程式函式來實現。)

在這裡,我們簡要總結了如何從相機的方位 t、觀察方向 d 和世界向上向量 k(都在世界座標中)計算檢視矩陣 。步驟很簡單

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年

投影變換和透視除法

[編輯 | 編輯原始碼]

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

從技術上講,投影變換將檢視座標轉換為裁剪座標。(場景中可見部分外部的所有圖元部分都在裁剪座標中被裁剪掉。)它應該是頂點著色器中應用於頂點的最後一個變換,在頂點以 gl_Position 返回之前。然後,這些裁剪座標透過**透視除法**轉換為歸一化裝置座標,該除法只是將所有座標除以第四個座標。(歸一化裝置座標之所以如此命名,是因為它們的取值範圍在場景中可見部分的所有點的 -1 到 +1 之間。)

此步驟將物體頂點的 3D 位置轉換為螢幕上的 2D 位置。

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

[編輯 | 編輯原始碼]

與模型變換和檢視變換類似,投影變換由一個 4×4 矩陣表示,稱為投影矩陣 。它通常被定義為頂點著色器的uniform變數。(在某些版本的 OpenGL(ES)中,頂點著色器中可以使用內建 uniform 變數 gl_Projection;另請參見“應用矩陣變換”部分。)

計算投影矩陣

[編輯 | 編輯原始碼]

與模型檢視矩陣類似,GLSL 程式設計師不必擔心投影矩陣的計算。但是,在現代版本的 OpenGL 和 OpenGL ES 或 WebGL 中開發應用程式時,需要計算投影矩陣。在舊版本的 OpenGL 中,這通常使用函式 gluPerspectiveglFrustumglOrtho 來完成。

在這裡,我們針對三種情況展示投影矩陣

  • 標準透視投影(對應於 gluPerspective
  • 傾斜透視投影(對應於 glFrustum
  • 正交投影(對應於 glOrtho
角度 的說明,該角度指定了 y 方向的視場。
圖示了在 的近裁剪平面和遠裁剪平面。

標準透視投影 的特徵在於

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

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

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

  

斜透視投影的引數。

斜透視投影 的特徵在於

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

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

正交投影引數。

正交投影(沒有透視縮短)如圖右側所示。引數與斜透視投影的情況相同;但是,視錐體(更準確地說,視體積)現在是一個長方體,而不是一個截斷的稜錐。

在引數 , , , , , 以及 ,正投影的投影矩陣

視口變換的示意圖。

視口變換

[編輯 | 編輯原始碼]

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

glViewport(GLint , GLint , GLsizei , GLsizei );

glDepthRangef(GLclampf , GLclampf );

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

進一步閱讀

[編輯 | 編輯原始碼]

此處描述的傳統頂點變換在“OpenGL 4.1 Compatibility Profile Specification”的第 2.12 節中進行了詳細定義,該規範可在 Khronos OpenGL 網站 上獲得。

Dave Shreiner 編寫的“OpenGL Programming Guide”一書的第 3 章(關於檢視)中給出了對頂點變換更易於理解的描述,該書由 Addison-Wesley 出版。(較舊的版本可在 網上 獲得)。


< GLSL 程式設計

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