Unity效能最佳化CPU最佳化

weigang發表於2024-05-20
CPU主要進行計算機的各種計算操作,因此關於CPU效能最佳化的方面和Tips有很多,有些影響大有些影響小,有些容易最佳化有些不易最佳化,細節方面也有很多,歸類之後重點講幾個方面,並列出常見Tips。
對CPU效能影響比較大的主要有以下幾個方面:
DrawCalls,物理元件,GC,程式碼質量,其中DrawCall是CPU最佳化最先考慮的點。
1.Draw Call最佳化
Draw Call實際上是一個命令,發起方是CPU、接收方是GPU,引擎每對一個物體進行一次DrawCall,就會產生一個Batch,這個Batch裡包含該物體所有的網格和頂點資料,當渲染另一個相同的物體時,引擎會直接呼叫Batch裡的資訊,將相關頂點資料直接送到GPU。
(1)使用Draw Call Batching(批處理)
Batching技術的主要目標是在一次DrawCall中批次處理多個物體。只要物體的變換和材質相同,GPU就可以按照相同的方式進行處理,即使用同一次DrawCall中。
分為靜態批處理和動態批處理。動態批處理機制是引擎自動進行的,靜態批處理要把場景物體手動設定static。
動態批處理:自動進行的,頂點數在300以內的可移動物體,只要使用相同的材質,就會組成Batch。(收費)
靜態批處理:把需要靜止的物體標記為static,無論大小,都會組成Batch。初春合併後的資料,會增加記憶體的消耗。
(2)紋理打包成圖集減少材質的使用
Editor>Project Settings>Editor 設定SpritePackage模式,設定為允許打包圖集。
Unity2018中Project中可以建立Sprite Atlas,再新增要打包的紋理圖片即可打包。
比如將3張紋理合併為一個圖集,Batches就會從3降低為1。
(3)減少渲染次數
避免使用大量很小的網格,儘量合併或使用通用;
避免使用過多的材質;
減少實施燈光、陰影、特效等減少渲染次數。
2.物理元件
(1)處理Rigidbody時,使用FixedUpdate,設定Fixed timestep,減少物理計算次數,提高效能。碰撞檢測使用離散的檢測。
(2)不使用網格碰撞器,使用簡單模型;關閉粒子的碰撞功能。
3.GC(垃圾回收)最佳化
GC指的是Unity記憶體管理進行垃圾回收,GC操作會需要大量的時間執行,如果GC在CPU執行的關鍵時刻執行,會對其他操作帶來很大的應先個,使遊戲幀率下降。
什麼時候會觸發GC:
  • 堆記憶體進行記憶體分配操作而記憶體不夠的時候都會觸發垃圾回收來利用閒置的記憶體;
  • GC會自動的觸發,不同平臺執行頻率不一樣;
  • GC可以被強制執行。
特別是堆記憶體進行記憶體分配時記憶體不足時,GC會頻繁觸發。
大體上透過三種方法降低GC的影響:
  • 減少GC執行次數;
  • 減少單次GC的執行時間;
  • GC執行時間延遲,避免在關鍵時候觸發。
解決這三個方面影響,主要有三種策略:
  • 重構程式碼,減少堆記憶體分配和引用的分配,更少的變數和引用會減少GC操作檢測的次數;
  • 降低堆記憶體分配和回收的頻率,尤其是關鍵時刻;
  • 試著測量GC和堆記憶體擴充套件的時間,使其按照預測的順序執行,當然這樣操作的難度極大。
具體方法:
(1)快取變數重複使用,避免反覆呼叫堆記憶體分配的函式;
(2)不在頻繁呼叫的函式如update中進行堆記憶體分配,或進行快取或降低獲取頻率;
(3)使用clear函式清空連結串列替代反覆多次的建立分配連結串列;
(4)物件池
(5)其他堆記憶體分配因素:字串、協程、裝箱…
(6)主動呼叫GC操作System.GC.Collect(),如場景切換的時候。
4.提高程式碼質量
許多操作需要CPU消耗很長的時間,可以儘量避免操作或縮短時間。
(1)GetComponent方法不要頻繁使用,宣告為全域性變數,儲存元件以引用;
(2)使用合理的演算法和資料結構。少使用複雜運算,如除法、開平方根、反餘弦,可以使用+、*代替
(3)使用內建陣列如使用Vector3.zero而不是new Vector(0,0,0);
(4)可以Break掉的迴圈直接退出,減少不必要的迴圈;
(5)將可以快取的資料儘可能的快取起來,避免重複計算和重複分配記憶體(比如不要重複例項化同一個物件,可以事先建好物件池)
(6)FixedUpdate等頻繁呼叫的方法可以擴大間隔,可以使用協程、InvokeRepeating代替;
(7)Shader儘量使用簡單的演算法,不使用太複雜的效果,儘量不使用透明的處理。
(8)等等等
5.其他
動畫系統,使用簡單的動畫;粒子系統減少粒子數量,縮小效果。
物理元件:
1) 處理Rigidbody時,使用FixedUpdate,設定Fixed timestep(固定時間步),減少物理計算次數,運動起來也平滑,提高遊戲效能。碰撞檢測方面、使用離散的檢測。
2)減少FPS,即減少每秒的幀數,在ProjectSetting-> Quality中的VSync Count 引數會影響你的FPS,EveryVBlank相當於FPS=60,EverySecondVBlank = 30;這兩種情況都不符合遊戲的FPS的話,或透過程式碼手動設定。
降低FPS的好處:
1.省電,減少手機發熱的情況;
2.能穩定遊戲FPS,減少出現卡頓的情況。
3)儘量不用MeshCollider
如果可以的話,儘量不用MeshCollider,以節省不必要的開銷。如果不能避免的話,儘量用減少Mesh的面片數,或用較少面片的來代替。
4)粒子元件,螢幕上最大粒子數量建議小於200個,並關閉粒子的碰撞功能。
程式碼方面:
1)使用合理的演算法和資料結構。少使用複雜運算,如除法、開平方根、反餘弦,可以使用+、*代替
2)不要頻繁使用GetComponent去頻繁獲取元件。如果要使用,可宣告為全域性變數,並只需在Awake函式中GetComponent。
3)使用內建陣列如使用Vector3.zero而不是new Vector(0,0,0);
4)指令碼在不使用時,禁用之,需要時再啟用;
5)可以使用射線Ray來代替OnMouseXXX類方法
6)儘量少用模運算和除法運算,比如a/5f,一定要寫成a*0.2f
7)不要使用原生的GUI方法,即OnGUI函式
8)務必刪除指令碼中為空或不需要的預設方法,如Update方法
9)同一指令碼中頻繁使用的變數建議宣告其為全域性變數,指令碼之間頻繁呼叫的變數或方法建議宣告為全域性靜態變數或方法
10)儘量使用整數數字,因為iPhone的浮點數計算能力很差
11)將計算分到多個邏輯幀中進行計算,避免短時間內的效能超過負荷,俗稱“分幀”。
12)將可以快取的資料儘可能的快取起來,避免重複計算和重複分配記憶體。
例如:不要重複例項化同一個物件,可以事先建好物件池
13)使用for迴圈代替foreach,使用List代替 ArrayList,儘量少使用封箱拆箱操作
其他或者其他說法:
14)可以Break掉的迴圈直接退出,減少不必要的迴圈。
15)FixedUpdate等頻繁呼叫的方法可以擴大間隔,可以使用協程、InvokeRepeating代替
16)不使用列印、不出現警告,打包出去的時候

相關文章