最近幾天看了《GPU編程與CG語言之陽春白雪下里巴人》這本書,書的內(nèi)容和之前看的《Unity Shader入門精要》很相似,但是側(cè)重點(diǎn)有所不同。因此,下面的三篇文章是在閱讀《GPU》之后,結(jié)合之前一本書的內(nèi)容,做一些更深入的理解或邏輯的理順。
這一篇文章是對渲染流水線的知識做一下進(jìn)一步理解。老生常談地,渲染流水線分為應(yīng)用階段、幾何階段、光柵化階段。
應(yīng)用階段
主要使用高級語言,在應(yīng)用層面準(zhǔn)備數(shù)據(jù)。本書中舉例如碰撞檢測、場景圖建立、空間八叉樹更新、視錐裁剪等。
我理解的是:我們在Unity的shader文件中聲明了變量(例如vertex、normal等),應(yīng)用階段是在這些變量被傳到shader之前做的事情。
幾何階段
包括頂點(diǎn)坐標(biāo)變換、光照、裁剪、投影、屏幕映射等操作。
頂點(diǎn)坐標(biāo)變換
頂點(diǎn)坐標(biāo)變換就是《Unity》一書第四章中的幾個坐標(biāo)系之間的轉(zhuǎn)換。其余的幾個步驟其實包含在頂點(diǎn)坐標(biāo)變換的過程中。
模型空間
需要注意的是從模型空間轉(zhuǎn)變到世界空間下,不只頂點(diǎn)坐標(biāo)要變換,法線也要跟著變化,法線的變換矩陣是頂點(diǎn)變換矩陣的逆轉(zhuǎn)置矩陣。推導(dǎo)過程詳見《Unity》一書第四章4.7節(jié)。世界空間
相機(jī)空間
相機(jī)空間到裁剪空間的映射過程通常稱為投影,可分為透視投影和正交投影。投影/裁剪空間
在裁剪空間做裁剪,把視錐之外的頂點(diǎn)剔除。
這一個步驟將模型作為一個整體,對頂點(diǎn)進(jìn)行剔除。如果一個模型對所有頂點(diǎn)都在視錐里,則保留;如果頂點(diǎn)全不在視錐里,則剔除;如果一部分在一部分不在則依具體算法計算。這一步不涉及到對具體三角形片元的裁剪。NDC空間
屏幕空間
圖元裝配
上述變換都是對頂點(diǎn)的操作,在這一步驟中,我們根據(jù)頂點(diǎn)坐標(biāo)和索引構(gòu)建出三角形網(wǎng)格。
三角形剔除
不在視錐內(nèi)的三角形剔除。三角形裁剪
對有一部分在視錐內(nèi)的三角形裁剪,先裁剪成四邊形,再拆成兩個三角形。背面剔除
使用右手定則確定法線方向,法線方向和視線方向的點(diǎn)積為正,說明該三角形正面朝向相機(jī),否則該三角形背對相機(jī),會被剔除。但是可以設(shè)置是否進(jìn)行背面剔除,如《Unity》一書使用透明度檢測實現(xiàn)透明效果時,就關(guān)閉了背面剔除。
這一階段結(jié)束后,我們得到了一些三角形面片用于下一步的光柵化。
光柵化階段
像素位置計算
將頂點(diǎn)的屏幕坐標(biāo)轉(zhuǎn)換為像素位置,并使用一定的算法計算出每一條線(三角形設(shè)置)和面(三角形遍歷)占用的像素位置。
像素顏色計算
- 深度/模版檢測
- 紋理
- 混合(Blending)
深度緩沖(Z-buffer)
Z-buffer中儲存的z值并不是歐氏距離,而是一個相對的值。我們只儲存了頂點(diǎn)的z值,內(nèi)部像素點(diǎn)的z值需要通過插值獲得,而得到的z值并不能反應(yīng)真實的空間點(diǎn)的深度關(guān)系,有可能獲得錯誤的結(jié)果。
如下圖所示,A、E是頂點(diǎn),B、C、D為真實的深度,而B'、C'、D'為插值計算出來的深度。

Tips:
坐標(biāo)變換時旋轉(zhuǎn)、縮放、平移的順序:
--縮放變換不改變坐標(biāo)軸的走向,也不改變原點(diǎn)的位置,所以兩個坐標(biāo)系仍然重合。
--旋轉(zhuǎn)變換改變坐標(biāo)軸的走向,但不改變原點(diǎn)的位置,所以兩個坐標(biāo)系坐標(biāo)軸不再處于相同走向。
--平移變換不改變坐標(biāo)軸走向,但改變原點(diǎn)位置,兩個坐標(biāo)系原點(diǎn)不再重合。
因此,變換順序只能是 縮放 -> 旋轉(zhuǎn) -> 平移 。
