unity shader 入門精要閱讀筆記-----渲染流水線


1渲染流水線

這一部分的重點就是渲染流水線,理解渲染流水線對於後面的學習來說至關重要,這也是圖形學的一個重要的基礎知識環節。

我們探討空間中的模型是怎樣一步一步轉換到我們的屏幕座標,然後顯示在我們的面前的。
我們把步驟分成四個步驟,頂點處理階段–光柵化階段–片元處理階段–輸出合併階段

1.1頂點處理階段

這一階段的任務就是把我們的頂點座標從模型空間轉換到裁剪空間。

1.1.1 矩陣變換

雖然大學我們都學過線性代數,但是學的時候只是單純的應試教育,很大程度上沒有理解其幾何意義,因此,這裏有必要重新去理解一遍。

平移、旋轉、縮放

旋轉和縮放變換被稱爲線性變換,平移變換和線性變換被稱爲仿射變換,對於一個三維空間中的點來說,線性變換可以用一個三維的矩陣來表示,但是平移變換是加法運算,無法通過右乘一個三維矩陣來實現,只能把三維點座標拓展成四維座標,然後右乘就可以實現平移變換,
在這裏插入圖片描述
如圖所示,三維點座標只需要把第四個座標值變成1就可以實現平移變換,如果第四個值爲0的話,最後的結果還是原來的點座標,這種情況正好適用於方向向量,因爲方向是沒有位置的概念的。

座標系變換 (很重要)

通過矩陣來把點從當前座標系轉換到另外一個座標系比想象中還是要簡單一點的。
如果我們知道座標系C的xyz軸在P中的表示以及知道C的原點座標以及C中某一點的座標,在我們的腦海中簡單的想象一下,便可以自然的得到其在P中的座標
在這裏插入圖片描述這個寫成矩陣的形式就是
在這裏插入圖片描述
沒錯,這就是我們座標轉換的矩陣,往往當我們只需要對方向向量進行變換的時候,就可以進行完全的線性變換,直接忽略掉最後一行,把三個座標系的表示分別按列形成矩陣就可以得到變換矩陣了。

在後面shader的編寫中,我們可以通過調用系統的unity_ObjectToWorld矩陣直接將頂點從模型空間變換到世界空間,這個變換大部分的shader都會用得到。

值得一提的是,如果進行了非均勻的縮放變換,也就是xyz三個座標軸變換的比例不同,我們得到的變換矩陣不能直接用來變換法線。需要用其逆轉置矩陣來進行變換,我們知道其原變換矩陣是unity_ObjectToWorld,其逆矩陣是unity_WorldToObject,我們再將其轉置一下,我們這裏只需要調換一下其在mul函數中的順序即可,大家可能會想到直接轉置不就不滿足矩陣乘法的公式了,沒法運算的呀,實際上,使用矩陣數學來進行矩陣x左乘矩陣y的運算,要求矩陣x的列數與矩陣y的行數相等。如果x是一個向量,那麼它將被解釋爲行向量。如果y是一個向量,那麼它將被解釋爲列向量。
因此後面我們會看到這樣變換法線
fixed3 worldNormal = normalize(mul(v.normal),(float3x3)unity_WorldToObject);

1.1.2從模型空間變換到世界空間

我們學會了上面的座標變換方法了,但是這裏卻不能直接那樣做,因爲我們不能直接獲得模型空間三個座標軸在世界空間中的表示,這裏可以換一種思路去做,直接通過仿射變換,移動模型空間的座標系和世界空間重合,得到的這個變換矩陣就是世界矩陣。

1.1.3從世界空間到觀察空間

實際上,這一步的變換和上面一步的原理是一模一樣的,但是最後因爲觀察空間是右手座標系,和前面的左手座標系不同,這裏需要把最後結果的z分量取反。
unity內置的觀察變換矩陣是unity_MatrixV

1.1.4從觀察空間到裁剪空間

同上面的變化相比,這一部分要算是非常複雜的,具體的推導細節可以參考3D Graphics for Game Programming這本書。下面簡單的貼一下書裏面關於投影矩陣的推導以及一些我自己的理解與困惑。
在這裏插入圖片描述如上圖所示,這個變化的實質就是把物體從視椎體變換到一個立方體中,立方體的範圍爲:x和y的範圍都是-1到1,z的範圍在opengl中也是-1到1,在Direct3D中的範圍是0到1,這種差異會直接導致推導的結果不一樣,不過過程差別也不大。
在推導的時候我們需要以下幾個參數:
1.FovY 表示Y軸方向的視野區域的角度
2.z=-n z=-f 表示近裁剪面和遠裁剪面
3.aspect 表示視截體底面寬度和高度的比值
在這裏插入圖片描述投影過程如上圖所示,發射若干條指向攝像機的射線,這些射線在最後的投影平面內都是平行的,他們構成投影平面內的場景圖像,因此,也很好理解,爲什麼越遠的地方會變得越小了,圖中的兩條線段儘管長度不相同,但是投影到了右圖中就變成一樣長了。
在這裏插入圖片描述橫截面如上圖所示,我們定義投影平面爲z=-cot(fovY/2),這樣可以保證在投影后y’的範圍在(-1,1),然後由相似三角形可以得到y’的表達式。
在這裏插入圖片描述同理,把y替換成x就可以得到x’的表達式
在這裏插入圖片描述但是我們不能直接得到fovx的值,需要通過aspect來推導出來
在這裏插入圖片描述由上圖我們能得到
在這裏插入圖片描述因此我們可以把座標映射表示成如下:
在這裏插入圖片描述D爲cot(fovY/2),A爲aspect
因爲其爲齊次座標,我們直接把所有的項乘上一個-z,就可以得到下面的公式,這樣做是爲了方便寫成矩陣變換的形式
在這裏插入圖片描述在這裏插入圖片描述
至此,矩陣中只有m1,m2,m3,m4是未知的,其他的我們都已經推導出來了,m1,m2,m3,m4有以下關係,
m1* x+m2* y+m3* z+m4 = -zz’
我們可以想象,任何一個平行於投影平面的平面,其z值都是一樣的,也就是投影后的z’值與x和y沒有關係,這樣的話,m1和m2的值理所當然也就是0了。
我們先拿D3D的座標來舉例子,z’的範圍是[-1,0],對於遠裁剪面-f其值是-1,近裁剪面-n其值是0,然後代入兩點,就可以解出來m3和m4的值
這樣我們就能得到最終的投影矩陣
這裏的第三行的所有分量都已經取反了,因爲在後面的光柵化階段,裁剪空間是左手座標系,而從觀察空間傳遞來的座標是基於右手座標系的,因此這裏還需要進行取反操作。
在這裏插入圖片描述
對於opengl來說也只是最後代入的兩點座標的不同而已,計算方法也是很類似的。

1.2 光柵化階段

1.2.1 裁剪操作

這個步驟是硬件中實現的,用戶無法改變,其目的就是把在裁剪空間外面的三角形全部剔除,部分在裁剪空間內的三角形進行裁剪。

1.2.2 透視除法

上面我們得到的投影矩陣乘過一個-z,這樣就會導致xyz會超出其應該的範圍,我們這裏還需要把xyz全部除以w的值,得到歸一化的設備座標(NDC)

1.2.3 背面剔除操作

把所有背向於攝像機的三角形全部剔除掉,可以理解爲把被遮擋住的三角形全部剔除掉。unity會默認剔除掉背面,我們也可以通過Cull Off來關閉背面剔除的效果,使得物體能渲染兩個面。

1.2.4 視口變換

這個變換就是把歸一化的設備座標映射到具體的屏幕座標上面
下圖是加上了齊次除法的視口變換的公式,理解起來也很容易,unity裏面使用的是opengl的裁剪空間,也就是z的範圍是-1到1,這樣的話,我們首先需要把-1到1映射到0~1,然後再乘上屏幕分辨率即可,也就是(clipx/clipw+1)/2* pixelWidth,就是下圖裏面的公式。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章