Unity3d優化

檢測方式:

一,Unity3D 渲染統計窗口

Game視窗的Stats去查看渲染統計的信息:

1、FPS

fps其實就是 frames per second,也就是每一秒遊戲執行的幀數,這個數值越小,說明遊戲越卡。

 

2、Draw calls

batching之後渲染mesh的數量,和當前渲染到的網格的材質球數量有關。

 

3、Saved by batching 

渲染的批處理數量,這是引擎將多個對象的繪製進行合併從而減少GPU的開銷;

很多GUI插件的一個好處就是合併多個對象的渲染,從而降低DrawCalls ,保證遊戲幀數。

 

4、Tris 當前繪製的三角面數

 

5、Verts 當前繪製的頂點數

 

6、Used Textures 當前幀用於渲染的圖片佔用內存大小

 

7、Render Textures 渲染的圖片佔用內存大小,也就是當然渲染的物體的材質上的紋理總內存佔用

 

8、VRAM usage 顯存的使用情況,VRAM總大小取決於你的顯卡的顯存

 

9、VBO Total 渲染過程中上載到圖形卡的網格的數量,這裏注意一點就是縮放的物體可能需要額外的開銷。

 

10、Visible Skinned Meshes 蒙皮網格的渲染數量

 

11、Animations 播放動畫的數量

注意事項:

1,運行時儘量減少 Tris 和 Draw Calls

預覽的時候,可點開 Stats,查看圖形渲染的開銷情況。特別注意 Tris 和 Draw Calls 這兩個參數。

一般來說,要做到:

Tris 保持在 7.5k 以下,有待考證。

Draw Calls 保持在 20 以下,有待考證。

2,FPS,每一秒遊戲執行的幀數,這個數值越小,說明遊戲越卡。

3,Render Textures 渲染的圖片佔用內存大小。

4,VRAM usage 顯存的使用情況,VRAM總大小取決於你的顯卡的顯存。

 

二,代碼優化

1. 儘量避免每幀處理

比如:

function Update() { DoSomeThing(); }

可改爲每5幀處理一次:

function Update() { if(Time.frameCount % 5 == 0) { DoSomeThing(); } }

2. 定時重複處理用 InvokeRepeating 函數實現

比如,啓動0.5秒後每隔1秒執行一次 DoSomeThing 函數:

 

function Start() { InvokeRepeating("DoSomeThing", 0.5, 1.0); }

 

3. 優化 Update, FixedUpdate, LateUpdate 等每幀處理的函數

函數裏面的變量儘量在頭部聲明。

比如:

function Update() { var pos: Vector3 = transform.position; }

可改爲

private var pos: Vector3; function Update(){ pos = transform.position; }

 

4. 主動回收垃圾

給某個 GameObject 綁上以下的代碼:

function Update() { if(Time.frameCount % 50 == 0) { System.GC.Collect(); } }

 

5. 優化數學計算

比如,如果可以避免使用浮點型(float),儘量使用整形(int),儘量少用複雜的數學函數比如 Sin 和 Cos 等等

 

6,減少固定增量時間

將固定增量時間值設定在0.04-0.067區間(即,每秒15-25幀)。您可以通過Edit->Project Settings->Time來改變這個值。這樣做降低了FixedUpdate函數被調用的頻率以及物理引擎執行碰撞檢測與剛體更新的頻率。如果您使用了較低的固定增量時間,並且在主角身上使用了剛體部件,那麼您可以啓用插值辦法來平滑剛體組件。

7,減少GetComponent的調用

使用 GetComponent或內置組件訪問器會產生明顯的開銷。您可以通過一次獲取組件的引用來避免開銷,並將該引用分配給一個變量(有時稱爲"緩存"的引用)。例如,如果您使用如下的代碼:

function Update () {

transform.Translate(0, 1, 0);

 

}

通過下面的更改您將獲得更好的性能:

 

var myTransform : Transform;

function Awake () {

myTransform = transform;

}

function Update () {

myTransform.Translate(0, 1, 0);

}

 

8,避免分配內存

您應該避免分配新對象,除非你真的需要,因爲他們不再在使用時,會增加垃圾回收系統的開銷。您可以經常重複使用數組和其他對象,而不是分配新的數組或對象。這樣做好處則是儘量減少垃圾的回收工作。同時,在某些可能的情況下,您也可以使用結構(struct)來代替類(class)。這是因爲,結構變量主要存放在棧區而非堆區。因爲棧的分配較快,並且不調用垃圾回收操作,所以當結構變量比較小時可以提升程序的運行性能。但是當結構體較大時,雖然它仍可避免分配/回收的開銷,而它由於"傳值"操作也會導致單獨的開銷,實際上它可能比等效對象類的效率還要低。

 

9,使用iOS腳本調用優化功能

UnityEngine 命名空間中的函數的大多數是在 C/c + +中實現的。從Mono的腳本調用 C/C++函數也存在着一定的性能開銷。您可以使用iOS腳本調用優化功能(菜單:Edit->Project Settings->Player)讓每幀節省1-4毫秒。此設置的選項有:

Slow and Safe – Mono內部默認的處理異常的調用

 

Fast and Exceptions Unsupported –一個快速執行的Mono內部調用。不過,它並不支持異常,因此應謹慎使用。它對於不需要顯式地處理異常(也不需要對異常進行處理)的應用程序來說,是一個理想的候選項。

 

10,

優化垃圾回收

 

如上文所述,您應該儘量避免分配操作。但是,考慮到它們是不能完全杜絕的,所以我們提供兩種方法來讓您儘量減少它們在遊戲運行時的使用:

如果堆比較小,則進行快速而頻繁的垃圾回收

這一策略比較適合運行時間較長的遊戲,其中幀率是否平滑過渡是主要的考慮因素。像這樣的遊戲通常會頻繁地分配小塊內存,但這些小塊內存只是暫時地被使用。如果在iOS系統上使用該策略,那麼一個典型的堆大小是大約 200 KB,這樣在iPhone 3G設備上,垃圾回收操作將耗時大約 5毫秒。如果堆大小增加到1 MB時,該回收操作將耗時大約 7ms。因此,在普通幀的間隔期進行垃圾回收有時候是一個不錯的選擇。通常,這種做法會讓回收操作執行的更加頻繁(有些回收操作並不是嚴格必須進行的),但它們可以快速處理並且對遊戲的影響很小:

if (Time.frameCount % 30 == 0)

{

System.GC.Collect();

}

 

但是,您應該小心地使用這種技術,並且通過檢查Profiler來確保這種操作確實可以降低您遊戲的垃圾回收時間

如果堆比較大,則進行緩慢且不頻繁的垃圾回收

這一策略適合於那些內存分配 (和回收)相對不頻繁,並且可以在遊戲停頓期間進行處理的遊戲。如果堆足夠大,但還沒有大到被系統關掉的話,這種方法是比較適用的。但是,Mono運行時會儘可能地避免堆的自動擴大。因此,您需要通過在啓動過程中預分配一些空間來手動擴展堆(ie,你實例化一個純粹影響內存管理器分配的"無用"對象):

 

function Start() {

 

var tmp = new System.Object[1024];

 

// make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks

 

for (var i : int = 0; i < 1024; i++)

 

tmp[i] = new byte[1024];

 

// release reference

 

tmp = null;

 

}

 

遊戲中的暫停是用來對堆內存進行回收,而一個足夠大的堆應該不會在遊戲的暫停與暫停之間被完全佔滿。所以,當這種遊戲暫停發生時,您可以顯式請求一次垃圾回收:

 

System.GC.Collect();

 

另外,您應該謹慎地使用這一策略並時刻關注Profiler的統計結果,而不是假定它已經達到了您想要的效果。

 

三,模型

1,壓縮 Mesh

導入 3D 模型之後,在不影響顯示效果的前提下,最好打開 Mesh Compression。

Off, Low, Medium, High 這幾個選項,可酌情選取。

2,避免大量使用 Unity 自帶的 Sphere 等內建 Mesh

Unity 內建的 Mesh,多邊形的數量比較大,如果物體不要求特別圓滑,可導入其他的簡單3D模型代替。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章