Unity中的幾種渲染佇列

2021-08-07 16:03:51 字數 3134 閱讀 3620

在渲染階段,引擎所做的工作是把所有場景中的物件按照一定的策略(順序)進行渲染。最早的是畫家演算法,顧名思義,就是像畫家畫畫一樣,先畫後面的物體,如果前面還有物體,那麼就用前面的物體把物體覆蓋掉,不過這種方式由於排序是針對物體來排序的,而物體之間也可能有重疊,所以效果並不好。所以目前更加常用的方式是z-buffer演算法,類似顏色緩衝區緩衝顏色,z-buffer中儲存的是當前的深度資訊,對於每個畫素儲存乙個深度值,這樣,我們螢幕上顯示的每個畫素點都會進行深度排序,就可以保證繪製的遮擋關係是正確的。而控制z-buffer就是通過ztest,和zwrite來進行。但是有時候需要更加精準的控制不同型別的物件的渲染順序,所以就有了渲染佇列。今天就來學習一下渲染佇列,ztest,zwrite的基本使用以及分析一下unity為了early-z所做的一些優化。

unity中的幾種渲染佇列

首先看一下unity中的幾種內建的渲染佇列,按照渲染順序,從先到後進行排序,佇列數越小的,越先渲染,佇列數越大的,越後渲染。

background(1000) 最早被渲染的物體的佇列。

geometry (2000) 不透明物體的渲染佇列。大多數物體都應該使用該佇列進行渲染,也是unity shader中預設的渲染佇列。

alphatest (2450) 有透明通道,需要進行alpha test的物體的佇列,比在geomerty中更有效。

transparent(3000) 半透物體的渲染佇列。一般是不寫深度的物體,alpha blend等的在該佇列渲染。

overlay (4000) 最後被渲染的物體的佇列,一般是覆蓋效果,比如鏡頭光暈,螢幕貼片之類的。

unity中設定渲染佇列也很簡單,我們不需要手動建立,也不需要寫任何指令碼,只需要在shader中增加乙個tag就可以了,當然,如果不加,那麼就是預設的渲染佇列geometry。比如我們需要我們的物體在transparent這個渲染佇列中進行渲染的話,就可以這樣寫:

[csharp] view plain copytags

我們可以直接在shader的inspector面板上看到shader的渲染佇列:

另外,我們在寫shader的時候還經常有個tag叫rendertype,不過這個沒有render queue那麼常用,這裡順便記錄一下:

opaque: 用於大多數著色器(法線著色器、自發光著色器、反射著色器以及地形的著色器)。

transparent:用於半透明著色器(透明著色器、粒子著色器、字型著色器、地形額外通道的著色器)。

transparentcutout: 蒙皮透明著色器(transparent cutout,兩個通道的植被著色器)。

background: 天空盒著色器。

overlay: guitexture,鏡頭光暈,螢幕閃光等效果使用的著色器。

treeopaque: 地形引擎中的樹皮。

treetransparentcutout: 地形引擎中的樹葉。

treebillboard: 地形引擎中的廣告牌樹

grass: 地形引擎中的草。

grassbillboard: 地形引擎何中的廣告牌草。

相同渲染佇列中不透明物體的渲染順序

拿出unity,建立三個立方體,都使用預設的bump diffuse shader(渲染佇列相同),分別給三個不同的材質(相同材質的小頂點數的物體引擎會動態合批),用unity5帶的frame debug工具檢視一下draw call。(unity5真是好用得多了,如果用4的話,還得用nsight之類的抓幀)

可以看出,unity中對於不透明的物體,是採用了從前到後的渲染順序進行渲染的,這樣,不透明物體在進行完vertex階段,進行z test,然後就可以得到該物體最終是否在螢幕上可見了,如果前面渲染完的物體已經寫好了深度,深度測試失敗,那麼後面渲染的物體就直接不會再去進行fragment階段。(不過這裡需要把三個物體之間的距離稍微拉開一些,本人在測試時發現,如果距離特別近,就會出現渲染次序比較亂的情況,因為我們不知道unity內部具體排序時是按照什麼標準來判定的哪個物體離攝像機更近,這裡我也就不妄加猜測了)

相同渲染佇列中半透明物體的渲染順序

透明物體的渲染一直是圖形學方面比較蛋疼的地方,對於透明物體的渲染,就不能像渲染不透明物體那樣多快好省了,因為透明物體不會寫深度,也就是說透明物體之間的穿插關係是沒有辦法判斷的,所以半透明的物體在渲染的時候一般都是採用從後向前的方法進行渲染,由於透明物體多了,透明物體不寫深度,那麼透明物體之間就沒有所謂的可以通過深度測試來剔除的優化,每個透明物體都會走畫素階段的渲染,會造成大量的over draw。這也就是粒子特效特別耗費效能的原因。

我們實驗一下unity中渲染半透明物體的順序,還是上面的三個立方體,我們把材質的shader統一換成粒子最常用的particle/additive型別的shader,再用frame debug工具檢視一下渲染的順序:

自定義渲染佇列

unity支援我們自定義渲染佇列,比如我們需要保證某種型別的物件需要在其他型別的物件渲染之後再渲染,就可以通過自定義渲染佇列進行渲染。而且超級方便,我們只需要在寫shader的時候修改一下渲染佇列中的tag即可。比如我們希望我們的物體要在所有預設的不透明物體渲染完之後渲染,那麼我們就可以使用tag就可以讓使用了這個shader的物體在這個佇列中進行渲染。

還是上面的三個立方體,這次我們分別給三個不同的shader,並且渲染佇列不同,通過上面的實驗我們知道,預設情況下,不透明物體都是在geometry這個佇列中進行渲染的,那麼不透明的三個物體就會按照cube1,cube2,cube3進行渲染。這次我們希望將渲染的順序反過來,那麼我們就可以讓cube1的渲染佇列最大,cube3的渲染佇列最小。貼出其中乙個的shader:

[csharp] view plain copyshader "custom/renderqueue1"

pass

cgprogram

#pragma vertex vert

#pragma fragment frag

#include "unitycg.cginc"

struct v2f

float4 pos : sv_position;

v2f o;

o.pos = mul(unity_matrix_mvp, v.vertex);

return o;

fixed4 frag(v2f i) : sv_target

return fixed4(0,0,1,1);

endcg

//fallback "diffuse"

寧波整形醫院

unity的渲染路徑

forward rendering path 前向渲染路徑 deffered rendering path 延遲渲染路徑 vertexlit rendering path 頂點照明渲染路徑 拋棄 標籤名描述 always 不管使用哪種渲染路徑,該pass總會被渲染,但不會計算任何光照 forward...

Unity的渲染流程

unity中座標空間的轉換 unity的渲染流程 渲染到裝置螢幕的每一幀畫面都要經歷如下幾個階段 應用程式階段 cpu 將材質和模型資料傳送給gpu 幾何階段 gpu 進行頂點變換計算 光柵化 gpu 將三角形轉化為片元,並對片元著色。cpu 準備需要渲染的物件。把可視的物件,進行遮擋剔除和視椎體剔...

Unity中的前向渲染路徑和延遲渲染路徑

渲染路徑核心 光照處理。unity中光照 逐頂點 逐畫素 球諧光照。逐畫素光照 按照每個畫素的顏色被計算,看起來比較平滑 逐頂點光照 每個頂點上做光照,其他地方插值,效果粗糙。但是逐畫素光照中,每個光源會使每個光源光照範圍內的物體增加乙個渲染批次。延遲渲染可以解決逐畫素光照對光源造成的效能影響。延遲...