10.Unity性能優(yōu)化總結(jié)

參考:
Unite Now - 性能優(yōu)化技巧 BV1Bp4y1i7wK? BV1Tt4y1X7f6
Unity 技術(shù)開放日 北京站 BV1r44y1z7X3
Unity 淺談Unity內(nèi)存管理 BV1aJ411t7N6
花桑-UGUI性能優(yōu)化總結(jié)? https://www.drflower.top/posts/aad79bf1/
Unity UI優(yōu)化(1~5) https://gwb.tencent.com/community/detail/127013
知乎-Unity的內(nèi)存管理與性能優(yōu)化 https://zhuanlan.zhihu.com/p/362941227

總覽:
1.通用優(yōu)化
2.UI優(yōu)化
3.設(shè)置(紋理設(shè)置,Mesh設(shè)置,音頻設(shè)置,Graphics設(shè)置)
根據(jù)大佬們的文章理解寫出來的,有錯誤歡迎指正!
1.通用優(yōu)化
1.多對象的Mono類上,通用的配置字段使用So配置代替,可以減少Mono復(fù)制字段占用內(nèi)存 ??
2.避免使用Resource 文件夾, 游戲啟動時加載索引表,影響啟動時間
3.清除空的Mono方法,即使方法內(nèi)是空的也會調(diào)用,例如Start,Update
4.動畫機的屬性使用Hash替代屬性名, 同理 材質(zhì),shader也適用
可以先將Hash緩存起來,減少字符串查找的消耗
5.避免Hierarchy的物體之間有很深的層級
因為當(dāng)對父節(jié)點的GameObject進行坐標(biāo)轉(zhuǎn)換時,就會產(chǎn)生OnTransformChanged事件,這消息會傳遞給該GameObject下所有子對象,即使這些對象沒有任何渲染組件
6.Accelerometer Frequency 關(guān)閉加速度計頻率(Project Settings->Player->IOS->Other Settings)
這個功能定義Unity從設(shè)備讀取加速度儀信息的頻率,在不需要加速儀的游戲中,將它啟動或設(shè)置了高于需求的頻率,會影響性能表現(xiàn)。因為讀取硬件設(shè)備信息,會增加CPU的處理時間
7.對于移動有rigidbody的物體,使用rb.MovePosition (在FixUpdate執(zhí)行)代替transform.Translate , 可以減少PsysX物理引擎的重計算
8.避免AddComponent使用過多 , 避免多次 Find,? GetComponent, 這些函數(shù)的消耗都比較大
9.減少裝箱拆箱操作
10.避免匿名函數(shù)
所有的匿名函數(shù)和閉包在C#編IL代碼時都會被new成一個Class(匿名class),所以在里面所有函數(shù),變量以及new的東西,都是要占內(nèi)存的。
11.使用單例需要注意,靜態(tài)的字段會一直保留占用內(nèi)存。
12.對于頻繁調(diào)用的屬性(getter/setter)改為字段,因為調(diào)用屬性相當(dāng)于調(diào)用函數(shù),會在堆棧上分配內(nèi)存。
13.當(dāng)發(fā)現(xiàn)Native Memory大量上升時,可以先著重檢查Scene
因為是C++引擎,所有的實體最終都會反映在C++上,而不會反映在托管堆上。所以當(dāng)構(gòu)建一個GameObject的時候,實際上在Unity的底層會構(gòu)建一個或多個Object來存儲這一個GameObject的信息(Component信息等)。所以當(dāng)一個Scene里面有過多的GameObject存在的時候,Native Memory就會顯著的上升,甚至可能導(dǎo)致內(nèi)存溢出。
2.UI優(yōu)化
UI的基本原理?
Canvas:Native層實現(xiàn)的Unity組件,Canvas負責(zé)將其內(nèi)部的幾何形狀合并到批處理、生成合適的渲染指令并發(fā)送到Unity圖形系統(tǒng)
這些操作都由原生C++代碼完成,這稱為?重新批處理(Rebatch)?或?批處理構(gòu)建(Batch Build)?。當(dāng)一個畫布被標(biāo)記為含有需要重新批處理的幾何形狀時,稱這個畫布為?臟(dirty)?畫布。
Graphic :類是由Unity UI系統(tǒng)的C#庫提供的基類,所有的向畫布系統(tǒng)提供可繪制幾何內(nèi)容的UI系統(tǒng)C#類都繼承它。大多數(shù)內(nèi)置的UI系統(tǒng)繪圖類都是通過?MaskableGraphic?子類實現(xiàn)的,這個子類實現(xiàn)了?IMaskable?接口,可以被遮罩。
Layout組件 控制RectTransform的尺寸和位置,它通常用于創(chuàng)建具有復(fù)雜布局并且內(nèi)部組件需要相對尺寸或者相對位置的UI。Layout組件只依賴RectTransform并且只影響與其關(guān)聯(lián)的RectTransform的屬性。
Graphic和Layout組件都依賴?CanvasUpdateRegistry?類,該類沒有在Unity編輯器中公開。這個類跟蹤那些需要進行更新的Layout組件和Graphic組件集合,并在與其相關(guān)的畫布調(diào)用 WillRenderCanvases?事件時根據(jù)需要觸發(fā)更新(update)。
Batch Build/Rebatch(Canvases):Canvas把表示它UI元素的網(wǎng)格合并起來,并生成合適的渲染命令發(fā)送到Unity的圖形管線中。這一過程的結(jié)果會被緩存并重,直到畫布被標(biāo)記為臟畫布。
計算批處理需要根據(jù)深度(Depth)對網(wǎng)格進行排序、檢查網(wǎng)格的重疊、共享材質(zhì)等情況。這個操作是多線程的,因此在不用的CPU架構(gòu)上性能差異很大。
Rebuild(Graphics):指重新計算Graphic的Layout和網(wǎng)格的過程(Layout重建+Graphic重建),在CanvasUpdateRegistry中執(zhí)行。
關(guān)注指標(biāo):
Canvas.BuildBatch 函數(shù)耗時
Canvas.SendWillRenderCanvases 函數(shù)耗時
Draw Call
Overdraw
堆內(nèi)存
合批規(guī)則(Draw Call)
UGUI的合批除了要求相同貼圖和材質(zhì)外,還對Depth和Hierarchy的層級等有要求。
比如兩個相鄰Image的圖是同個圖集,則不打斷合批
可以借助FrameDebugger實時調(diào)試合批情況。
優(yōu)化
1.盡量減少層次 -> 減少Layout Rebuild計算時間
2.慎用Mask組件和Outline、Shadow組件
都是通過重復(fù)繪制多個Mesh實現(xiàn)的,其中Showdow繪制為原文本Mesh的2倍,而Outline為5倍,對渲染面數(shù)、頂點數(shù),BuildBatch和SendWillRenderCanvases的耗時,Overdraw都有影響
3.Raycast關(guān)閉, 不需要射線遮擋的關(guān)閉
4.隱藏界面時,可用CanvasGroup.Alpha=0,或者Canvas設(shè)置enable=false,代替SetActive。
5.使用RectMask2D代替Mask
Mask:
裁剪依賴Image組件,可根據(jù)Image裁剪不規(guī)則形狀。
增加兩個DrawCall
RectMask2D:
裁剪按照Rect大小,不依賴Image
6.盡量保持UI上的粒子特效簡單,盡量使用序列幀實現(xiàn)。
7.界面上的特效不要直接掛在在UI的Prefab上,而是用動態(tài)加載的方式,有助于減小UI的Prefab體積以及加載時間。
8.Canvas動靜分離(減少BuildBatch耗時),把更新頻繁的UI就放在另一個Canvas里。例如血條,飄字。還有盡量減低更新頻率,如隔幀更新。
9.使用圖集(減少內(nèi)存碎片,減少合批次數(shù))
3.設(shè)置
紋理設(shè)置
1.關(guān)閉Read/Write。減少一半內(nèi)存
2.UI不需要MipMaps (MipMap的意思是分級細化紋理,也可以理解為圖片的LOD)
3.不透明圖移除Alpha通道
4.UI使用圖集
紋理格式選擇:
Mesh設(shè)置
1.Mesh Compression ->選擇High(高比特率壓縮)
2.關(guān)閉Read/Write
3.不是動畫對象關(guān)閉Rig
4.Blendshapes:無使用則關(guān)閉
5.Material:如果Material沒有用到法向量和切線信息,則關(guān)閉
音頻設(shè)置
1.使用Force To Mono , 強制單聲道
2.格式:Android:vorbis? iOS:ADPCM或者MP3
3.LoadType設(shè)置
Graphics設(shè)置
1.靜態(tài)批處理,將不動的對象標(biāo)記為靜態(tài)批次
2.Mesh Render關(guān)閉陰影投射: Mesh Render>Lighting-> Shadow Casting Off
3.光照使用Culliing Masks (遮罩),只對特定層的物體光照
4.避免直接使用手機分辨率,因為有的手機自身過高,會增加渲染負擔(dān)
Screen.SetResolution(width,height,false);
相對的,關(guān)閉則可能會導(dǎo)致分辨率過低,這就需要設(shè)置一個合適的分辨率