1.ZTest & ZWrite
ZTest:深度測試,開啓後測試結果決定片元是否被捨棄,可配置
ZWrite:深度寫入,開啓後決定片元的深度值是否寫入深度緩衝,可配置
ZTest可設置的測試規則:
ZTest Less:深度小於當前緩存則通過
ZTest Greater:深度大於當前緩存則通過
ZTest LEqual:深度小於等於當前緩存則通過
ZTest GEqual:深度大於等於當前緩存則通過
ZTest Equal:深度等於當前緩存則通過
ZTest NotEqual:深度不等於當前緩存則通過
ZTest Always:不論如何都通過
注意,ZTest Off等同於ZTest Always,關閉深度測試等於完全通過。
ZWrite配置:
ZWrite On 深度寫入開啓 ZWrite Off 深度寫入關閉
ZTest和ZWrite發生在逐片元操作過程,處於片元着色後,最終屏幕輸出前。ZTest與ZWrite的具體操作流程:
因爲ZWrite默認值爲On,ZTest默認值爲LEqual,所以這很好地解釋了爲什麼在unity中,距離相機近的東西會阻擋住距離相機遠的東西。如果我們先繪製一個距離較近的物體,再繪製距離較遠的物體,則距離遠的物體因爲後繪製,會把距離近的物體覆蓋掉,這時我們可以通過修改ZWrite和ZTest來改變物體的遮擋關係
所以對於透明物體的渲染,一般要關閉掉ZWrite,比如Unity中用於渲染Sprite的默認SpriteDefault材質的Shader:
加深對ZTest & ZWrite的理解,可以參考這篇文章的測試部分,把各例子理解明白非常有幫助。
https://www.jianshu.com/p/9137ee354dbd
2.Unity渲染順序
能夠影響渲染順序的因素有:
- Camera Depth: 相機組件上設置的相機深度,深度越大越靠後渲染。
- Sorting Layer: 在Tags & Layers設置中可見
- Order In Layer: 相對於Sorting Layer的子排序,用這個值做比較時只有都在同一層時纔有效。
- RenderQueue: Shader中對Tags設置的“Queue”。
- 物體距離相機的距離,ZDepth值
下面是結果:
1、Camera Depth
永遠最高。Camera Depth小的一定先進渲染管線。
2、當Sorting Layer和Order In Layer不相同時
- 當兩個材質使用了不同的RenderQueue,且這兩個RenderQueue都在[0~2500]或[2501~5000]時,SortingLayer和OrderInLayer的排序生效。
- 當兩個材質使用了不同的RenderQueue,且這兩個RenderQueue分別在[0~2500]和[2501~5000]時,則一定會按照RenderQueue繪製,無視SortingLayer、OrderInLayer的排序。
3、當Sorting Layer和Order In Layer相同時
- RenderQueue不相等:
RenderQueue小的先進渲染管線。
- RenderQueue 相等
RenderQueue 2500以下,由近到遠排序優先 (不透明)
RenderQueue 2500以上, 由遠到近排序優先 (透明)
說明一下:2500是關鍵值,它是透明跟不透明的分界點,因此我們考慮層級的時候要注意着點:renderqueue > 2500的物體絕對會在renderqueue <= 2500的物體前面,即渲染時renderqueue大的會擋住renderqueue小的,不論它的sortingLayer和sortingOrder怎麼設置都是不起作用的。知道了這點,其他的就很好理解了。當兩個的RenderQueue都在同一側時,在SortingLayer高的絕對會在sortingLayer前面,無視renderqueue跟soringOrder,只有在sortingLayer相同的前提下,soringOrder高的會在sortingOrder低的前面,無視renderqueue。當sortingLayer跟sortingOrder相同時,纔看renderqueue的高低,高的在前面。
總結下Unity影響渲染順序各參數的優先級
如果物體的RenderQueue在2500的同一側:
Camera Depth > Sorting Layer > Order In Layer > RenderQueue > 距離相機的距離
如果物體的RenderQueue在2500的不同側:
Camera Depth > RenderQueue > Sorting Layer > Order In Layer > 距離相機的距離
3.Unity中的一個坑
Properties | Value | 渲染隊列描述 | 說明 |
---|---|---|---|
Background | 1000 | This render queue is rendered before any others. | 這個隊列通常被最先渲染(比如 天空盒)。 |
Geometry | 2000 | Opaque geometry uses this queue. | 這是默認的渲染隊列。它被用於絕大多數對象。不透明幾何體使用該隊列。 |
AlphaTest | 2450 | Alpha tested geometry uses this queue. | 需要開啓透明度測試的物體。Unity5以後從Geometry隊列中拆出來,因爲在所有不透明物體渲染完之後再渲染會比較高效。 |
GeometryLast | 2500 | Last render queue that is considered “opaque”. | 所有Geometry和AlphaTest隊列的物體渲染完後 |
Transparent | 3000 | This render queue is rendered after Geometry and AlphaTest, in back-to-front order. | 所有Geometry和AlphaTest隊列的物體渲染完後,再按照從後往前的順序進行渲染,任何使用了透明度混合的物體都應該使用該隊列(例如玻璃和粒子效果) |
Overlay | 4000 | This render queue is meant for overlay effects. | 該隊列用於實現一些疊加效果,適合最後渲染的物體(如鏡頭光暈)。 |
從Unity文檔中這個圖我們可以看出來,Background理應最先被渲染,Unity中的skybox 應該屬於這個renderqueue,但是當你實際使用的時候,怪事發生了:
從FrameDebugger中可以看到,對於不透明物體的渲染,skybox是在opaque的最後渲染,從而減少OverDraw。這尼瑪不跟RenderQueue寫的1000衝突麼?!Google一頓操作,結果是這樣:
總結來說就是:Unity關於Skybox部分的文檔好久沒有更新了,目前Skybox應該是RenderQueue 值爲2500.5時渲染,在Opaque和AlphaTest之後,Transparent之前。
Unity這個文檔證明了這個說法:https://docs.unity3d.com/Manual/GraphicsCommandBuffers.html?_ga=2.53580588.563516390.1589165101-117244140.1588818896
4. 2.5D遊戲渲染排序解決方案
上邊總結了Unity中渲染順序的相關知識,那利用這些知識,可以實現2D遊戲中景深以及排序的問題,初步總結了幾種方案:
1.Order In Layer
通過設置Order In Layer 爲不同的值來進行排序,缺點是需要自定義一套標準來決定物體的Order In Layer值
下邊這個插件用的是這個原理
https://assetstore.unity.com/packages/tools/sprite-management/isometric-toolkit-33032
2.用Shader自定義修改ZDepth
通過自己設置Shader中的ZDepth來達到排序的目的,也就是說Sprite在場景中的Z值都一樣,通過制定一套標準,來人爲定義物體的ZDepth值
下邊這個插件用的是這個原理
https://assetstore.unity.com/packages/templates/systems/2-5d-isometric-engine-106321
3.利用Z軸,實際就是ZDepth
在場景中把各個Sprite擺放位置根據前後關係設置Z軸位置,這樣2D遊戲也可以擁有ZDepth的信息,從而可以正確渲染
4.修改UnityProject 的設置
改爲Y軸爲排序軸,這種方法不用考慮Z軸,完全根據Sprite的y軸大小設置,非常簡便。我是用的這種方式,暫時的缺點是無法根據sprite大小精確控制排序。