概念化的流水線流程圖如下:
應(yīng)用階段 Application Stage
由CPU負(fù)責(zé)執(zhí)行镣丑,開發(fā)者可完全控制舔糖。
主要任務(wù)如下:
準(zhǔn)備場景數(shù)據(jù)
相機(jī),視錐體莺匠,模型金吗,光源等等。粗粒度剔除
剔除不可見物體趣竣。設(shè)置每個物體的渲染狀態(tài)
材質(zhì)摇庙,貼圖,Shader等遥缕。最終輸出下一階段所需要的幾何數(shù)據(jù)卫袒,即渲染圖元(rendering primitives)。點(diǎn)单匣,線夕凝,三角面等宝穗。
可分為三個步驟:
將數(shù)據(jù)加載到顯存中
CPU將數(shù)據(jù)從硬盤加載到內(nèi)存中,然后再將數(shù)據(jù)從內(nèi)存加載到顯存中码秉,之后無用的數(shù)據(jù)會從內(nèi)存中移除逮矛。
顯存速度比內(nèi)存更快,而且顯卡也沒有訪問內(nèi)存的權(quán)限泡徙。設(shè)置渲染狀態(tài)
調(diào)用DrawCall
CPU向GPU發(fā)起DrawCall命令橱鹏,通知其繪制哪一個物體膜蠢。然后GPU會直接從顯存中讀取對應(yīng)物體的數(shù)據(jù)進(jìn)行渲染操作堪藐。
幾何階段 Geometry Stage
由GPU負(fù)責(zé)執(zhí)行,用于處理所有要繪制的物體的幾何數(shù)據(jù)挑围。主要任務(wù)是將頂點(diǎn)坐標(biāo)變換到屏幕空間中礁竞,輸出屏幕空間中的二維頂點(diǎn)坐標(biāo),深度值杉辙,著色等相關(guān)信息模捂。
光柵化階段 Rasterizer Stage
由GPU負(fù)責(zé)執(zhí)行,使用幾何階段傳遞的數(shù)據(jù)來生成屏幕上的像素蜘矢,并渲染出最終的圖像狂男。主要任務(wù)是決定每個渲染圖元中的哪些像素應(yīng)該被繪制在屏幕上。對逐頂點(diǎn)數(shù)據(jù)(如紋理坐標(biāo)品腹,頂點(diǎn)顏色等)進(jìn)行插值岖食,然后進(jìn)行逐像素處理。
GPU流水線
幾何階段具體步驟:
頂點(diǎn)著色器 Vertex Shader
可編程舞吭。
- 逐頂點(diǎn)坐標(biāo)變換
將坐標(biāo)從模型空間轉(zhuǎn)換到齊次裁剪空間(投影空間)泡垃。然后經(jīng)過硬件透視除法后,得到歸一化設(shè)備坐標(biāo)(Normalized Device Coordinates羡鸥,NDC).
float4 pos = mul(UNITY_MATRIX_MVP, i.vertex);
齊次裁剪空間坐標(biāo)范圍:
X[-1,1], Y[-1,1]
Z[-1,1] OpenGL/Unity
Z[0,1] DirectX
- 逐頂點(diǎn)光照
- 準(zhǔn)備下一階段需要的數(shù)據(jù)
曲面細(xì)分著色器
可選著色器蔑穴,用于細(xì)分圖元。
幾何著色器
可選著色器惧浴,用于執(zhí)行逐圖元的著色操作存和,或用于生成更多的圖元。
裁剪 Culling
可配置衷旅。剔除不在相機(jī)視野內(nèi)的頂點(diǎn)捐腿,面片。
由于裁剪是在NDC下進(jìn)行的芜茵,所以比較容易叙量。
- 在單位立方體內(nèi)的圖元被保留
- 完全在單位立方體外的圖元被丟棄
- 部分在單位立方體內(nèi)的圖元被拆分
屏幕映射 Screen Mapping
不可控。把每個圖元的NDC坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)系中九串。
屏幕坐標(biāo)系是一個二維坐標(biāo)系绞佩,長寬與顯示器分辨率對應(yīng)寺鸥。
X[0, ScreenWidth]
Y[0, ScreenHeight]
Z 不變化,仍為NDC坐標(biāo)中的Z值
OpenGL中屏幕坐標(biāo)原點(diǎn)為左下角品山,DirectX中為左上角
光柵化階段步驟:
三角形設(shè)置 Triangle Setup
不可控胆建。計算每個三角面光柵化所需的信息,比如三角形邊界像素的坐標(biāo)信息肘交,從而得到三角形邊界的表示方式笆载。
三角形遍歷 Triangle Traversal
不可控。檢查每個像素是否被一個三角網(wǎng)格所覆蓋涯呻,如果被覆蓋就會生成一個片元(fragment)凉驻。這個階段也稱為掃描變換(Scan Conversion)。
三角形遍歷會使用上一個階段的計算結(jié)果來判斷一個三角形覆蓋了哪些像素复罐,并使用三角網(wǎng)格3個頂點(diǎn)的信息對整個覆蓋區(qū)域的像素進(jìn)行插值涝登。比如對深度,UV效诅,法線進(jìn)行插值胀滚。每個像素對應(yīng)的信息存儲在一個片元中,然后組成一個片元序列來表示當(dāng)前三角形光柵化所需要的信息乱投。
片元著色器
可編程咽笼。實(shí)現(xiàn)逐片元的著色操作。輸入為上一階段對頂點(diǎn)信息進(jìn)行插值得到的結(jié)果戚炫,輸出為顏色值剑刑。最重要的操作為紋理采樣,得到每個像素在紋理中對應(yīng)的顏色值嘹悼。
逐片元操作
可配置叛甫。主要任務(wù)有:
a. 使用模板測試,深度測試杨伙,決定每個片元的可見性
b. 如果通過測試其监,則混合顏色,否則丟棄
-
模板測試
通常用于限制渲染的區(qū)域限匣。例如渲染陰影抖苦,輪廓渲染等。
無論測試結(jié)果是否成功米死,都可以對模板緩沖區(qū)進(jìn)行操作锌历。
Ref referenceValue
ReadMask readMask
WriteMask writeMask
Comp comparisonFunction
Pass stencilOperation
Fail stencilOperation
ZFail stencilOperation
-
深度測試 DepthTest
當(dāng)模板測試成功后,才會進(jìn)入深度測試階段峦筒。
只有深度測試成功才可以寫入深度緩沖區(qū)究西,當(dāng)然也可以設(shè)置通過了深度測試,但不寫入深度值物喷。
ZWrite Off/On // 是否寫入深度值
ZTest LEqual // 深度比較操作
-
混合 Blend
當(dāng)深度測試成功后卤材,會進(jìn)入顏色混合階段遮斥。通過設(shè)置混合模式(即混合公式)將片元顏色與顏色緩沖中的顏色進(jìn)行計算,輸出新的顏色扇丛。
雙重顏色緩沖區(qū)(Dboule Buffering)术吗,在后置緩沖(Back Buffer)中渲染場景,等渲染完成后帆精,再與前置緩沖區(qū)(Front Buffer)交換较屿,這樣避免了看到還沒有渲染完的場景。
注意:
正常情況下卓练,引擎一般會在片元著色器之前進(jìn)行模板測試與深度測試隘蝎,以避免會被剔除的片元仍會參與片元著色做無用功。下圖所示昆庇,Unity的DepthTest在Fragment Shader之前執(zhí)行末贾。
但是使用了AlphaTest時,模板測試與深度測試無法提前執(zhí)行整吆,還是會延時到片元操作階段執(zhí)行。這是因為:
- AlphaTest在Geometry隊列之后辉川,Transparent隊列之前渲染
- AlphaTest與Geometry一樣表蝙,都是從前至后渲染
- 有一部分像素會被剔除,所以應(yīng)該可以看到這些將要被剔除像素后面的物體乓旗,但如果在剔除前就使用深度測試府蛇,會導(dǎo)這些將被剔除像素后面的物體也被剔除(深度測試失敗)屿愚。片元著色器中使用Clip命令進(jìn)行剔除操作汇跨。
所以可以看出,AlphaTest是比較費(fèi)性能的妆距,多余的消耗主要在不能提前進(jìn)行模板與深度測試穷遂,所以使用了AlphaTest的物體即使被遮擋了(被其它物體或被自身遮擋),還是會執(zhí)行片元著色操作娱据。
而且蚪黑,使用AlphaTest的物體在屏幕上顯示面積越大,消耗越多中剩,因為片元著色操作次數(shù)與物體像素數(shù)成正比忌穿。
比如,場景中一顆大樹的樹葉使用了AlphaTest结啼,而且樹葉很多的話掠剑,那么所有樹葉都會執(zhí)行一次片元著色,無論它有沒有被其它樹葉遮擋捉祭ⅰ(因為此時深度測試在片元著色之后才會執(zhí)行)朴译。如果此時相機(jī)離樹很近的話沸伏,消耗就更大了。