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

Unity 開發者大會筆記 2017,優化x優化x優化

Edit icon 沒有留言
Unity 開發者大會 2017 台北

紀錄這次參加 Unity 開發者論壇,比較有印象的場次筆記。因為是開發者大會,所以大多是聽技術專場,而很大一部分都是在討論遊戲優化的議題。如何讓遊戲效能能夠穩定 FPS 60 以上,讓玩家擁有較好的遊戲體驗,而不是玩起來卡卡的,這是一個相當重要的議題。

而遊戲優化議程聽下來,優化主要圍繞以下兩個重點,根據各遊戲設計的狀況,以及 Unity 引擎設計的架構,進行遊戲的調整優化:

  • CPU:減少過多動態記憶體配置 (Memory allocation),所導致 GC spike 的卡頓 (lags)
  • GPU:減少 Drawcall,減少 Overdraw

Eagle Flight (VR)

Eagle flight 遊戲截圖

Eagle flight 遊戲截圖

[Eagle Flight(https://www.ubisoft.com/en-gb/game/eagle-flight/)是一款由 Ubisoft 推出的 VR 遊戲,玩家扮演一隻老鷹翱翔於巴黎城市中,更多關於此遊戲可參考 Trailer。在這次開發者大會的所有議程中,蠻喜歡這場講師帶來製作此遊戲的優化流程與技術,感想是做 AAA 等級的 3D games,或是在運算較差的裝置上跑更好的遊戲畫面,還是得熟悉電腦繪圖學的知識啊,不是是要怎麼做優化達到更好的美術效果,不禁想起之前參與巨獸浩劫專案的優化流程……。

  • 採用 Unity 是希望能夠快速完成開發遊戲雛形 (Fast phototyping)
  • 整個城市場景一開始全部載入到記憶體中
  • 整個城市貼圖只打包兩張紋理圖集 (only two texture atlas),方便後續 batching 優化
  • 不使用 Unity 內建優化策略之原因
    • Occlusion culling,老鷹飛在城市天空上,不能剔除多少場景物件不畫
    • Static batching,不能控制 batching 區域範圍
    • GPU instancing,沒有幫助,瓶頸在場景太多 polygons 需要 raster
  • 自行建立 Mesh baker 技術,處理 Grid LOD
    • Enable/ disable GameObjects 代價昂貴
    • Mip-mapped method
    • 實作細節不清楚
  • 場景記憶體問題
    • 壓縮 UVs 座標,在 Shader repack
    • 成果 1400Mbs -> 700Mbs
  • Overdraw 問題處理
    • 剔除場景物件與場景物件重疊部分的面 (remove overlapping areas polygons)
    • SDF method & Dome method (不是很了解細節)
  • Stencil optimization
    • 遊戲中模擬老鷹飛翔,會有鳥嘴以及兩側黑暗區 (遊戲展示看不出來),使用 Stencil 進行剔除不畫
    • 能不畫的像素 (pixels) 就不畫
    • 省下 GPU 1ms 時間 (補充:如果要維持穩定 FPS 60,那麼 GPU 最多能使用 16.33ms 來完成場景渲染)
  • GC spikes 避免 (GC 花費時間造成遊戲卡頓)
    • 使用 Object pooling 機制重複利用
    • 不使用 Debug.Log
    • 注意第三方的 library GC 問題,提到 Photon & Wwise
    • 遊戲設計執行 GC.Collect
      • 老鷹撞障礙死亡變暗畫面,執行 GC.Collect 強制釋放
    • 少用 foreach
    • 注意 ToArray
    • 不使用 StringBuilder (字串處理連結注意)
  • UI Canvas 優化 (如何優化,見UGUI 優化技巧)
  • 後製特效優化 (如何優化,企劃優化技巧)
  • VR Profiling 需要兩個人一起合作 (一個人玩,一個人檢測 Profile)

Unity 非同步編程技術

這場聽得有點不太喜歡,除了專有名稱地區翻譯的不同以外,專有名詞翻譯成中文還真的不能習慣啊。

介紹 Unity 目前三種方式:

  • Coroutine
    • 有記憶體配置花費 (GC 本身會有額外的效能花費啊)
      • Fixed: StartCoroutine 引擎實作本身就會有固定式花費
      • Variable: Coroutine 應用實作根據其變數宣告,會有另外的花費
    • 注意不要擁有太多 Coroutines
    • 常用於等待 HTTP 回應,遊戲資源場景加載,或是其他遊戲長時間的非同步處理
  • Thread
    • OS 觀念要有就好,使用 .Net API 建立 Thread
    • 避免 Dead-lock,Starvation 等問題
    • Unity API 不是 Thread-safe,會避免非 Main Thread 呼叫
    • 使用 Thread 不容易,建議不使用它
  • Job Worker (開發中)
    • 目前什麼都不明確,請關注 Unity Blog

UGUI 優化技巧 (Unity GUI)

介紹 Canvas 為核心所進行的優化調整,UGUI 系統內建 Batching 機制,該機制會將繪製命令排序優化,減少繪製 draw calls,越少 draw calls 通常意味著其繪製時間越少。

(3D objects 也是有 Batching 機制,參考 Unity Documentation: Draw call batching)

Batching 除了排序繪製命令,將相同材質的繪製命令排在一起畫以外 (減少 SetRenderState),另個機制會將同一個 Canvas 裏頭的繪製元件 (Graphics, e.g. Image and Text),根據使用到的材質 (Materials) 以及其 Transform 和 Layout 資訊等,嘗試進行合併成單一物件 (Geometry 上的意味),使得原先需要多個 draw calls 才能繪製完 UI,減少成少量的 draw calls 即可繪製完成。(電腦科學:Space-time tradeoff)

而這個合併物件幾何資訊的過程稱為 Rebuild,原則上如果後續的 UGUI 沒有發生任何的改變 (材質沒有換,位置沒有動,Layout 沒有改等等等),那麼 UGUI 只需要 Rebuild 一次即可。

若繪製元件在遊戲過程中發生改變,則其所屬 Canvas 則會標示 Dirty (變成骯髒的狀態),這時候 UGUI 就會在 Camera rendering 之前,重新執行一次 Rebuild。

因此 UGUI 最大的效能瓶頸會在 Rebuild,大致上其重點整理:

  • Rebuild 過程很花時間
  • 遊戲設計應考量盡量減少 Rebuild 次數
  • 減少 Rebuild 每次所需的計算的繪製元件量
  • 設計將 UGUI 放在多個 Canvas
    • 常常動的跟不常動的分開放,並且避免繪圖元件重疊 (重疊無法合併)
  • Disable UGUI 元件非常昂貴 (因為需要 Rebuild),可考慮 Disable Canvas

雖然講師沒有提到,在尋找補充資料的過程中,發現進一步更細節的都可以在 Best Practices: Optimizing Unity UI 中找得到。

Unity 企業級使用範例

大量的優化技巧與實務使用,更多進階請參考這篇文章 Understanding optimization in Unity

  • Model import settings
    • 若模型不需要使用到這些資源,則應該關閉不使用…
    • 取消 Read/Write Enabled
      • 通常不需要讀取寫入,Unity 預設值啟用主要是要給 Mesh Coliider 使用
      • 開啟開功能將消耗大量記憶體
    • Animation Type 沒有動畫資料應該設定為 None (場景模型)
      • 避免多餘 Animator
    • Normals & Tangents
      • 用不到則關閉
  • Texture import settings
    • Generate mip maps
      • 2D 不需要,可以關閉
      • Mip maps 是根據物體距離 Camera 遠近,進行材質貼圖的切換,來達到較快的渲染 (Render) 以及減少圖像鋸齒 (Anti-aliasing)的功能
  • Audio import settings
    • 不同平台設定不同的壓縮格式,使用平台的硬體來解音檔
      • iOS -> mp3
      • Android -> vorbis
    • Sample rate 40k -> 20k
    • 檔案小的音檔,可使用 Decompress on Load
    • 手機平台通常沒有良好的立體聲,可考慮 Force to mono
  • 不要用 Resources 這個已經沒有再更新的系統
    • 造成遊戲啟動慢
    • 消耗大量記憶體
  • 其他技巧
    • 初始化呼叫 Shader.WarmupAllShaders
      • 避免第一次使用到該 Shader 造成載入 Shader 遊戲卡頓的問題
    • OnGUI 不推薦使用,請改用 UGUI
    • NGUI 有記憶體管理問題,請改用 UGUI
    • 大量後製特效 (PostEffect) 會造成渲染效能變差
      • 寫新的 Shader,合併多個 PostEffect 效果,在一次渲染中完成遊戲中所有後製特效的處理
      • 使用 Unity 官方推出的 Post Processing Stack
  • 推薦效能檢測工具
  • 盡量使用較新的 Unity 版本

Animation Instancing

由於議題調換,沒能聽到 Geometry instancing 的議程。

目標是要在遊戲場景中繪製上萬個動畫物件 (Animation),這想必需要消耗許多繪圖資源,需要進行優化達到較好的繪製效能。然而動畫物件沒有辦法用 Unity 現有的 Batching 來進行優化,因此這場次主講人介紹一種使用 Geometry instancing 技術來進行大量的動畫物件繪製技術。

大致上流程作法:

  • 將動畫資料 (Skinned mesh) 編碼至貼圖中
  • 透過 Command buffer 以及 Geometry instancing 繪製動畫物件
  • 使用自訂 Shader 從貼圖取得動畫資料,在 GPU 計算完動畫位置

該技術存在一些問題:

  • 無法使用 Blend tree
  • 無法使用 Animator state
  • 無法使用 IK (Inverse kinematics,由世界資料反算動畫位置,例如動畫物件移動時,利用 IK 使得其雙腳能貼齊世界地形)

參考資料

Vulkan (Graphics API)

  • 一般開發者不會特別接觸到 Vulkan
  • 支援 Multi-core graphic API
  • 針對手機大小核的優化設計
  • 能夠更省電,效能有明顯提升
  • 專門設計給手機平台 (2017: 支援手機不多)
    • Android 7 native support
    • iOS, 3rd party support
  • Unity 5.6 支援, see detail

更多參考,see Wiki: Vulkan (API)

AssetBundle GraphTool

完全不需要寫程式的圖形化介面打包 AssetBundles,並且能夠設定 import rules,目前可以從官方的 Bitbucket 下載,未來似乎有計畫納入放入 Unity。

不過之前已經準備好專案的 AssetBundles 打包流程 (參考 AssetBundle 打包筆記),目前應該沒有計畫切換到該工具,也許等它正式被放入到 Unity 中?

沒有留言: