Unity 開發者大會筆記 2017,優化x優化x優化
紀錄這次參加 Unity 開發者論壇,比較有印象的場次筆記。因為是開發者大會,所以大多是聽技術專場,而很大一部分都是在討論遊戲優化的議題。如何讓遊戲效能能夠穩定 FPS 60 以上,讓玩家擁有較好的遊戲體驗,而不是玩起來卡卡的,這是一個相當重要的議題。
而遊戲優化議程聽下來,優化主要圍繞以下兩個重點,根據各遊戲設計的狀況,以及 Unity 引擎設計的架構,進行遊戲的調整優化:
- CPU:減少過多動態記憶體配置 (Memory allocation),所導致 GC spike 的卡頓 (lags)
- GPU:減少 Drawcall,減少 Overdraw
Eagle Flight (VR)
[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 花費時間造成遊戲卡頓)
- UI Canvas 優化 (如何優化,見UGUI 優化技巧)
- 後製特效優化 (如何優化,企劃優化技巧)
- VR Profiling 需要兩個人一起合作 (一個人玩,一個人檢測 Profile)
Unity 非同步編程技術
這場聽得有點不太喜歡,除了專有名稱地區翻譯的不同以外,專有名詞翻譯成中文還真的不能習慣啊。
介紹 Unity 目前三種方式:
- Coroutine
- 有記憶體配置花費 (GC 本身會有額外的效能花費啊)
- Fixed: StartCoroutine 引擎實作本身就會有固定式花費
- Variable: Coroutine 應用實作根據其變數宣告,會有另外的花費
- 注意不要擁有太多 Coroutines
- 常用於等待 HTTP 回應,遊戲資源場景加載,或是其他遊戲長時間的非同步處理
- 有記憶體配置花費 (GC 本身會有額外的效能花費啊)
- Thread
- OS 觀念要有就好,使用 .Net API 建立 Thread
- 避免 Dead-lock,Starvation 等問題
- Unity API 不是 Thread-safe,會避免非 Main Thread 呼叫
- 之前有做過該問題的筆記:Unity cross thread call
- 使用 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)的功能
- Generate mip maps
- 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
- 初始化呼叫 Shader.WarmupAllShaders
- 推薦效能檢測工具
- 盡量使用較新的 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 使得其雙腳能貼齊世界地形)
參考資料
- 原始議程來自於 Unite 上海 2017: 基于Animation Instancing的大规模人群模拟
- 尋找相關資料時找到的可用資源,Assetstore: Mesh Animator
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 中?
沒有留言: