Unity rendering order 整理筆記
自從上次 GameJam 體驗在 Unity 中,使用 SpriteRenderer 可直接調整 Sorting layer 來決定 render 順序後,便一直很好奇其背後實作到底是什麼,為什麼改變一個數值便能調整 sprites 在 render 結果的先後順序,而不用調整距離相機 (camera) 的距離來達到。
儘管 Sorting layer 是 Unity 4.3 推出用來製作 2D 的功能,但介紹其底層實作或是概念的資料並不好找,最終透過一些線上討論、實驗推敲與過去的經驗,終於想明白這是怎麼回事,是自己腦袋打結想太複雜,其實概念很簡單。
關於深度緩衝 (Depth buffering, or z-buffering)
勢必得先回歸電腦繪圖學 (Computer graphics) 的知識,理解 Rasterization 怎麼透過 z-buffering ,來解決物體 rendering 可視問題 (visibility problem),哪些可見那些不可見,這也關係到物件在 rendering result 成像後前後順序。
當物件 rendering 時,每個所生成的 pixel 產生的深度資訊 (z coordinate) 會儲存在 z-buffer (或稱為 depth buffer),buffer 為二維陣列,其尺寸大小與最後成像尺寸相同。在 Unity shader 中可利用 ZWrite On | Off
來切換是否將深度資訊要寫入到 z-buffer。
如果場景中其他物件 rendering 時,也在同一個 pixel 位置渲染結果時,會檢查 z-buffer 所儲存的深度資訊,是否將渲染結果覆蓋原本的 pixel,並且將新的深度資訊寫入到 z-buffer。通常條件會設定為深度資訊比原本更接近攝影機時,就能夠覆蓋原本結果。在 Unity shader 中可利用 ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always
來調整判斷方式。
有 z-buffering 機制,可不管物件算繪順序 (rendering order),使得離攝影機越近的物件,永遠都描繪在其他離攝影機越遠的物件之前 (ZTest LEqual
)。
Renderer’s rendering order
假設 shader 中關閉深度機制的判斷 (ZTest Always
),或者在 render 場景物件的過程中都不寫入深度 (ZWrite Off
),即沒有 z-buffering 機制,rendering order 會決定成像的結果,越晚畫的物件永遠都在其他較早畫的物件之上。
而在 SpriteRenderer 直接修改 sorting layer 以及 order in layer 來改變 rendering order,就能調整該物件在算繪結果的物件前後,便是基於此緣故,更多細節可查看 Sprites/Default
shader 程式碼。
故整理在 Unity 中,rendering order 是根據以下參數進行排序:Camera depth > Material type > Sorting layer > Order in layer > Material render queue > Camera order algorithm。
- Camera depth
- 數字越大越晚畫
- 通常無法搭配 Clear Flags: Don’t Clear,因為不會清除 depth buffer (z-buffer)
- 程式設定
camera.depth
- 選擇場景中的 camera 編輯
- Material type
- 先畫不透明物件 (opaque),再畫透明物件 (transparent)
- 根據 material render queue 來決定,數值小於等於 2500 為不透明物件,數值大於 2500 為透明物件
- Sorting layer
- 數字越大越晚畫
- 大多數的 renderer 都有支援此參數,但僅有 SpriteRenderder 以及 ParticleSystemRenderer 能在預設的 Inspector 編輯(不過自定義編輯器來達成)
- 程式設定
renderer.sortingLayerID
- 在 Tag Manager 編輯 Sorting layer
- 選擇場景的 SpriteRenderder 或是 ParticleSystemRenderer 編輯 Sorting layer
- Order in layer
- 數字越大越晚畫
- 大多數的 renderer 都有支援此參數,但僅有 SpriteRenderder 以及 ParticleSystemRenderer 能在預設的 Inspector 編輯
- 程式設定
renderer.sortingOrder
- 選擇場景的 SpriteRenderder 或是 ParticleSystemRenderer 編輯 Order in layer
- Material render queue
- 數字越大越晚畫
- 預設值會從 Shader 取得,但可自行定義
- 不透明物件 (Opaque)、半透明物件 (AlphaTest)、透明物件 (Transparent) 預設值分別 2000、2450、以及 3000
- 通常只有透明物件會關閉 ZWrite
- 程式設定
material.renderQueue
- 選擇專案中的 material 編輯
- Camera render algorithm
- 無法在預設編輯器修改,使用程式調整
- 非透明物件排序演算法
camera.opaqueSortMode
- Default:在 Unity 2018.1 預設值 FrontToBack
- FrontToBack:粗略低由近到遠排序繪製,能使得 GPU rendering 時有更好的效能
- NoDistanceSort:關閉排序繪製,能降低 CPU 的使用量
- 透明物件排序演算法
camera.transparencySortMode
- Default:根據 camera projection mode 調整
- Perspective:根據 camera 位置到物件中心 (object center) 的距離排序
- Orthographic:根據 view plane 到物件中心 (object center) 的距離排序
- CustomAxis:制定 axis 排序,專門用於 2D 遊戲製作,可參考這篇文章
UGUI’s rendering order
在 Unity 5.x 推出的 UGUI 系統中,其 rendering order 卻是另外規則,這分成兩個部分探討 Canvas & CanvasRenderer,其概念可想像是 CanvasRenderer 可視為畫在畫布 Canvas 的元件,之後該畫布再畫在最終的畫面上(e.g. render target)。
關於 Canvas 的 rendering order:
- Screen Space - Overlay
- 想像該 canvas 由隱藏的 camera 處理,其 depth = 101 (最後才處理)
- 多個相同的 canvas 使用 Sort Order 來決定描繪順序,數字越大越晚畫
- Screen Space - Camera & World Space
- 想像為存在在世界場景的平面
- 多個相同 canvas 使用 Sorting layer 以及 Order in layer 來決定 rendering order
關於同一個 canvas 下,其 CanvasRenderer 之間的 rendering order:
- Material render queue > Transform order
- Material render queue 同前面說明,看材質球 (material) 的 render queue 參數
- Transform order:依照 Transform 階層關係,採 Pre-order 方式排序
- 注意:當所屬的 Canvas 之 render mode 為 Screen Space - Overlay,則無視 Material render queue
使用實踐情境
- 3D
- 不透明物件 & 半透明物件 (e.g. 草、鐵絲網等等) 依照場景擺放
- 不需要特別設定 rendering order
- 一切交給 z-buffering 機制
- 透明物件或是粒子特效 (particle system) 可透過 sort layer & order in layer 機制調整 rendering order
- 透明物件 shader 通常不會寫 z-buffer (e.g.
ZWrite Off
) - 可 hack inspector 來設定
renderer.sortingLayerID
以及renderer.sortingOrder
- 透明物件 shader 通常不會寫 z-buffer (e.g.
- 不透明物件 & 半透明物件 (e.g. 草、鐵絲網等等) 依照場景擺放
- 2D
- Sprite renderer 使用 sort layer & order in layer 機制來調整 rendering order,以控制 depth
- UGUI
- 利用 transform hierarchy 來建立 rendering order,因應效能優化可能還得拆成多個 canvas
- 若採用 Canvas render mode: World space,想讓 UI 與 3D 場景物件的結合,可將 canvas 視為 3D 物件去設計場景架構 (這自己就沒有經驗…)
Reference
- Wiki: Z-buffering
- Unity Manual: ShaderLab: Culling & Depth Testing
- Unity Tutorials: Sorting Layers
- Unity Doc: ShaderLab: SubShader Tags
- Unity Answers: Render Queue VS Sorting Layer
- Unity ScriptRef.: Material.renderQueue
- Unity Manual: Canvas
- Unity ScriptRef.: Camera.opaqueSortMode
- Unity ScriptRef.: Camera.transparencySortMode
沒有留言: