Unity-Shader-渲染隊列
- 渲染簡介
- Unity中的幾種渲染隊列
- Background (1000)最早被渲染的物體的隊列。
- Geometry (2000) 不透明物體的渲染隊列。大多數物體都應該使用該隊列進行渲染,也就是Unity Shader中默認的渲染隊列。
- AlphaTest (2450) 有透明通道,需要進行Alpha Test的物體的隊列,比在Geomerty中更有效。
- Transparent (3000)半透物體的渲染隊列。一般是不寫深度的物體,Alpha Blend等的在該隊列渲染。
- Overlay (4000)最后被渲染的物體的隊列,一般是覆蓋效果,比如鏡頭光暈,屏幕貼片之類的。
- Opaque: 用于大多數著色器(法線著色器、自發光著色器、反射著色器以及地形的著色器)。
- Transparent:用于半透明著色器(透明著色器、粒子著色器、字體著色器、地形額外通道的著色器)。
- TransparentCutout: 蒙皮透明著色器(Transparent Cutout,兩個通道的植被著色器)。
- Background: 天空盒著色器。
- Overlay: GUITexture,鏡頭光暈,屏幕閃光等效果使用的著色器。
- TreeOpaque: 地形引擎中的樹皮。
- TreeTransparentCutout: 地形引擎中的樹葉。
- TreeBillboard: 地形引擎中的廣告牌樹。
- Grass: 地形引擎中的草。
- GrassBillboard: 地形引擎中的廣告牌草。
- 相同渲染隊列中不透明物體的渲染順序
- 相同渲染隊列中半透明物體的渲染順序
- 自定義渲染隊列
- 注意
渲染簡介
在渲染階段,引擎所做的工作是把所有場景中對象按照一定的策略(順序)進行渲染。最早的是畫家算法,顧名思義,就是像畫家畫畫一樣,先畫后面的物體,如果前面還有物體,那么就用前面的物體把后面的物體覆蓋,不過這種方式由于排列是針對物體來排序的,而物體之間也可能有重疊,所以效果并不好。所以目前更加常用的方式是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就可以了,當然,如果不加,name就是默認的渲染隊列Geometry。比如我們需要我們的物體在Transparent這個渲染隊列中進行渲染的話,就可以這樣寫:
Tags{“Queue” = “Transparent”}
我們可以直接在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(渲染隊列相同),分別給三個人不同材質(相同材質的小頂點數的物體引擎會動態合批),用Unity帶的Frame Debug工具查看一下DrawCall。
可以看出,Unity中對于不透明的物體,是采用了從前到后的渲染順序進行渲染的,這樣,不透明物體在進行完vertex階段,進行Z Test,然后就可以得到該物體最終是否在屏幕上可見了,如果前面渲染完的物體已經寫好了深度,深度測試失敗,那么后面渲染的物體就不會再去進行fragment階段。(不過這里需要把三個物體之間的距離稍微拉開一些,本人在測試時發現,如果距離特別近,就會出現渲染次序比較亂的情況,因為我們不知道Unity內部距離排序時是按照什么標準來判定的哪個物體離攝像機更近,這里我也就不猜測了)
相同渲染隊列中半透明物體的渲染順序
透明物體的渲染一直是圖形學方面比較蛋疼的地方,對于透明物體的渲染,就不能像渲染不透明物體那樣多快好省了,因為透明物體不會寫深度,也就是說透明物體之間穿插關系是沒有辦法判斷的,所以半透明的物體在渲染的時候一般都是采用從后向前的方法進行渲染的,由于透明物體多了,透明物體不寫深度,name透明物體之間就沒有所謂的可以通過深度測試來剔除的優化,每個透明物體都會走像素階段的渲染,會造成大量的over Draw。這也就是粒子特效特別耗費性能的原因。
我們實驗一下Unity中渲染半透明物體的順序,還是上面三個立方體,我們把材質的shader統一換成粒子最常用的Particle/Additive類型的shader,再用FrameDebug工具查看一下渲染的順序:
自定義渲染隊列
Unity支持我們自定義渲染隊列,比如我們需要保證某種類型的對象需要在其他類型的對象渲染之后再渲染,就可以通過自定義隊列進行渲染。而且超級方便,我們只需要在寫shader的時候修改一下渲染隊列中的Tag即可。比如我們希望我們的物體要在所有默認的不透明物體渲染完之后渲染,name我們就可以使用
Tag{“Queue” = “Geometry+1”}就可以讓使用了這個shader的物體在這個隊列中進行渲染。
還是上面的三個立方體,這次我們分別給三個不同的shader,并且渲染隊列不同,通過上面的實驗我們知道,默認情況下,不透明物體都是在Geometry這個隊列中進行渲染的,那么不透明的三個物體就會按照cube1,cube2,cube3進行渲染。這次我們希望將渲染的順序反過來,那么我們就可以讓cube1的渲染隊列最大,cube3的渲染隊列最小。貼出其中一個的shader:
Shader "Custom/RenderQueue1" {SubShader{Tags { "RenderType"="Opaque" "Queue" = "Geometry+1"}Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float4 pos : SV_POSITION;};v2f vert(appdata_base v){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"
}
這里我用ASE制作的Shader跟上述是一致的。
其他的兩個shader類似,只是渲染隊列和輸出顏色不同。
通過渲染隊列,我們就可以自由地控制使用該shader的物體在什么時機渲染。比如某個不透明的像素階段操作較費,我們就可以控制它的渲染隊列,讓其渲染更靠后,這樣可以通過其他不透明物體寫入的深度剔除該物體所占的一些像素。
注意
我們在修改shader的時候一般不需要什么其他操作就可以直接看到修改后的變化,但是改完渲染隊列后,有時候會出現從shader的文件上能看到渲染隊列的變化,但是從渲染結果以及Frame Debug工具中并沒有看到渲染結果的變化,重啟Unity也沒有起到作用,直到我們把shader重新賦值給材質之后,變化才起了效果。**