Unity移動端性能優化(轉)

在知乎上看到一篇不錯的性能優化文章,進行了比較系統的概括,下面分享一下,原文地址:

https://zhuanlan.zhihu.com/p/26030252

1.渲染

  • 利用reflect probe代替反射、折射,儘量不用RTT、GrabPass、RenderWithShader、CommandBuffer.Blit (BuiltinRenderTextureType.CurrentActive...)
  • 建立統一後處理框架(bloom、hdr、DOF等)代替多後處理,可以共用模糊函數,減少多次blit;另外要注意RTT的尺寸。
  • 空氣折射、熱浪扭曲等使用GrabPass不是所有硬件都支持,改爲RTT或者後處理來優化。
  • 建立統一shader材質代替單一shader,充分利用shader_feature、multi_compile,並將宏開關顯示於界面。
  • 圖像混合代替多通道紋理,陰影投射、陰影接收、MetaPass、forwardadd 等pass不需要時要剔除。
  • 少用alpha test、discard、clip、Alpha Converage等,因爲會影響Early-Z Culling、HSR的優化。
  • 避免Alpha Blend穿透問題(權重混合、深度剝離等透明排序方法代價太大了)。
  • 光照貼圖代替動態陰影、儘量不用實時光;陰影貼圖、環境貼圖用16位代替32位;利用projector+rtt或者光圈代替實時陰影。
  • 將環境參數(風、雨、太陽)等shader全局參數統一管理。
  • 非主角可以用matcap代替pbr、無金屬不一定要用pbr,仔細選擇物理渲染所用的FDG(F:schlick、cook-torrance、lerp、要求不高用4次方,D:blinn-phong、beckmann、GGX、GGX Anisotropic,G:neumann、cook-torrance、Kelemen、SmithGGX;standard shader要注意選擇BRDF1-BRDF3),渲染要求不高時不用GGX;可以用LH來優化GGX。
  • 用fixed、half代替float,建立shader統一類型(fixed效率是float的4倍,half是float的2倍),小心選擇shader變量的修飾(uniform、static、全局),選擇Mobile或Unlit目錄下shader
  • 使用高低配渲染,內存足夠時可以考慮開啓mipmap
  • 使用surface shader注意關掉不用的功能,比如:noshadow、noambient、novertexlights、nolightmap、nodynlightmap、nodirlightmap、nofog、nometa、noforwardadd等
  • standard shader的變體太多(3萬多),導致編譯時間較長,內存佔用也很驚人(接近1G),如果使用要關掉沒用的shader_feature,比如:_PARALLAXMAP、SHADOWS_SOFT、DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE、_DETAIL_MULX2、_ALPHAPREMULTIPLY_ON;另外要去掉多餘的pass
  • shaderforge、Amplify Shader Editor生成的shader有多餘代碼要程序專門優化,Amplify Shader Editor功能更強大一些,而且開源,建議學習。
  • 不要用unity自帶terrian,因爲即使只用3張splat圖,shader也是對應4個的,建議T4M或者轉爲mesh。
  • 模型和材質相同且數量巨大時用Instance來優化,比如草。
  • 利用查找紋理(LUT)來優化複雜的光照渲染,比如:皮膚、頭髮、噴漆等。
  • 儘量不要使用Procedural Sky,計算瑞麗散射和米氏散射效率比較低。
  • 儘量不要使用speedtree,改爲模型加簡單樹葉動畫,不過SpeedTreeWind.cginc裏面的動畫函數很豐富,TerrianEngine中的SmoothTriangleWave很好用。
  • 多用調試工具檢查shader性能,常用工具有:FrameDebug、Nsight、RenderDoc 、AMD GPU ShaderAnalyzer / PVRShaderEditor、Adreno Profiler 、騰訊Cube、UWA等;另外可以內置GM界面,比如開關陰影,批量替換shader等方便真機調試。

2.腳本

  • 減少GetComponent、find等查找函數在Update等循環函數中的調用、go.CompareTag代替go.tag 、
  • 減少SendMessage等同步函數調用;減少字符串連接;for代替foreach,5.5以後版本foreach已經優化過了;少用linq;
  • 大資源改爲異步加載
  • 合理處理協程調用
  • 將AI、網絡等放在單獨線程
  • 發佈優化:關閉log、剔除代碼
  • 僞隨機
  • 腳本掛載類改爲Manager等全局類實現
  • lua中儘量不實現update、fixedupdate等循環函數,lua和csharp互調用的效率比較低。

3.內存管理

  • 池子管理粒子、float UI等小資源,頻繁地GC會造成卡頓
  • 必要時主動調用GC.Collect()
  • 按照不同資源、不同設備管理資源生命週期,Resources.Load和Assetbundle統一接口,利用引用計數來管理生命週期,並打印和觀察生命週期。保證資源隨場景而卸載,不常駐內存,確定哪些是預加載,哪些泄漏。
  • 內存泄漏(減少駐留內存):Container內資源不remove掉用Resources.UnloadUnusedAssets是卸載不掉的;對於這種情況,建議直接通過Profiler Memory中的Take Sample來對其進行檢測,通過直接查看WebStream或SerializedFile中的AssetBundle名稱,即可判斷是否存在“泄露”情況;通過Android PSS/iOS Instrument反饋的App線程內存來查看;
  • 堆內存過大:避免一次性堆內存的過大分配,Mono的堆內存一旦分配,就不會返還給系統,這意味着Mono的堆內存是隻升不降的。常見:高頻調用new;log輸出;
  • CPU佔用高:NGui的重建網格導致UIPanel.LateUpdate(按照靜止、移動、高頻移動來切分);NGUI錨點自身的更新邏輯也會消耗不少CPU開銷。即使是在控件靜止不動的情況下,控件的錨點也會每幀更新(見UIWidget.OnUpdate函數),而且它的更新是遞歸式的,使CPU佔用率更高。因此我們修改了NGUI的內部代碼,使錨點只在必要時更新。一般只在控件初始化和屏幕大小發生變化時更新即可。不過這個優化的代價是控件的頂點位置發生變化的時候(比如控件在運動,或控件大小改變等),上層邏輯需要自己負責更新錨點。 加載用協程; 控制同一個UIPanel中動態UI元素的數量,數量越多,所創建的Mesh越大,從而使得重構的開銷顯著增加。比如,戰鬥過程中的HUD血條可能會大量出現,此時,建議研發團隊將運動血條分離成不同的UIPanel,每組UIPanel下5~10個動態UI爲宜。這種做法,其本質是從概率上儘可能降低單幀中UIPanel的重建開銷。
  • 資源冗餘:AssetBundle打包打到多份中;動態修改資源導致的Instance拷貝多份(比如動態修改材質,Renderer.meterial,Animation.AddClip)。
  • 磁盤空間換內存:對於佔用WebStream較大的AssetBundle文件(如UI Atlas相關的AssetBundle文件等),建議使用LoadFromCacheOrDownLoad或CreateFromFile來進行替換,即將解壓後的AssetBundle數據存儲於本地Cache中進行使用。這種做法非常適合於內存特別喫緊的項目,即通過本地的磁盤空間來換取內存空間

4.美術

  • 建立資源審查規範和審查工具:PBR材質貼圖製作規範、場景製作資源控制規範、角色製作規範、特效製作規範;利用AssetPostprocessor建立審查工具。
  • 壓縮紋理、優化精靈填充率、壓縮動畫、壓縮聲音、壓縮UI(九宮格優於拉伸);嚴格控制模型面數、紋理數、角色骨骼數。
  • 粒子:錄製動畫代替粒子、減少粒子數量、粒子不要碰撞
  • 角色:啓用Optimize Game Objects減少節點,使用(SimpleLOD、Cruncher)優化面數。
  • 模型:導入檢查Read/Write only、Optimize Mesh、法線切線、color、禁用Mipmap
  • 壓縮紋理問題:壓縮可能導致色階不足;無透明通道用ETC1,現在安卓不支持ETC2已不足5%,建議放棄分離通道辦法。
  • UI:儘可能將動態UI元素和靜態UI元素分離到不同的UIPanel中(UI的重建以UIPanel爲單位),從而儘可能將因爲變動的UI元素引起的重構控制在較小的範圍內; 儘可能讓動態UI元素按照同步性進行劃分,即運動頻率不同的UI元素儘可能分離放在不同的UIPanel中; 儘可能讓動態UI元素按照同步性進行劃分,即運動頻率不同的UI元素儘可能分離放在不同的UIPanel中;
  • ugui:可以充分利用canvas來切分不同元素。
  • 大貼圖會導致卡頓,可以切分爲多個加載。
  • iOS使用mp3壓縮、Android使用Vorbis壓縮

5.批次

  • 開啓static batch
  • 開啓dynamic batch:要求模型小於900頂點,用法線小於300,用切線小於180,縮放不一致、使用lightmap、多通道材質等會使dynamic batch無效。
  • 減少GameObject,場景模型數量對fps影響巨大。
  • 批次不是越少越好,過大的渲染數據會給總線傳輸帶來壓力。

6.物理

  • 不需要移動的物體設爲Static
  • 不要用Mesh碰撞,角色不用碰撞體
  • 觸發器邏輯優化
  • 尋路頻率、AI邏輯頻率 、Fixed Timestep、降幀到30
  • 出現卡頓的複雜計算,例如尋路、大量資源加載 可以用分幀或者協成異步來處理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章