關於 web service, unity, blogger 等軟體工程筆記

Unity rendering order 整理筆記

Edit icon 沒有留言
Unity

自從上次 GameJam 體驗在 Unity 中,使用 SpriteRenderer 可直接調整 Sorting layer 來決定 render 順序後,便一直很好奇其背後實作到底是什麼,為什麼改變一個數值便能調整 sprites 在 render 結果的先後順序,而不用調整距離相機 (camera) 的距離來達到。

儘管 Sorting layer 是 Unity 4.3 推出用來製作 2D 的功能,但介紹其底層實作或是概念的資料並不好找,最終透過一些線上討論、實驗推敲與過去的經驗,終於想明白這是怎麼回事,是自己腦袋打結想太複雜,其實概念很簡單。

成像結果與場景俯視圖,rendering result 物件前後順序,不表示在場景中是依照其離攝影機深度來排列

成像結果與場景俯視圖,rendering result 物件前後順序,不表示在場景中是依照其離攝影機深度來排列

提示:使用 Unity 2018.1 測試

關於深度緩衝 (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 編輯
      編輯 depth 參數

      編輯 depth 參數

  • Material type
    • 先畫不透明物件 (opaque),再畫透明物件 (transparent)
    • 根據 material render queue 來決定,數值小於等於 2500 為不透明物件,數值大於 2500 為透明物件
  • Sorting layer
    • 數字越大越晚畫
    • 大多數的 renderer 都有支援此參數,但僅有 SpriteRenderder 以及 ParticleSystemRenderer 能在預設的 Inspector 編輯(不過自定義編輯器來達成)
    • 程式設定 renderer.sortingLayerID
    • 在 Tag Manager 編輯 Sorting layer
      編輯 Sorting layers
    • 選擇場景的 SpriteRenderder 或是 ParticleSystemRenderer 編輯 Sorting layer
      編輯 Sorting layer
  • Order in layer
    • 數字越大越晚畫
    • 大多數的 renderer 都有支援此參數,但僅有 SpriteRenderder 以及 ParticleSystemRenderer 能在預設的 Inspector 編輯
    • 程式設定 renderer.sortingOrder
    • 選擇場景的 SpriteRenderder 或是 ParticleSystemRenderer 編輯 Order in layer
      編輯 Order in layer
  • Material render queue
    • 數字越大越晚畫
    • 預設值會從 Shader 取得,但可自行定義
    • 不透明物件 (Opaque)、半透明物件 (AlphaTest)、透明物件 (Transparent) 預設值分別 2000、2450、以及 3000
      • 通常只有透明物件會關閉 ZWrite
    • 程式設定 material.renderQueue
    • 選擇專案中的 material 編輯
      編輯 render queue
  • 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 來決定描繪順序,數字越大越晚畫
      編輯 Canvas's Sort Order
  • Screen Space - Camera & World Space
    • 想像為存在在世界場景的平面
    • 多個相同 canvas 使用 Sorting layer 以及 Order in layer 來決定 rendering order
      編輯 Canvas's Sorting layer & Order in layer

關於同一個 canvas 下,其 CanvasRenderer 之間的 rendering order:

  • Material render queue > Transform order
    • Material render queue 同前面說明,看材質球 (material) 的 render queue 參數
    • Transform order:依照 Transform 階層關係,採 Pre-order 方式排序
      Canvas renderer's rendering order example
    • 注意:當所屬的 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
  • 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

沒有留言: