調UI遮擋關系有三種思路:
- 調Sorting Layer,層級越后渲染到越前面
- 調Order in Layer,數字越大渲染到越前面
- 修改UI材質調RenderQueue,數字越大越后渲染
對前兩種比較陌生的同學可以看一下我以前寫的這篇,不看也沒事,后面會解釋Unity Canvas的sorting Layer作用_unity sortinglayer-CSDN博客?
第三種方法的話,就是通過給UI材質的方式,把材質的Shader改成渲染順序在后面,并且關閉深度測試(被別的遮擋),以此來實現始終渲染在最前方。但是這個方法更多的適用于你只需要保證一個UI顯示在最前方,而不在意其他UI會不會被它影響的極端情況。
另外如果使用第三種方法的UI(暫時稱為A)上面有文本B的話,文本B也需要調整材質為Overlay,使其渲染順序大于A
同理,如果需要一個UI永遠渲染在最后方,可以添加關閉深度寫入(遮擋別的)且Hierarchy靠前的材質。
方法看起來很簡單,但是項目大了為了滿足各種需求難免會出現方法混用的情況,這時候這三種順序控制的方式很容易攪在一起形成非常古怪的效果?,因此本文在拷打GPT后深度解析了unity的UGUI渲染順序。
Unity 在渲染 UGUI 時:
- 收集所有 Canvas → 按 sortingLayer & sortingOrder 排序
- 對每個 Canvas 內的元素進行 Batching(合批)
- 再生成繪制命令 → 提交到 GPU
因為 Canvas 本身是作為渲染批次的邊界,所以先后順序受 Canvas 排序控制。另外在overlay以外的情況下UGUI(Canvas Renderer)都參與深度測試(被別的遮擋)寫入深度緩沖(ZWrite Off)(遮擋別的)
CPU層管理渲染順序:?
(1)Canvas 自身的順序
-
每個 Canvas 都有:
-
sortingLayer
(圖層) -
sortingOrder
(層內順序)
-
-
排序先按
sortingLayer
(后畫的圖層覆蓋前畫的) -
再按
sortingOrder
(數字大的后畫)
如果兩個 UI 元素在不同 Canvas上,那么:
-
sortingLayer 順序決定誰先畫
-
如果 sortingLayer 相同,sortingOrder 數值大的后畫 → 后畫就會蓋住前畫
(2)同一個 Canvas 內部:
-
按 Hierarchy 層級順序(從上到下,越下越后渲染)
-
添加SortingGroup排序如果它們被不同的 SortingGroup 包起來,且每個 SortingGroup 設置了不同的 sortingOrder:?Unity 會把每個 SortingGroup 當成單獨的渲染批次(draw call);不同組之間無法合批(在
World Space
或Screen Space - Camera
+Override Sorting
時,SortingGroup 才真正控制排序)
(3)Render Queue 在 UI 下的角色
UGUI 的渲染系統會給它生成的材質(批次)加上默認的 Render Queue:
-
通常在
Overlay
(4000)隊列(測試發現WorldSpace下是3000) -
這個 Render Queue 是系統根據 Canvas 類型決定的
-
如果你手動改了 Shader 的 Queue,只能在 Canvas 內部影響先后順序,但無法跨 Canvas 打破 sortingOrder 約束(因為需要合批)
也就是說:
-
不同 Canvas:優先用 sortingLayer/sortingOrder 控制
-
?同一 Canvas 內的材質:sortingGroup管理內部合批,Render Queue 和材質順序也會影響
GPU層像素級別決定是否渲染:
因為光是誰前誰后渲染在三維空間下是無法判斷出像下面這樣重疊態時怎么渲染的,是白色全渲染還是紅色全渲染?這時候就需要深度測試
圖形渲染流水線大體是按CPU給的順序分批次逐像素處理
頂點著色器 → 裁剪 → 光柵化 → 片元著色器 → 深度/模板測試 → 合成到幀緩沖
具體:
- ?頂點著色器:計算模型頂點的坐標
- ?裁剪:裁掉視錐外的部分
- ?光柵化:把三角形拆成像素(片元)
- ?片元著色器:對每個片元計算最終顏色,此時得到了一個片元:位置(Z)、顏色、透明度等信息
- 深度測試 & 模板測試(Depth & Stencil Test):對比當前片元的 Z 值和深度緩沖區已有值,根據 ZTest 設置(比如 Less)決定要不要丟棄
- ?通過測試的片元:才寫進幀緩沖(Color Buffer)和/或寫進深度緩沖(Depth Buffer,取決于 ZWrite)
關鍵點
-
深度測試在片元著色器之后
→ 是像素級別的決定:這個像素畫不畫 -
Render Queue、sortingOrder 決定什么時候發出 draw call(繪制指令)
-
深度測試決定:這個 draw call 產生的片元,最后要不要顯示
步驟 | 做什么 | 誰決定 |
---|---|---|
收集所有要畫的 Canvas | 根據 sortingLayer & sortingOrder 排序 | Unity CPU 層邏輯 |
按順序提交 draw call(材質+網格) | 內部按 render queue 排序 | Unity CPU 層邏輯 |
GPU 渲染片元時 | 每個像素都要經過深度測試 | GPU 硬件 |
總結
sortingOrder 和 render queue 讓CPU決定誰先誰后提交 draw call;
深度測試在 GPU 上決定像素要不要畫,深度測試是在「片元著色器之后」到「寫入幀緩沖之前」進行的。
最后,在不考慮性能的情況下(drawcall很費性能,而一個canvas/sortingGroup會形成一個batch,batch會產生drawcall),協調各個UI順序的邪門快捷方法是每個面板都加個canvas。
或者針對非Overlay的canvas的內部元素添加sortingGroup,調節其order in layer手動進行排序,遮擋關系一下就捋順了?