渲染流水線[Render_Pipeline]
渲染管線(RenderPipeline)
渲染管線可以理解為處理資料的各個階段,實時3D渲染流水線【基於光柵器插值】主流的實時3D渲染流水線分為:Direct 3D 和 OpenGL
應用階段
——當把資料載入到VRAM時,RAM的資料可以移除,但對於一些資料,CPU仍然需要訪問它們【CPU訪問網格資料進行碰撞檢測】
幾何階段
光柵化階段
渲染流水線基本階段和流程
幾何階段[頂點處理]
——頂點處理器是一個硬體單元,可以執行Cg頂點程式,片段處理器可以執行Cg片段程式
1.幾何階段之頂點著色器
________插一嘴________
--列舉
順序讀取3個頂點構成三角形
--索引
記錄三角形的方式:直接記錄頂點本身
記錄頂點索引
--座標系和頂點法線
座標系:環繞順序:x-y-z-w
三角面法線
確定座標系,當把頂點資料從左(右)手匯入右(左)手系時,會產生內外表面相反
解決方案:需要重新調整頂點在緩衝區中的排列順序
頂點法線
DCC在編輯模型時可以直接指定頂點法線,理論上一個頂點的法線可以是過該點的任意一條射線
__________插完嘴_________
在頂點從在模型空間變換裁剪空間 ,到最終把圖元畫到螢幕上 。這期間還會涉及到幾個空間變換
首先
DCC
中建模頂點都是依據自身座標系建模,每個模型都是獨立的,跟其他模型的沒有關係,當模型放到Unity,在頂點著色器就 可以訪問到
世界空間為我們所關心的最大的空間,現在需要把頂點從模型空間變換世界空間,讓物體間產生聯絡。變換矩陣為
定義一個三維旋轉操作,需要定義對應的旋轉軸
--均勻縮放
--非均勻縮放
當模型非均勻縮放,法線不再垂直於模型表面,
可透過乘以
的逆轉置矩陣
,求得正確的法線
Unity中,頂點使用左手系,從DCC匯出頂點資料時,都要將其轉換到左手系
頂點緩衝區中,頂點座標定義為
分量為
的齊次座標
unity_ObjectToWorld內建變數
可以在
內定義
,當給定
的狀態後,則觀察空間也得以確立,且世界空間中的頂點也隨之變換到觀察空間
向量組
,在
中,攝像機位於
原點處且指向
即攝像機的觀察方向,也稱朝前方向為
構造觀察空間的方法
觀察矩陣
一種思路
觀察變換用到的
操作分解為
是在給定觀察座標系的前提下,保持觀察座標系不動;計算出模型的頂點相對於觀察座標系3個座標軸平移了多少,旋轉了多少;最終複合成觀察矩陣
,但計算旋轉度就會麻煩
換一個思路
讓模型和座標系“錨定”,透過【平移】【旋轉】觀察座標系,使之最終與世界座標系重合。當觀察座標系【平移】【旋轉】時,與之“錨定”的模型頂點也隨之【平移】【旋轉】
最終世界空間與觀察空間重合時,模型頂點變換後得到的世界座標值,實質上就是它在觀察座標系下的值
一個例子
把
移到原點
的矩陣
以
為原點,
到
的距離為
觀察空間為右手系 所以
座標為
那按點
的方式重新定義的點
要在保持觀察座標系的向量組
相互垂直的前提下,旋轉它們並使其朝向和向量組完全重合
也就是說,要構造一個矩陣,使得向量組
列向量右乘矩陣
時,分別等於
的方向向量值
另外2軸可以透過代入
和
,可得出矩陣
Unity 3D中世界座標系和觀察座標系分別是左手系和右手系,這兩種座標系的
軸和
軸是重合的,
軸則相反
--最終矩陣為
Unity3D中的觀察空間座標系
透過使用unity_MatrixV內建變數,可以把頂點從基於左手座標系的世界空間變換到基於右手座標的觀察空間
這塊空間取決於視截體(view frustum),它是空間中的一塊區域,決定了相機可以看到的空間,視錐體是由六個平面包圍而成的【由 Camera元件中的引數和Game檢視的橫縱比共同決定】
投影矩陣有兩個目的
首先:是為投影做準備,雖然
的名稱包含了投影二字,但並沒有進行真正的投影工作,而是在為投影做準備 。真正的投影發生在後面的齊次除法過程中, 而經過
的變換後,頂點的
分量將會具有特殊的意義
其次:是對
分量進行縮放。如果直接使用視錐體的6個裁剪平面來進行裁剪會比較麻煩, 而經過投影矩陣的縮放後,我們可以直接使用
分量作為一個範圍值 ,如果
分量都位於這個範圍內,就說明該頂點位於裁剪空間內
視截體剔除操作:
頂點資料投遞給渲染流水線之前,把這些無貢獻的模型頂點丟棄,則會大幅地提升效能
操作:在執行之前的預處理階段,計算網格的包圍體,隨後CPU執行多邊形網格的包圍體與視截體的相交測試
如果多邊形網格的包圍體完全在視截體之外——丟棄;其餘的丟進渲染流水線
但
並不是完全在視截體內,有一部分與遠截面相交。因此
應根據視截體的邊介面進行裁剪處理,僅顯示視截體之內的那一部分
裁剪操作並不是在
中,而是在光柵化階段中的
中,由硬體完成。因此,在頂點處理階段,投影變換可視為最後一步操作
投影矩陣
及其推導過程
裁剪空間:
透過
可以將正稜臺狀的視截體
軸對齊的立方體
,
視截體轉換為一個軸對齊的立方體
透視投影變換並不生成二維影象,只使場景中的三維物體發生變形
視截體的橫切面,藍色線條為投影面
定義一個投影平面,
限定了
,
此平面的定義公式為
求
為垂直視野角度
求
D是座標系原點到投影平面的距離,即z′
從圖可知
未知,但可以根據
和
得到
根據齊次座標的性質,如果
,則
,現在把
的座標值乘以
,
帶入矩陣函式
在視截體中,任意一個平行於投影平面的平面,其上面的任意一個頂點投影到投影平面上,其z都是相等的,即待投影點的投影z和其x、y無關
由於投影后
代入式
裁剪空間【軸對齊立方體】是基於右手系 ,投影變換後
在光柵化階段,裁剪空間採用左手系,需要把右手系的裁剪空間
左手系
左手系的裁剪空間
軸的朝向與右手座標系相同,即
軸相反。因此
右乘倒轉
軸的
才能得到最終
分別是Unity3D在Direct3D平臺和OpenGL平臺上的投影矩陣值,根據式中投影后
的不同取值範圍,
的第三行在不同平臺上有不同的值
現在可以按如下不等式來判斷 個變換後的頂點是否,任何不滿足上述條件的圖元都需要被剔除或者裁剪
Direct3D平臺,
,OpenGL平臺,
當座標系從右手系
左手系
Direct3D平臺,
,OpenGL平臺,
Direct3D平臺上
中的
中的
,所得到未除以
分量的齊次座標值
分量的取值範圍是
OpenGL平臺上
中的
,得到未除以
分量的齊次座標值
——
透視除法
的第4行是
一個
分量為
齊次座標
一個例子
設
矩陣函式
經過投影變換後,在兩個空間中對應的頂點,其
沒有變化,原來等長的
和
還是等長但是
有變化,但變換後的
超出了
。為了把該齊次座標變成笛卡兒座標,需要把他們各自除以它們的
分量
這時
發生了變化,產生了“近大遠小”,並且
也限定在了
範圍內
把
分量不為
的裁剪空間座標值除以
,使得
分量等於
,四維齊次座標降維成三維笛卡兒座標的操作
Direct3D平臺
經過透視除法,裁剪空間中齊次座標值
分量的取值範圍,從原來在
OpenGL平臺上
把裁剪空間中齊次座標值
分量的取值範圍,從原來的
範圍內。兩種平臺下裁剪空間中齊次座標值
則限制在
內
Unity的裁剪空間座標系
在各平臺下Unity3D的裁剪空間使用左手座標系,並且在未經透視除法之前
由於
不是仿射變換,因此
的
分量不為1
呼叫UnityViewToClipPos函式,可以把頂點從
變換到
,程式碼如下:
背面剔除操作
觀察空間中做背面剔除操作的原理,判斷一個三角形
是正面還是背面,可以透過計算三角形法線向量
與
位置到當前三角形
連線
之間的點積
大部分渲染流水線中,背面剔除操作並不是在觀察空間中完成的
該演算法裡,要判斷每一個三角形的正面背面,必須計算出
到該三角形法線的連線
。每次渲染有成千上萬個三角形,這個計算操作是非常耗時,因此,最佳化手段是不計算這些連線向量
而是想辦法把連線
常數化。透過
把頂點變換到裁剪空間之後,投影線便可以當做連線
使用
和
的頂點順序排列是一樣
視見立方體的z軸朝向和真正的裁剪空間的z軸朝向是相反的。因此,裁剪空間中的連線向量應該是[0 0 1]
的頂點順序排列是一樣,但是在觀察空間中的三角形
的頂點排列順序是逆時針順序,在裁剪空間中變成了順時針順序,兩者的正面和背面是剛好相反的
在裁剪空間中做背面剔除操作
左手法則
把
和連線
做點積
帶入數值可解
的值為
三角形
與連線
的夾角為鈍角。也就是說,三角形
的正面對著攝像機,對應的三角形
則背面對著攝像機。因此,三角形
應該被剔除
視為當前場景所投影的矩形區域。視口定義於當前螢幕空間中,並且不一定非得為全部螢幕,可以為當前程序視窗的部分割槽域
視口的寬高比等於視截體的寬高比
且兩者
軸同向,
軸相反,因此,從裁剪空間中變換到螢幕空間中首先需要進行逆置
軸操作
定義螢幕空間
原來在裁剪空間中
軸方向上大小範圍是
軸方向上大小範圍是
或
的頂點縮放到
解得
完成縮放操作後,再做一次平移操作,使座標系的原點從中間移到螢幕左上角
組成圖元的頂點即完全變換到二維螢幕上。接下來進行掃描轉換,把圖元插值成片段
光柵化
光柵化流程
光柵化階段有兩個最重要的目標 :計算每個圖元覆蓋了哪些畫素,以及為這些畫素計算它們的顏色
三角形設定
上一個階段輸出的都是
網格的頂點,即
網格每條邊的兩個端點。但如果要得到整個
網格對畫素的覆蓋情況。 就必須計算每條邊上 的畫素座標。為了能夠計算邊界畫素的座標資訊,就需要得到
形邊界的表示方式。這樣個計算三角網格表示資料的過程就叫做三角形設定
三角形遍歷
三角形遍歷階段將會檢查每個畫素是否被 一個
網格所覆蓋。如果被覆蓋的話,就會生成一個片元,而這樣一個找到哪些畫素被
網格覆蓋的過程就是
遍歷,這個階段也被稱為掃描變換
遍歷階段會根據上 個階段的計算結果來判斷一個
網格覆蓋了哪些畫素,並使用
網格 3個頂點的頂點資訊對整個覆蓋區域的畫素進行插值。
對這些資訊進行插值都是用硬體電路實現,當全部片元[並不是真正意義上的畫素 ,而是包含了很多狀態的集合]屬性都完成掃描轉換之後,即完成光柵化階段
片元處理
採用標準化紋理座標(u,v)訪問不同紋理並且獲取到不同的紋素
--紋理操作
--解決方案
如果紋理多邊形網格從Direct3D
OpenGL平臺,則各個頂點的紋理座標應從
調整為
Direct3D和OpenGL的紋理座標系的差異
紋理對映座標與紋素陣列索引
光柵化階段插值生成的片元紋理對映座標
當給定了片元的紋理對映座標後,對應的紋理陣列索引值將透過圖形API在執行期中自動計算得到
Direct3D 9平臺下
計算紋理陣列索引值
根據紋理對映座標
和紋理的高寬
輸出合併
渲染流水線會比較
輸出合併階段不可程式設計操作,主要解決每個片元的可見性問題。會提供一系列的【Alpha測試】【Alpha混合】【深度測試】等指令來對片元透明值和深度值進行比較整合操作
先繪製淺色三角形後繪製深色三角形的過程
先繪製深色三角形後繪製淺色三角形的過程
只要啟用了深度測試機制,圖元就可以以任意的先後順序繪製而最終仍能得到正確的結果
通道包含
位資料,則
通道也應包含8位資料。因此顏色值
位的
,通常在程式設計實踐中使用單位化的浮點數取值範圍
--一個例子
假定了渲染順序為先繪製淺色三角形後繪製深色三角形
理論上深度緩衝演算法與圖元的繪製順序無關,但實際上要繪製透明圖元時無法以任意順序進行渲染
--半透明物體應執行排序操作
Unity 3D ShaderLab中的Alpha混合指令及深度測試指令
和
可以是同一個運算子號,也可以不同;片元或畫素的顏色操作係數和透明值混合係數也可以是同一個係數,也可以不同
常用的Alpha混合運算子及混合係數
常用的顏色值透明值混合係數
在著色器程式碼中宣告Alpha混合所用到的顏色值透明值混合運算子和混合操作係數。
④深度測試指令
ShaderLab語言提供了控制是否寫入當前片元的深度值到深度緩衝區的控制函式,以及和當前深度緩衝區對應點的深度值相比滿足何種關係時才寫入的一系列判斷函式
Cg簡介
著色語言只是非實時渲染器PRMan(PhotoRealistic RenderMan)一部分
在著色樹和現實主義中渲染物體的表面外觀進行廣泛的控制需要可程式語言
Cg編譯器和執行庫(Runtime)
——GPU不能夠從文字方式直接執行Cg程式,那麼就要把Cg翻譯成GPU可以執行的形式
Cg嵌入到一個Cg應用程式中
CgFX工具箱和檔案格式
提供一種方法把渲染一個三維資訊和Cg程式捆綁在一起