渲染管線中的頂點(diǎn)變換

概述

在圖形學(xué)渲染管線中,一個(gè)頂點(diǎn)坐標(biāo),大概要經(jīng)歷局部坐標(biāo)系、世界坐標(biāo)系、相機(jī)坐標(biāo)系、裁剪坐標(biāo)系,最后到窗口坐標(biāo)系,顯示在屏幕上。

坐標(biāo)空間變換示意圖

在這些過程中,從一個(gè)坐標(biāo)系到另一個(gè)坐標(biāo)系,都需要進(jìn)行一定的變換。下面,將介紹每次變換的方式。

注意,本文是針對(duì)OpenGL的。

局部空間->世界空間

這一變換過程,主要是將模型放置在世界空間中,進(jìn)行一定的縮放、旋轉(zhuǎn)或平移。這一步比較簡(jiǎn)單,只要將相應(yīng)的矩陣作用到模型的局部空間坐標(biāo)即可。

比如,對(duì)模型縮放\left(S_{x},S_{y},S_{z} \right),然后繞Z軸旋轉(zhuǎn)\theta度,再進(jìn)行\left(T_{x},T_{y},T_{z} \right)的平移。注意,這里的變換順序是不能變的,即要先進(jìn)行縮放,再進(jìn)行旋轉(zhuǎn),最后進(jìn)行平移。據(jù)此,我們可以構(gòu)建模型變換矩陣。
M_{model}= \begin{bmatrix} 1 & 0 & 0 & T_{x} \\ 0 & 1 & 0 & T_{y} \\ 0 & 0 & 1 & T_{z} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} \cos{\theta} & -\sin{\theta} & 0 & 0 \\ \sin{\theta} & \cos{\theta} & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} S_{x} & 0 & 0 & 0 \\ 0 & S_{y} & 0 & 0 \\ 0 & 0 & S_{z} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

世界空間->相機(jī)空間

首先定義一下相機(jī):

  • 坐標(biāo)為\vec{e}

  • 觀察方向\vec{g}

  • 向上方向\vec{t}

示意圖如下所示:

相機(jī)坐標(biāo)系示意圖

有一個(gè)性質(zhì)注意一下:當(dāng)相機(jī)和相機(jī)“看“到的物體一起變換時(shí),相機(jī)”看“到的內(nèi)容是不變的。這樣,可以將相機(jī)的坐標(biāo)移動(dòng)到世界坐標(biāo)的原點(diǎn),向上方向?qū)R世界坐標(biāo)的Y軸,觀察方向?qū)R世界坐標(biāo)的-Z軸。然后,對(duì)物體進(jìn)行相同的變換即可。

在數(shù)學(xué)上,這個(gè)過程大概這樣:

  • 將相機(jī)移動(dòng)到坐標(biāo)原點(diǎn)
  • 旋轉(zhuǎn)觀察方向\vec{g}到-Z軸
  • 旋轉(zhuǎn)向上方向\vec{t}到Y(jié)軸
  • 旋轉(zhuǎn)(\vec{g} \times \vec{t})到X軸

大體分為兩步:先位移,后旋轉(zhuǎn)。即M_{view} = R_{view}T_{view}。

平移部分:
T_{view} = \begin{bmatrix} 1 & 0 & 0 & -x_{e} \\ 0 & 1 & 0 & -y_{e} \\ 0 & 0 & 1 & -z_{e} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
對(duì)于旋轉(zhuǎn)部分,先補(bǔ)充一些知識(shí)點(diǎn)。對(duì)于二維空間來說:
R_{\theta} = \begin{pmatrix} \cos{\theta} & -\sin{\theta} \\ \sin{\theta} & \cos{\theta} \\ \end{pmatrix}

R_{-\theta} = \begin{pmatrix} \cos{\theta} & \sin{\theta} \\ -\sin{\theta} & \cos{\theta} \\ \end{pmatrix} = R_{\theta}^\mathrm{T}

根據(jù)定義,旋轉(zhuǎn)\theta角度和旋轉(zhuǎn)-\theta角度是互逆的,即:R_{-\theta} = R_{\theta}^{-1}

所以,對(duì)于旋轉(zhuǎn)變換,可以得出旋轉(zhuǎn)矩陣的逆等于它的轉(zhuǎn)置,即:
R_{\theta}^\mathrm{T} = R_{\theta}^{-1}
回到上面的旋轉(zhuǎn)部分,直接求相機(jī)的坐標(biāo)軸旋轉(zhuǎn)到世界坐標(biāo)軸的矩陣不是很方便,但是反過來,求世界坐標(biāo)軸旋轉(zhuǎn)到相機(jī)的坐標(biāo)軸很容易:
R_{view}^{-1} = \begin{bmatrix} x_{\vec{g} \times \vec{t}} & x_{\vec{t}} & x_{-\vec{g}} & 0 \\ y_{\vec{g} \times \vec{t}} & y_{\vec{t}} & y_{-\vec{g}} & 0 \\ z_{\vec{g} \times \vec{t}} & z_{\vec{t}} & z_{-\vec{g}} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
根據(jù)旋轉(zhuǎn)矩陣的逆等于它的轉(zhuǎn)置,得出:
R_{view} = (R_{view}^{-1})^\mathrm{T} = \begin{bmatrix} x_{\vec{g} \times \vec{t}} & y_{\vec{g} \times \vec{t}} & z_{\vec{g} \times \vec{t}} & 0 \\ x_{\vec{t}} & y_{\vec{t}} & z_{\vec{t}} & 0 \\ x_{-\vec{g}} & y_{-\vec{g}} & z_{-\vec{g}} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
根據(jù)M_{view} = R_{view}T_{view},可以得出:
M_{view} = R_{view}T_{view} = \begin{bmatrix} x_{\vec{g} \times \vec{t}} & y_{\vec{g} \times \vec{t}} & z_{\vec{g} \times \vec{t}} & 0 \\ x_{\vec{t}} & y_{\vec{t}} & z_{\vec{t}} & 0 \\ x_{-\vec{g}} & y_{-\vec{g}} & z_{-\vec{g}} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -x_{e} \\ 0 & 1 & 0 & -y_{e} \\ 0 & 0 & 1 & -z_{e} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

相機(jī)空間->裁剪空間

在一個(gè)頂點(diǎn)著色器運(yùn)行的最后,期望所有的坐標(biāo)都能落在一個(gè)特定的范圍內(nèi),且任何在這個(gè)范圍之外的點(diǎn)都應(yīng)該被裁剪掉(Clipped)。被裁剪掉的坐標(biāo)就會(huì)被忽略,所以剩下的坐標(biāo)就將變?yōu)槠聊簧峡梢姷钠巍_@也就是裁剪空間(Clip Space)名字的由來。

因?yàn)閷⑺锌梢姷淖鴺?biāo)都指定在-1.0到1.0的范圍內(nèi)不是很直觀,所以我們會(huì)指定自己的坐標(biāo)集(Coordinate Set)并將它變換回標(biāo)準(zhǔn)化設(shè)備坐標(biāo)系。

由投影矩陣創(chuàng)建的觀察箱(Viewing Box)被稱為平截頭體(Frustum),每個(gè)出現(xiàn)在平截頭體范圍內(nèi)的坐標(biāo)都會(huì)最終出現(xiàn)在用戶的屏幕上。將特定范圍內(nèi)的坐標(biāo)轉(zhuǎn)化到標(biāo)準(zhǔn)化設(shè)備坐標(biāo)系的過程(而且它很容易被映射到2D觀察空間坐標(biāo))被稱之為投影(Projection),因?yàn)槭褂猛队熬仃嚹軐?D坐標(biāo)投影(Project)到很容易映射到2D的標(biāo)準(zhǔn)化設(shè)備坐標(biāo)系中。

這里要注意一下,OpenGL是右手坐標(biāo)系的,但是在NDC中,是左手坐標(biāo)系的,這里要特別注意?。?!

相機(jī)空間轉(zhuǎn)換到裁剪空間,有需要用到投影變換。有兩種投影變換:正交投影和透視投影。下面分別介紹一下。

正交投影

我們先定義一個(gè)正交投影的視錐體[l,r] \times [b,t] \times [f,n](注意,n和f都是負(fù)數(shù),f是遠(yuǎn)平面,所以f<n),它是一個(gè)長(zhǎng)方體。我們需要做的,就是將正交投影的視錐體轉(zhuǎn)換到標(biāo)準(zhǔn)立方體(即標(biāo)準(zhǔn)化設(shè)備坐標(biāo),[-1,1]^{3})。注意,這里[f,n]映射到NDC中的[1,-1]。

image

這里,分成兩個(gè)步驟:平移和縮放。正交投影的矩陣如下:
M_{ortho} = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & 0 \\ 0 & \frac{2}{t-b} & 0 & 0 \\ 0 & 0 & \frac{2}{f-n} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -\frac{r+l}{2} \\ 0 & 1 & 0 & -\frac{t+b}{2} \\ 0 & 0 & 1 & -\frac{n+f}{2} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}= \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & \frac{2}{f-n} & -\frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

透視投影

對(duì)于透視投影,分成兩步操作:

  • 首先,“壓扁”視錐體成一個(gè)長(zhǎng)方體(n->n,f->f)(M_{persp->ortho});
  • 然后,做正交投影操作(M_{ortho},即上面的正交投影)。
透視投影和正交投影的視錐體示意圖

觀察下圖:

從X軸觀察

根據(jù)相似三角形的關(guān)系,可以得出:
y^{'} = \frac{n}{z}y
類似的,可以得出:
x^{'} = \frac{n}{z}x
由此,可以得出下面的關(guān)系:
M_{persp->ortho}^{(4 \times 4)} \begin{pmatrix} x\\ y\\ z\\ 1\\ \end{pmatrix}= \begin{pmatrix} \frac{n}{z}x \\ \frac{n}{z}y \\ unknown \\ 1 \\ \end{pmatrix}

下面,說一個(gè)齊次坐標(biāo)的性質(zhì):在3D坐標(biāo)系統(tǒng)中,\left ( x,y,z,1 \right ),\left ( kx,ky,kz,k \neq 0 \right ),\left ( xz,yz,z^{2},z \neq 0 \right )都表示相同的坐標(biāo)---\left ( x,y,z \right )。例如:\left ( 1,0,0,1 \right )\left ( 2,0,0,2 \right )都表示坐標(biāo)\left ( 1,0,0 \right )

所以,有如下關(guān)系:
M_{persp->ortho}^{(4 \times 4)} \begin{pmatrix} x\\ y\\ z\\ 1\\ \end{pmatrix}= \begin{pmatrix} \frac{n}{z}x \\ \frac{n}{z}y \\ unknown \\ 1 \\ \end{pmatrix} = \begin{pmatrix} nx \\ ny \\ unknown \\ z \\ \end{pmatrix}
更進(jìn)一步的,可以得到:
M_{persp->ortho} = \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \\ \end{pmatrix}
現(xiàn)在,還剩下第三列是未知的。

經(jīng)過觀察上面的透視投影視錐體,可以得出以下推論:

  1. 近平面上的點(diǎn)的坐標(biāo)都不會(huì)改變;

  2. 遠(yuǎn)平面上的點(diǎn),Z坐標(biāo)不改變。

根據(jù)推論1,近平面上的點(diǎn)\left (x,y,n,1 \right )經(jīng)過變換后,不會(huì)改變。即:
M_{persp->ortho} \begin{pmatrix} x \\ y \\ n \\ 1 \\ \end{pmatrix} = \begin{pmatrix} x \\ y \\ n \\ 1 \\ \end{pmatrix} = \begin{pmatrix} nx \\ ny \\ n^{2} \\ n \\ \end{pmatrix}
根據(jù):
M_{persp->ortho} \begin{pmatrix} x\\ y\\ z\\ 1\\ \end{pmatrix}= \begin{pmatrix} nx \\ ny \\ unknown \\ z \\ \end{pmatrix}
因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=n%5E%7B2%7D" alt="n^{2}" mathimg="1">與x和y都沒有關(guān)系,所以可以得出M_{persp->ortho}的第三列的形式是\left (0,0,A,B \right )。

根據(jù):
\left(0,0,A,B \right) \begin{pmatrix} x \\ y \\ n \\ 1 \\ \end{pmatrix} = n^{2}
可以得出:
An+B = n^{2}
根據(jù)推論2,遠(yuǎn)平面的中心點(diǎn)\left (0,0,f,1 \right),經(jīng)過變換后,還是本身。如下:
M_{persp->ortho} \begin{pmatrix} 0 \\ 0 \\ f \\ 1 \\ \end{pmatrix} = \begin{pmatrix} 0 \\ 0 \\ f \\ 1 \\ \end{pmatrix} = \begin{pmatrix} 0 \\ 0 \\ f^{2} \\ f \\ \end{pmatrix}
所以,可以得出:
\left(0,0,A,B \right) \begin{pmatrix} 0 \\ 0 \\ f \\ 1 \\ \end{pmatrix} = f^{2}

即:
Af + B = f^{2}
到這里,可以得出方程組:
\begin{cases} An + B = n^{2} \\ Af + B = f^{2} \\ \end{cases} \Rightarrow \begin{matrix} A = n + f \\ B = -nf \\ \end{matrix}
到這里,可以得出M_{persp->ortho}:
M_{persp->ortho} = \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \\ \end{bmatrix}
最終,透視投影矩陣:
M_{persp} = M_{ortho}M_{persp->ortho} = \begin{bmatrix} \frac{2n}{r-l} & 0 & \frac{l+r}{l-r} & 0 \\ 0 & \frac{2n}{t-b} & \frac{b+t}{b-t} & 0 \\ 0 & 0 & \frac{f+n}{f-n} & \frac{2nf}{n-f} \\ 0 & 0 & 1 & 0 \\ \end{bmatrix}

裁剪空間->窗口空間

在裁剪空間的最后,所以的可見的點(diǎn)都在標(biāo)準(zhǔn)設(shè)備坐標(biāo)系(NDC)中,即坐標(biāo)坐落在范圍[-1,1]^{3}內(nèi)。

先不考慮Z軸的變換。

從NDC到窗口空間,需要經(jīng)過視口變換。定義一個(gè)屏幕空間:\left (0,0,w,h \right)。平面左下角的坐標(biāo)位\left (0,0 \right),右上角的坐標(biāo)為\left (w,h \right)。對(duì)于X和Y坐標(biāo)的變換,即從\left(-1,1\right) \times \left(-1,1\right)\left(0,w\right) \times \left(0,h\right)

這里,經(jīng)過兩步變換:

  1. 將NDC的中心平移到窗口的中心;
    T_{viewport} = \begin{pmatrix} 1 & 0 & 0 & \frac{w}{2} \\ 0 & 1 & 0 & \frac{h}{2} \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{pmatrix}

  2. 將NDC的大小縮放到屏幕的大小。

R_{viewport} = \begin{pmatrix} \frac{w}{2} & 0 & 0 & 0 \\ 0 & \frac{h}{2} & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{pmatrix}

合并到一起:
M_{viewport} = R_{viewport}T_{viewport} = \begin{pmatrix} \frac{w}{2} & 0 & 0 & \frac{w}{2} \\ 0 & \frac{h}{2} & 0 & \frac{h}{2} \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{pmatrix}
對(duì)于Z坐標(biāo),從\left(-1,1\right)映射到了\left(0,1\right)。這里只是簡(jiǎn)單的線性映射。假設(shè)z^{'} = Az+B,當(dāng)z等于-1時(shí),z^{'}等于0;當(dāng)z等于1時(shí),z^{'}等于1??傻萌缦路匠探M:
\begin{cases} A(-1) + B = 0 \\ A(1) + B = 1 \\ \end{cases} \Rightarrow \begin{cases} A = \frac{1}{2} \\ B = \frac{1}{2} \\ \end{cases}
所以,z^{'} = \frac{1}{2}z + \frac{1}{2}。代入上述M_{viewport}矩陣,可得:
M_{viewport} = \begin{pmatrix} \frac{w}{2} & 0 & 0 & \frac{w}{2} \\ 0 & \frac{h}{2} & 0 & \frac{h}{2} \\ 0 & 0 & \frac{1}{2} & \frac{1}{2} \\ 0 & 0 & 0 & 1 \\ \end{pmatrix}

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容