Unity 性能優化(力薦)

開始以前先分享幾款性能優化的插件:html

一、SimpleLOD :android

除了一樣擁有Mesh Baker所具備的Mesh合併、Atlas烘焙等功能,它還能提供Mesh的簡化,並對動態蒙皮網格進行了很好的支持。ios

該插件可在Run-time和Editor中均可以使用,同時開放了源碼,你們能夠根據項目的實際狀況而做修改。web

http://download.csdn.net/download/jasonczy/10178526算法

 

1、編程

轉載自 http://blog.csdn.net/game_jqd/article/details/51899000數組

使用Profiler工具分析內存佔用狀況
  • System.ExecutableAndDlls:系統可執行程序和DLL,是隻讀的內存,用來執行全部的腳本和DLL引用。不一樣平臺和不一樣硬件獲得的值會不同,能夠經過修改Player Setting的Stripping Level來調節大小。

 

Ricky:我試着修改了一下Stripping Level彷佛沒什麼改變,感受雖佔用內存大但不會影響遊戲運行。咱們暫時忽略它吧(- -)!緩存

 

  • GfxClientDevice:GFX(圖形加速\圖形加速器\顯卡 (GraphicsForce Express))客戶端設備。

 

Ricky:雖佔用較大內存,但這也是必備項,沒辦法優化。繼續忽略吧(- -)!!安全

 

  • ManagedHeap.UsedSize:託管堆使用大小。

 

Ricky:重點監控對象,不要讓它超過20MB,不然可能會有性能問題!性能優化

 

  • ShaderLab:Unity自帶的着色器語言工具相關資源。

 

Ricky:這個東西你們都比較熟悉了,忽略它吧。

 

  • SerializedFile:序列化文件,把顯示中的Prefab、Atlas和metadata等資源加載進內存。

 

Ricky:重點監控對象,這裏就是你要監控的哪些預設在序列化中在內存中佔用大小,根據需求進行優化。

 

 

  • PersistentManager.Remapper:持久化數據重映射管理相關

 

Ricky:與持久化數據相關,好比AssetBundle之類的。注意監控相關的文件。

 

  • ManagedHeap.ReservedUnusedSize:託管堆預留不使用內存大小,只由Mono使用。

 

Ricky:沒法優化。

  1. 許多貼圖採用的Format格式是ARGB 32 bit因此保真度很高但佔用的內存也很大。在不失真的前提下,適當壓縮貼圖,使用ARGB 16 bit就會減小一倍,若是繼續Android採用RGBA Compressed ETC2 8 bits(iOS採用RGBA Compressed PVRTC 4 bits),又能夠再減小一倍。把不須要透貼但有alpha通道的貼圖,全都轉換格式Android:RGB Compressed ETC 4 bits,iOS:RGB Compressed PVRTC 4 bits。
  2. 當加載一個新的Prefab或貼圖,不及時回收,它就會永駐在內存中,就算切換場景也不會銷燬。應該肯定物體再也不使用或長時間不使用就先把物體制空(null),而後調用Resources.UnloadUnusedAssets(),才能真正釋放內存。
  3. 有大量空白的圖集貼圖,能夠用TexturePacker等工具進行優化或考慮合併到其餘圖集中。

 

 

  • AudioManager:音頻管理器

 

Ricky:隨着音頻文件的增多而增大。

 

  • AudioClip:音效及聲音文件

 

Ricky:重點優化對象,播放時長較長的音樂文件須要進行壓縮成.mp3或.ogg格式,時長較短的音效文件能夠使用.wav 或.aiff格式。

 

  • Cubemap:立方圖紋理

 

Ricky:這個通常在天空盒中比較常見,我也不知道如何優化這個。。。

 

  • Mesh:模型網格

 

Ricky:主要檢查是否有重複的資源,還有儘可能減小點面數。

  • Mesh:場景中使用的網格模型

 

Ricky:注意網格模型的點面數,能合併的mesh儘可能合併。

1)ManagedHeap.UsedSize: 移動遊戲建議不要超過20MB.

2)SerializedFile: 經過異步加載(LoadFromCache、WWW等)的時候留下的序列化文件,可監視是否被卸載.

3)WebStream: 經過異步WWW下載的資源文件在內存中的解壓版本,比SerializedFile大幾倍或幾十倍,不過咱們如今項目中展現沒有。

4)Texture2D: 重點檢查是否有重複資源和超大Memory是否須要壓縮等.

5)AnimationClip: 重點檢查是否有重複資源.

6)Mesh: 重點檢查是否有重複資源.

1.Device.Present:

1)GPU的presentdevice確實很是耗時,通常出如今使用了很是複雜的shader.

2)GPU運行的很是快,而因爲Vsync的緣由,使得它須要等待較長的時間.

3)一樣是Vsync的緣由,但其餘線程很是耗時,因此致使該等待時間很長,好比:過量AssetBundle加載時容易出現該問題.

4)Shader.CreateGPUProgram:Shader在runtime階段(非預加載)會出現卡頓(華爲K3V2芯片).

5)StackTraceUtility.PostprocessStacktrace()和StackTraceUtility.ExtractStackTrace(): 通常是由Debug.Log或相似API形成,遊戲發佈後需將Debug API進行屏蔽。

2.Overhead:

1)通常狀況爲Vsync所致.

2)一般出如今Android設備上.

3.GC.Collect:

緣由:

1)代碼分配內存過量(惡性的)

2)必定時間間隔由系統調用(良性的).

佔用時間:

1)與現有Garbage size相關

2)與剩餘內存使用顆粒相關(好比場景物件過多,利用率低的狀況下,GC釋放後須要作內存重排)

4.GarbageCollectAssetsProfile:

1)引擎在執行UnloadUnusedAssets操做(該操做是比較耗時的,建議在切場景的時候進行)。

2)儘量地避免使用Unity內建GUI,避免GUI.Repaint過渡GCAllow.

3)if(other.tag == a.tag)改成other.CompareTag(a.tag).由於other.tag爲產生180B的GC Allow.

4)少用foreach,由於每次foreach爲產生一個enumerator(約16B的內存分配),儘可能改成for.

5)Lambda表達式,使用不當會產生內存泄漏.

5.儘可能少用LINQ:

1)部分功能沒法在某些平臺使用.

2)會分配大量GC Allow.

6.控制StartCoroutine的次數:

1)開啓一個Coroutine(協程),至少分配37B的內存.

2)Coroutine類的實例 -> 21B.

3)Enumerator -> 16B.

7.使用StringBuilder替代字符串直接鏈接.

8.緩存組件:

1)每次GetComponent均會分配必定的GC Allow.

2)每次Object.name都會分配39B的堆內存.

 
 
 
.框架設計層面。
 
一個相對中大型的遊戲,系統很是的多。這時候合理的適時的釋放內存有助於遊戲的正常體驗,甚至能夠防止內存快速到達峯值,致使設備Crash。
目前主流平臺機型可用內存:
Android平臺:在客戶端最低配置以上,均需知足如下內存消耗指標(PSS):
1)內存1G如下機型:最高PSS<=150MB
2)內存2G的機型:最高PSS<=200MB
iOS平臺:在iPhone4S下運行,消耗內存(real mem)不大於150MB

 

1.場景切換時避開峯值。
當前一個場景還未釋放的時候,切換到新的場景。這時候因爲兩個內存疊加很容易達到內存峯值。解決方案是,在屏幕中間遮蓋一個Loading場景。在舊的釋放完,而且新的初始化結束後,隱藏Loading場景,使之有效的避開內存大量疊加超過峯值。

 

2.GUI模塊加入生命週期管理。

 

主角、強化、技能、商城、進化、揹包、任務等等。一般一個遊戲都少不了這些系統。但要是所有都打開,或者這個時候再點世界地圖,外加一些邏輯數據內存的佔用等等。你會發現,內存也很快就達到峯值。
這時候有效的管理系統模塊生命週期就很是有必要。首先將模塊進行劃分:

 

1)常常打開 Cache_10;
2)偶爾打開 Cache_5;
3)只打開一次 Cache_0。

 

建立一個ModuleMananger 類,內部Render方法每分鐘輪詢一次。若是是「Cache_0」這個類型,一關閉就直接Destroy釋放內存;「Cache_10」這個類型爲10分鐘後自動釋放內存;" Cache_5"這種類型爲5分鐘後自動釋放內存。每次打開模塊,該模塊就會從新計時。這樣就能夠有效合理的分配內存。

 

 

 

一、  因爲實時對戰遊戲的數據包數量巨大,早期版本的幀同步策略會致使比較明顯的卡頓,經過進行數據包的合併與優化逐漸解決了卡頓問題;

二、  頻繁建立和銷燬的小兵對象讓CPU爆表了,大量的小兵若是採用實時內存的分配和回收,會產生大量的內存碎片和系統開銷,解決方法之一就是採用高效的對象池進行優化,對每一個內存對象的狀態進行操做便可;

三、  性能分析過程當中,發現單人同屏和多人同屏時的開銷都很大,經過視野裁剪技術,使得玩家視野外的沒必要要的特效和渲染能夠所有關閉,極大下降了CPU、GPU和內存的開銷;

四、  在高中低三檔機型上玩遊戲時,分別加載不一樣層次的特效包,這也有助於下降CPU和內存的開銷;性能分析過程當中發現副本內wwise音頻組件佔了30%的CPU時間,果斷拋棄之,採用Unity自帶音頻功能,優化很明顯;

五、  遊戲內界面採用了UGUI的方式實現,但大量的實時UI變化使得副本內每幀會有230以上的drawcall,致使中低端機型感覺到明顯卡頓,最終採用UGUI+自研究UI的組合拳,重寫了一套緊密結合遊戲自身特性的UI來實現戰鬥血條和浮動文字的效果。

六、    資源使用總量是否在合理範圍以內。

七、   一個場景內的資源重複率。

八、   資源對象拷貝的數量是否合理。

九、  場景切換時保留的資源詳情。

十、             網格、紋理、音頻、動畫、GameObject等資源是否超標。

 

十一、             貼圖:

十二、             l  控制貼圖大小,儘可能不要超過 1024x1024;

1三、             l  儘可能使用2的n次冪大小的貼圖,不然GfxDriver裏會有2份貼圖;

1四、             l  儘可能使用壓縮格式減少貼圖大小;

1五、             l  若干種貼圖合併技術;

1六、             l  去除多餘的alpha通道;

1七、             l  不一樣設備使用不一樣的紋理貼圖,分層顯示;

1八、              

1九、             模型:

20、             l  儘可能控制模型的面數,小於1500會比較合適;

2一、             l  不一樣設備使用不一樣的模型面數;

2二、             l  儘可能保持在30根骨骼內;

2三、             l  一個網格不要超過3個material;

2四、             動畫:

2五、             l  N種動畫壓縮方法;

2六、             l  儘可能減小骨骼數量;

2七、             聲音:

2八、             l  採用壓縮MP3 和 wav;

2九、             資源方面的優化:

30、             l  使用 Resource.Load 方法在須要的時候再讀取資源;

3一、             l  各類資源在使用完成後,儘快用Resource.UnloadAsset和UnloadUnusedAsset卸載掉;

3二、             l  靈活運用AssetBundle的Load和Unload方法動態加載資源,避免主要場景內的初始化內存佔用太高;(實現起來真的很難…)

3三、             l  採用www加載了AssetBundle後,要用www.Dispose 及時釋放;

3四、             l  在關卡內謹慎使用DontDestroyOnLoad,被標註的資源會常駐內存;

3五、             代碼的優化:

3六、             l  儘可能避免代碼中的任何字符串鏈接,由於這會給GC帶來太多垃圾;

3七、             l  用簡單的「for」循環代替「foreach」循環;

3八、             l  爲全部遊戲內的動態物體使用內存對象池,能夠減小系統開銷和內存碎片,複用對象實例,構建本身的內存管理模式,減小Instantiate和Destory;

3九、             l  儘可能不使用LINQ命令,由於它們通常會分配中間緩器,而這很容易生成垃圾內存;

40、             l  將引用本地緩存到元件中會減小每次在一個遊戲對象中使用 「GetComponent」 獲取一個元件引用的需求;

4一、             l  減小角色控制器移動命令的調用。移動角色控制器會同步發生,每次調用都會耗損較大的性能;

4二、             l  最小化碰撞檢測請求(例如raycasts和sphere checks),儘可能從每次檢查中得到更多信息;

4三、             l  AI邏輯一般會生成大量物理查詢,建議讓AI更新循環設置低於圖像更新循環,以減小CPU負荷;

4四、             l  要儘可能減小Unity回調函數,哪怕是空函數也不要留着;(例如空的Update、FixedUpdate函數)

4五、             l  儘可能少使用FindObjectsOfType函數,這個函數很是慢,儘可能少用且必定不要在Update裏調用;

4六、             l  千萬必定要控制mono堆內存的大小;

4七、              

4八、             unity3D 對於移動平臺的支持無可厚非,可是也有時候用Unity3D 開發出來的應用、遊戲在移動終端上的運行有着明顯的效率問題,好比卡、畫質等各類問題。本身在作遊戲開發的時候偶有所得。對於主要影響性能的因素作個總結。

4九、             

50、             主要因素有:

5一、                     1.      Savedby batching 值過大   ---- > 這個值主要是針對Mesh的批處理,這個值越高,應用就越卡   

5二、                     2.     Drawcall值過大 ---- >  Drawcall 值過大,所須要的 GPU 的處理性能較高,從而致使CPU的計算時間過長,因而就卡了

5三、                     3.     點、面過多           ----> 點、面過多,GPU 根據不一樣面的效果展開計算,而且CPU計算的數據也多,因此效果出來了,可是卡巴斯基

5四、             因爲 Saved by batching 和 Drawcall 值過大所引發的卡的問題我所作的優化方式有:

5五、                     1.    對於模型 :Mesh 合併,有個不錯的插件(DrawCallMinimizer   --->  直接上AssetStore 下載便可,免費的,並且有文檔,很容易上手)

5六、                     2.    對於UI  :  儘可能避免使用Unity3D自帶的 GUI 換用 NGUI或者EZGUI;由於這兩個UI插件對於UI中的圖片處理是將UI圖片放置在一個 Atlas中,一個 Atlas 對應一個Drawcall

5七、                     3.   對於燈光: 能夠使用 Unity3D 自帶的  Lightmapping插件來烘焙場景中的燈光效果到物體材質上 

5八、                     4.  對於場景: 能夠使用 Unity3D 自帶的 OcclusionCulling 插件把靜止不動的場景元素烘焙出來

5九、                     4.   對於特效:儘可能把材質紋理合並

60、             對於Unity3D 在移動終端上支持的Drawcall 數到底多少,主要是跟機子性能有關的,固然也不是說值小性能就必定沒問題(本人親測,也有17就卡的,主要是模型材質紋理過大所引發的),目前我作的是70左右的,還OK,挺正常的

6一、              

6二、             因爲點、面過多所致使的性能問題,最好用簡模,用四面體來作複雜的模型,可是面、點也別太多,至於Unity3D 到底支持多少點、面的說法各異,我也搞不懂,總之少些確定OK

6三、              

6四、              

6五、              

6六、             檢測方式:

6七、             一,Unity3D 渲染統計窗口

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

6九、             一、FPS

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

7一、              

7二、             二、Draw calls

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

7四、              

7五、             三、Saved by batching 

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

7七、             不少GUI插件的一個好處就是合併多個對象的渲染,從而下降DrawCalls ,保證遊戲幀數。

7八、              

7九、             四、Tris 當前繪製的三角面數

80、              

8一、             五、Verts 當前繪製的頂點數

8二、              

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

8四、              

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

8六、              

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

8八、              

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

90、              

9一、             十、VisibleSkinned Meshes 蒙皮網格的渲染數量

9二、              

9三、             十一、Animations 播放動畫的數量

9四、             注意事項:

9五、             1,運行時儘可能減小 Tris 和 Draw Calls

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

9七、             通常來講,要作到:

9八、             Tris 保持在 7.5k 如下,有待考證。

9九、             Draw Calls 保持在 20 如下,有待考證。

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

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

10二、          4,VRAM usage 顯存的使用狀況,VRAM總大小取決於你的顯卡的顯存。

10三、           

10四、          二,代碼優化

10五、          1. 儘可能避免每幀處理

10六、          好比:

10七、          function Update() {DoSomeThing(); }

10八、          可改成每5幀處理一次:

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

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

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

1十二、           

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

11四、           

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

11六、          函數裏面的變量儘可能在頭部聲明。

11七、          好比:

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

11九、          可改成

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

12一、           

12二、          4. 主動回收垃圾

12三、          給某個 GameObject 綁上如下的代碼:

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

12五、           

12六、          5. 優化數學計算

12七、          好比,若是能夠避免使用浮點型(float),儘可能使用整形(int),儘可能少用複雜的數學函數好比 Sin 和 Cos 等等

12八、           

12九、          6,減小固定增量時間

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

13一、          7,減小GetComponent的調用

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

13三、          function Update () {

13四、          transform.Translate(0, 1, 0);

13五、           

13六、          }

13七、          經過下面的更改您將得到更好的性能:

13八、           

13九、          var myTransform : Transform;

140、          function Awake () {

14一、          myTransform = transform;

14二、          }

14三、          function Update () {

14四、          myTransform.Translate(0, 1, 0);

14五、          }

14六、           

14七、          8,避免分配內存

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

14九、           

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

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

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

15三、           

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

15五、           

15六、          10,

15七、          優化垃圾回收

15八、           

15九、          如上文所述,您應該儘可能避免分配操做。可是,考慮到它們是不能徹底杜絕的,因此咱們提供兩種方法來讓您儘可能減小它們在遊戲運行時的使用:

160、          若是堆比較小,則進行快速而頻繁的垃圾回收

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

16二、          if (Time.frameCount % 30 == 0)

16三、          {

16四、          System.GC.Collect();

16五、          }

16六、           

16七、          可是,您應該當心地使用這種技術,而且經過檢查Profiler來確保這種操做確實能夠下降您遊戲的垃圾回收時間

16八、          若是堆比較大,則進行緩慢且不頻繁的垃圾回收

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

170、           

17一、          function Start() {

17二、           

17三、          var tmp = newSystem.Object[1024];

17四、           

17五、          // make allocations in smallerblocks to avoid them to be treated in a special way, which is designed forlarge blocks

17六、           

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

17八、           

17九、          tmp[i] = new byte[1024];

180、           

18一、          // release reference

18二、           

18三、          tmp = null;

18四、           

18五、          }

18六、           

18七、          遊戲中的暫停是用來對堆內存進行回收,而一個足夠大的堆應該不會在遊戲的暫停與暫停之間被徹底佔滿。因此,當這種遊戲暫停發生時,您能夠顯式請求一次垃圾回收:

18八、           

18九、          System.GC.Collect();

190、           

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

19二、           

19三、          三,模型

19四、          1,壓縮 Mesh

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

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

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

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

 

19九、           

200、          1不是每一個主流手機都支持的技術(就是若是能夠不用就不用或有備選方案)

20一、          屏幕特效

20二、          動態的pixel光照計算(如法線)

20三、          實時的陰影

20四、           

20五、          2優化建議

20六、          2.1渲染

20七、          1.不使用或少使用動態光照,使用light mapping和light probes(光照探頭)

20八、          2.不使用法線貼圖(或者只在主角身上使用),靜態物體儘可能將法線渲染到貼圖

20九、          3.不適用稠密的粒子,儘可能使用UV動畫

2十、          4.不使用fog,使用漸變的面片(參考shadowgun)

2十一、          5.不要使用alpha–test(如那些cutout shader),使用alpha-blend代替

2十二、          6.使用盡可能少的material,使用盡可能少的pass和render次數,如反射、陰影這些操做

21三、          7.若有必要,使用Per-LayerCull Distances,Camera.layerCullDistances

21四、          8.只使用mobile組裏面的那些預置shader

21五、          9.使用occlusionculling

21六、          11.遠處的物體繪製在skybox上

21七、          12.使用drawcallbatching:

21八、                  對於相鄰動態物體:若是使用相同的shader,將texture合併

21九、                  對於靜態物體,batching要求很高,詳見Unity Manual>Advanced>Optimizing Graphics Performance>Draw Call Batching

220、           

22一、          規格上限

22二、          1.      每一個模型只使用一個skinnedmesh renderer

22三、          2.      每一個mesh不要超過3個material

22四、          3.      骨骼數量不要超過30

22五、          4.      面數在1500之內將獲得好的效率

22六、          2.2物理

22七、          1.真實的物理(剛體)很消耗,不要輕易使用,儘可能使用本身的代碼模仿假的物理

22八、          2.對於投射物不要使用真實物理的碰撞和剛體,用本身的代碼處理

22九、          3.不要使用meshcollider

230、          4.在edit->projectsetting->time中調大FixedTimestep(真實物理的幀率)來減小cpu損耗

23一、          2.3腳本編寫

23二、          1.儘可能不要動態的instantiate和destroyobject,使用object pool

23三、          2.儘可能不要再update函數中作複雜計算,若有須要,能夠隔N幀計算一次

23四、          3.不要動態的產生字符串,如Debug.Log("boo"+ "hoo"),儘可能預先建立好這些字符串資源

23五、          4.cache一些東西,在update裏面儘可能避免search,如GameObject.FindWithTag("")、GetComponent這樣的調用,能夠在start中預先存起來

23六、          5.儘可能減小函數調用棧,用x= (x > 0 ? x : -x);代替x = Mathf.Abs(x)

23七、          6.下面的代碼是幾個gc「噩夢」

23八、           String的相加操做,會頻繁申請內存並釋放,致使gc頻繁,使用System.Text.StringBuilder代替

23九、             functionConcatExample(intArray: int[]) {

240、                         varline = intArray[0].ToString();

24一、           

24二、                         for(i = 1; i < intArray.Length; i++) {

24三、                                         line+= ", " + intArray[i].ToString();

24四、                         }

24五、           

24六、                         returnline;

24七、          }

24八、          在函數中動態new array,最好將一個array、傳進函數裏修改

24九、          functionRandomList(numElements: int) {

250、                    varresult = new float[numElements];

25一、           

25二、                    for(i = 0; i < numElements; i++) {

25三、                                   result[i]= Random.value;

25四、                    }

25五、           

25六、                    returnresult;

25七、          }

25八、           

25九、          2.4 shader編寫

260、          1.數據類型

26一、           fixed / lowp -for colors, lighting information and normals,

26二、          half / mediump -for texture UV coordinates,

26三、          float / highp -avoid in pixel shaders, fine to use in vertex shader for position calculations.

26四、          2.少使用的函數:pow,sin,cos等

26五、          2.4 GUI

26六、          1.不要使用內置的onGUii函數處理gui,使用其餘方案,如NGUI

26七、           

26八、          3.格式

26九、          1.貼圖壓縮格式:ios上儘可能使用PVRTC,android上使用ETC

 

 

270、          最簡單的優化建議:

1.PC平臺的話保持場景中顯示的頂點數少於200K~3M,移動設備的話少於10W,一切取決於你的目標GPU與CPU。
2.若是你用U3D自帶的SHADER,在表現不差的狀況下選擇Mobile或Unlit目錄下的。它們更高效。
3.儘量共用材質。
4.將不須要移動的物體設爲Static,讓引擎能夠進行其批處理。
5.儘量不用燈光。
6.動態燈光更加不要了。
7.嘗試用壓縮貼圖格式,或用16位代替32位。
8.若是不須要別用霧效(fog)
9.嘗試用OcclusionCulling,在房間過道多遮擋物體多的場景很是有用。若不當反而會增長負擔。
10.用天空盒去「褪去」遠處的物體。
11.shader中用貼圖混合的方式去代替多重通道計算。
12.shader中注意float/half/fixed的使用。
13.shader中不要用複雜的計算pow,sin,cos,tan,log等。
14.shader中越少Fragment越好。
15.注意是否有多餘的動畫腳本,模型自動導入到U3D會有動畫腳本,大量的話會嚴重影響消耗CPU計算。
16.注意碰撞體的碰撞層,沒必要要的碰撞檢測請捨去。


1.爲何須要針對CPU(中央處理器)與GPU(圖形處理器)優化?

CPU和GPU都有各自的計算和傳輸瓶頸,不一樣的CPU或GPU他們的性能都不同,因此你的遊戲須要爲你目標用戶的CPU與GPU能力進行鍼對開發。


2.CPU與GPU的限制

GPU通常具備填充率(Fillrate)和內存帶寬(Memory Bandwidth)的限制,若是你的遊戲在低質量表現的狀況下會快不少,那麼,你極可能須要限制你在GPU的填充率。

CPU通常被所須要渲染物體的個數限制,CPU給GPU發送渲染物體命令叫作DrawCalls。通常來講DrawCalls數量是須要控制的,在能表現效果的前提下越少越好。一般來講,電腦平臺上DrawCalls幾千個以內,移動平臺上DrawCalls幾百個以內。這樣就差很少了。固然以上並非絕對的,僅做一個參考。

每每渲染(Rendering)並非一個問題,不管是在GPU和CPU上。極可能是你的腳本代碼效率的問題,用Profiler查看下。

關於Profiler介紹:http://docs.unity3d.com/Documentation/Manual/Profiler.html

須要注意的是:
在GPU中顯示的RenderTexture.SetActive()佔用率很高,是由於你同時打開了編輯窗口的緣由,而不是U3D的BUG。

3.關於頂點數量和頂點計算

CPU和GPU對頂點的計算處理都不少。GPU中渲染的頂點數取決於GPU性能和SHADER的複雜程度,通常來講,每幀以內,在PC上幾百萬頂點內,在移動平臺上不超過10萬頂點。

CPU中的計算主要是在蒙皮骨骼計算,布料模擬,頂點動畫,粒子模擬等。GPU則在各類頂點變換、光照、貼圖混合等。

【我的認爲,具體仍是看各位的項目需求,假設你項目的是3d遊戲。你遊戲須要兼容低配置的硬件、流暢運行、控制硬件發熱的話,還要達到必定效果(LIGHTMAP+霧效),那麼頂點數一定不能高。此時同屏2W頂點我認爲是個比較合適的數目,DRAWCALL最好低於70。另,控制發熱請控制最高上限的幀率,流暢的話,幀率其實不須要過高的。】



4.針對CPU的優化——減小DRAW CALL 的數量

爲了渲染物體到顯示器上,CPU須要作一些工做,如區分哪一個東西須要渲染、區分開物體是否受光照影響、使用哪一個SHADER而且爲SHADER傳參、發送繪圖命令告訴顯示驅動,而後發送命令告訴顯卡刪除等這些。

假設你有一個上千三角面的模型卻用上千個三角型模型來代替,在GPU上花費是差很少的,可是在CPU上則是極其不同,消耗會大不少不少。爲了讓CPU更少的工做,須要減小可見物的數目:

a.合併相近的模型,手動在模型編輯器中合併或者使用UNITY的Draw call批處理達到相同效果(Draw call batching)。具體方法和注意事項查看如下連接:

Draw call batching :http://docs.unity3d.com/Documentation/Manual/DrawCallBatching.html


b.在項目中使用更少的材質(material),將幾個分開的貼圖合成一個較大的圖集等方式處理。

若是你須要經過腳原本控制單個材質屬性,須要注意改變Renderer.material將會形成一份材質的拷貝。所以,你應該使用Renderer.sharedMaterial來保證材質的共享狀態。

有一個合併模型材質不錯的插件叫Mesh Baker,你們能夠考慮試下。

c.儘可能少用一些渲染步驟,例如reflections,shadows,per-pixel light 等。

d.Draw call batching的合併物體,會使每一個物體(合併後的物體)至少有幾百個三角面。

假設合併的兩個物體(手動合併)但不共享材質,不會有性能表現上的提高。多材質的物體至關於兩個物體不用一個貼圖。因此,爲了提高CPU的性能,你應該確保這些物體使用一樣的貼圖。

另外,用燈光將會取消(break)引擎的DRAW CALL BATCH,至於爲何,查看如下:

Forward Rendering Path Details:
http://docs.unity3d.com/Documentation/Components/RenderTech-ForwardRendering.html

e.使用相關剔除數量直接減小Draw Call數量,下文有相關說起。


5.優化幾何模型

最基本的兩個優化準則:
a.不要有沒必要要的三角面。
b.UV貼圖中的接縫和硬邊越少越好。

須要注意的是,圖形硬件須要處理頂點數並跟硬件報告說的並不同。不是硬件說能渲染幾個點就是幾個點。模型處理應用通展現的是幾何頂點數量。例如,一個由一些不一樣頂點構成的模型。在顯卡中,一些集合頂點將會被分離(split)成兩個或者更多邏輯頂點用做渲染。若是有法線、UV座標、頂點色的話,這個頂點必須會被分離。因此在遊戲中處理的實際數量顯然要多不少。


6.關於光照

若不用光確定是最快的。移動端優化能夠採用用光照貼圖(Lightmapping)去烘培一個靜態的貼圖,以代替每次的光照計算,在U3D中只須要很是短的時間則能生成。這個方法能大大提升效率,並且有着更好的表現效果(平滑過渡處理,還有附加陰影等)。

在移動設備上和低端電腦上儘可能不要在場景中用真光,用光照貼圖。這個方法大大節省了CPU和GPU的計算,CPU獲得了更少的DRAWCALL,GPU則須要更少頂點處理和像素柵格化。

Lightmapping : http://docs.unity3d.com/Documentation/Manual/Lightmapping.html


7.對GPU的優化——圖片壓縮和多重紋理格式

Compressed Textures(圖片壓縮):

http://docs.unity3d.com/Documentation/Components/class-Texture2D.html

圖片壓縮將下降你的圖片大小(更快地加載更小的內存跨度(footprint)),並且大大提升渲染表現。壓縮貼圖比起未壓縮的32位RGBA貼圖佔用內存帶寬少得多。

以前U3D會議還據說過一個優化,貼圖儘可能都用一個大小的格式(512 * 512 , 1024 * 1024),這樣在內存之中能獲得更好的排序,而不會有內存之間空隙。這個是否真假沒獲得過測試。

MIPMAps(多重紋理格式):

http://docs.unity3d.com/Documentation/Components/class-Texture2D.html

跟網頁上的略縮圖原理同樣,在3D遊戲中咱們爲遊戲的貼圖生成多重紋理貼圖,遠處顯示較小的物體用小的貼圖,顯示比較大的物體用精細的貼圖。這樣能更加有效的減小傳輸給GPU中的數據。


8.LOD 、 Per-Layer Cull Distances 、 Occlusion Culling

LOD (Level Of Detail) 是很經常使用的3D遊戲技術了,其功能理解起來則是至關於多重紋理貼圖。在以在屏幕中顯示模型大小的比例來判斷使用高或低層次的模型來減小對GPU的傳輸數據,和減小GPU所須要的頂點計算。

攝像機分層距離剔除(Per-Layer Cull Distances):爲小物體標識層次,而後根據其距離主攝像機的距離判斷是否須要顯示。

遮擋剔除(Occlusion Culling)其實就是當某個物體在攝像機前被另一個物體徹底擋住的狀況,擋住就不發送給GPU渲染,從而直接下降DRAW CALL。不過有些時候在CPU中計算其是否被擋住則會很耗計算,反而得不償失。

如下是這幾個優化技術的相關使用和介紹:

Level Of Detail :
http://docs.unity3d.com/Documentation/Manual/LevelOfDetail.html

Per-Layer Cull Distances :
http://docs.unity3d.com/Documentation/ScriptReference/Camera-layerCullDistances.html

Occlusion Culling :
http://docs.unity3d.com/Documentation/Manual/OcclusionCulling.html


9.關於Realtime Shadows(實時陰影)

實時陰影技術很是棒,但消耗大量計算。爲GPU和CPU都帶來了昂貴的負擔,細節的話參考下面:

http://docs.unity3d.com/Documentation/Manual/Shadows.html


10.對GPU優化:採用高效的shader

a.須要注意的是有些(built-in)Shader是有mobile版本的,這些大大提升了頂點處理的性能。固然也會有一些限制。

b.本身寫的shader請注意複雜操做符計算,相似pow,exp,log,cos,sin,tan等都是很耗時的計算,最多隻用一次在每一個像素點的計算。不推薦你本身寫normalize,dot,inversesqart操做符,內置的確定比你寫的好。

c.須要警醒的是alpha test,這個很是耗時。

d.浮點類型運算:精度越低的浮點計算越快。

在CG/HLSL中--

float :32位浮點格式,適合頂點變換運算,但比較慢。
half:16位浮點格式,適合貼圖和UV座標計算,是highp類型計算的兩倍。
fixed: 10位浮點格式,適合顏色,光照,和其餘。是highp格式計算的四倍。

寫Shader優化的小提示:
http://docs.unity3d.com/Documentation/Components/SL-ShaderPerformance.html


11.另外的相關優化:

a.對Draw Call Batching的優化
http://docs.unity3d.com/Documentation/Manual/DrawCallBatching.html

b.對Rendering Statistics Window的說明和提示:
http://docs.unity3d.com/Documentation/Manual/RenderingStatistics.html

c.角色模型的優化建議
用單個蒙皮渲染、儘可能少用材質、少用骨骼節點、移動設備上角色多邊形保持在300~1500內(固然還要看具體的需求)、PC平臺上1500~4000內(固然還要看具體的需求)。

http://docs.unity3d.com/Documentation/Manual/ModelingOptimizedCharacters.html

 

 

 

渲染順序

U3D的渲染是有順序的,U3D的渲染順序是由咱們控制的,控制好U3D的渲染順序,你才能控制好DrawCall

一個DrawCall,表示U3D使用這個材質/紋理,來進行一次渲染,那麼此次渲染假設有3個對象,那麼當3個對象都使用這一個材質/紋理的 時候,就會產生一次DrawCall,能夠理解爲一次將紋理輸送到屏幕上的過程,(實際上引擎大多會使用如雙緩衝,緩存這類的手段來優化這個過程,但在這 裏咱們只須要這樣子認識就能夠了),假設3個對象使用不一樣的材質/紋理,那麼無疑會產生3個DrawCall

接下來咱們的3個對象使用2個材質,A和B使用材質1,C使用材質2,這時候來看,應該是有2個DrawCall,或者3個DrawCall。 應該是2個DrawCall啊,爲何會有3個DrawCall???並且是有時候2個,有時候3個。咱們按照上面的DrawCall分析流程來分析一 下:

1.渲染A,使用材質1 
2.渲染B,使用材質1 
3.渲染C,使用材質2

在這種狀況下是2個DrawCall,在下面這種狀況下,則是3個DrawCall

1.渲染A,使用材質1 
2.渲染C,使用材質2 
3.渲染B,使用材質1

由於咱們沒有控制好渲染順序(或者說沒有去特地控制),因此致使了額外的DrawCall,由於A和B不是一次性渲染完的,而是被C打斷了,因此致使材質1被分爲兩次渲染

那麼是什麼在控制這個渲染順序呢?首先在多個相機的狀況下,U3D會根據相機的深度順序進行渲染,在每一個相機中,它會根據你距離相機的距離,由遠到近進行渲染,在UI相機中,還會根據你UI對象的深度進行渲染

那麼咱們要作的就是,對要渲染的對象進行一次規劃,正確地排列好它們,規則是,按照Z軸或者深度,對空間進行劃分,而後肯定好每一個對象的Z軸和深度,讓使用同一個材質的東西,儘可能保持在這個空間內,不要讓其餘材質的對象進入這個空間,不然就會打斷這個空間的渲染順序

在這個基礎上,更細的規則有:

場景中的東西,咱們使用Z軸來進行空間的劃分,例如背景層,特效層1,人物層,特效層2 
NGUI中的東西,咱們統一使用Depth來進行空間的劃分 
人物模型,當人物模型只是用一個材質,DrawCall只有1,可是用了2個以上的材質,DrawCall就會暴增(或許對材質的RenderQueue 進行規劃也能夠使DrawCall只有2個,但這個要拆分好才行),3D人物處於複雜3D場景中的時候,咱們的空間規則不免被破壞,這隻能在設計的時候盡 量去避免這種狀況了 
使用了多個材質的特效,在動畫的過程當中,每每會引發DrawCall的波動,在視覺效果能夠接受的範圍內,能夠將特效也進行空間劃分,假設這個特效是2D顯示,那麼能夠使用Z軸來劃分空間

 

2、

優化: 

1. 更新不透明貼圖的壓縮格式爲ETC 4bit,由於android市場的手機中的GPU有多種,
每家的GPU支持不一樣的壓縮格式,但他們都兼容ETC格式,

2. 對於透明貼圖,咱們只能選擇RGBA 16bit 或者RGBA 32bit。

3. 減小FPS,在ProjectSetting-> Quality中的
VSync Count 參數會影響你的FPS,EveryVBlank至關於FPS=60,EverySecondVBlank = 30;
這兩種狀況都不符合遊戲的FPS的話,咱們須要手動調整FPS,首先關閉垂直同步這個功能,而後在代碼的Awake方法裏手動設置FPS(Application.targetFrameRate = 45;)
下降FPS的好處:
1)省電,減小手機發熱的狀況;
2)能都穩定遊戲FPS,減小出現卡頓的狀況。

4. 當咱們設置了FPS後,再調整下Fixed timestep這個參數,
這個參數在ProjectSetting->Time中,目的是減小物理計算的次數,來提升遊戲性能。

5. 儘可能少使用Update LateUpdate FixedUpdate,這樣也能夠提高性能和節省電量。
多使用事件(不是SendMessage,使用本身寫的,或者C#中的事件委託)。

6. 待機時,調整遊戲的FPS爲1,節省電量。

7. 圖集大小最好不要高於1024,不然遊戲安裝以後、低端機直接崩潰、緣由是手機系統版本低於2.二、超過1000的圖集沒法讀取、致使。
2.2 以上沒有碰見這個狀況。
注意手機的RAM 與 ROM、小於 512M的手機、直接放棄機型適配。

VSCount 垂直同步
   中新建一個場景空的時候,幀速率(FPS老是很低),大概在60~70之間。
一直不太明白是怎麼回事,如今基本上明白了。我在這裏解釋一下緣由,若有錯誤,歡迎指正。
在Unity3D中當運行場景打開Profiler的時候,咱們會看到VSync 這一項佔了很大的比重。
這個是什麼呢,這個就是垂直同步,稍後再作解釋。
咱們能夠關閉VSync來提升幀速率,選擇edit->project settings->Quality。

<ignore_js_op>

 


在右側面板中能夠找到VSync Count,把它選成Don't Sync。
<ignore_js_op> 
這就關閉了VSync(垂直同步),如今在運行場景看看,幀速率是否是提升不少。

如今來講說什麼是垂直同步,要知道什麼是垂直同步,必需要先明白顯示器的工做原理,
顯示器上的全部圖像都是一線一線的掃描上去的,不管是隔行掃描仍是逐行掃描,
顯示器都有兩種同步參數——水平同步和垂直同步。

什麼叫水平同步?什麼叫垂直同步?
垂直和水平是CRT中兩個基本的同步信號,水平同步信號決定了CRT畫出一條橫越屏幕線的時間,
垂直同步信號決定了CRT從屏幕頂部畫到底部,再返回原始位置的時間,
而偏偏是垂直同步表明着CRT顯示器的刷新率水平。

爲何關閉垂直同步信號會影響遊戲中的FPS數值?
若是咱們選擇等待垂直同步信號(也就是咱們平時所說的垂直同步打開),
那麼在遊戲中或許強勁的顯卡迅速的繪製完一屏的圖像,可是沒有垂直同步信號的到達,
顯卡沒法繪製下一屏,只有等85單位的信號到達,才能夠繪製。
這樣FPS天然要受到操做系統刷新率運行值的制約。

而若是咱們選擇不等待垂直同步信號(也就是咱們平時所說的關閉垂直同步),那麼遊戲中做完一屏畫面,
顯卡和顯示器無需等待垂直同步信號就能夠開始下一屏圖像的繪製,天然能夠徹底發揮顯卡的實力。
可是不要忘記,正是由於垂直同步的存在,才能使得遊戲進程和顯示器刷新率同步,使得畫面更加平滑和穩定。
取消了垂直同步信號,當然能夠換來更快的速度,可是在圖像的連續性上勢必打折扣。
這也正是不少朋友抱怨關閉垂直後發現畫面不連續的理論緣由。

合併材質球unity 3d中每倒入一次模型就多一個材質球,可個人這些模型都是共用一張貼圖的就想共用一個材質球,因此每次都要刪除再附上,很麻煩。怎麼才能合併這些材質球?
採用TexturePacking吧
一、遍歷gameobject,取出material,並根據shader來將material分類
二、調用Unity自帶的PackTextures函數來合併每一個shader分類中的material所對應的textures(PackTextures函數有缺陷,不過能夠將就用)
三、根據合併的大的texture來更新原有模型的texture、material已經uv座標值。

須要注意的是:須要合併的紋理應該是物體在場景中距離相近的,若是物體在場景中的距離較遠,
則不建議合併紋理,由於這樣作頗有可能非但起不到優化的做用,反而下降了運行效率。 

mesh合併 
分爲2種方式合併
1.自帶的合併必須勾選靜態。
<ignore_js_op> 
全部被勾選了「Static」的GameObject,其中的Mesh Filter中的mesh都會被合併到 "Combined Mesha (root: scene)" 中


2.也能夠用腳原本合併mesh 。

[C#]  純文本查看 複製代碼
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
using UnityEngine;
using System.Collections;
 
public class MyClass : MonoBehaviour
{
     void Start ()
     {
         MeshFilter [] meshFilters = GetComponentsInChildren<MeshFilter> ();
         CombineInstance[] combine = new CombineInstance[meshFilters.Length];
 
         for ( int i = 0; i < meshFilters.Length; i++) {
             combine [i].mesh = meshFilters [i].sharedMesh;
             combine [i].transform = meshFilters [i].transform.localToWorldMatrix;
             meshFilters [i].gameObject.active = false ;
         }
 
             transform.GetComponent<MeshFilter> ().mesh = new Mesh ();
             transform.GetComponent<MeshFilter> ().mesh.CombineMeshes (combine);
             transform.gameObject.active = true ;
     }
}


1. 先在 Unity 中創建 空物件 ( Empty ) 
2. 再建立2個 Cube 方塊,並放入 空物件底下 (能夠改爲你本身的模型)
3. 把 MyClass 代碼丟進 空物件上 。
4. (可選) 創建一個 Material 材質,而且丟進 空物件上
5. 執行

<ignore_js_op> 


<ignore_js_op> 
========================================分割線====================================

  • 角色Material數量
2-3
  • 骨骼數量
小於30個
  • 面片數量
300-1500
  • 通常角色應該沒有IK結點
這是由於角色的動做大多數都是事先設定好的,並不須要通過IK操做來進行實時計算(Rogdoll除外),因此在模型導入時,不要將IK結點一塊兒導入。

 

二、靜態實體

  • 不要附加 Component
在靜態實體上附加Animation部件雖然對結果沒有影響,但卻會增長必定的CPU開銷來調用這一組件,因此儘可能去掉該組件。
  • 網格頂點數
小於500
  • UV值範圍儘可能不要超過(0, 1)區間
儘可能保證UV值不越界,這對於未來的紋理拼合優化頗有幫助。

 

三、地形

  • 地形的分辨率大小
長寬均儘可能小於257。這是由於地形太大,會形成大量頂點數據,給你的內存帶寬形成必定的影響,在目前的ios設備中,內存帶寬是很是有限的,須要儘可能節省。同時,若是用Unity自帶的地形,必定也要使用Occlusion Culling,由於Unity的刷地形工具雖然方便,但倒是framekiller,刷過以後,你會發現drawcall增長的很是多。
  • 混合紋理數量
不要超過4。地形的混合操做是很耗時的,應該儘可能避免。能合併的紋理儘可能合併。

 

四、紋理

  • 紋理格式
建議png或tga。不用轉成ios硬件支持的PVRTC格式,由於Unity在發佈時會幫你自動轉的。
  • 紋理尺寸
長寬小於1024。同時應該儘量地小,夠用就好,以保證紋理對內存帶寬的影響達到最小。
  • 支持Mipmap
建議生成Mipmap。雖然這種作法會增長一些應用程序的大小,但在遊戲運行時,系統會根據需求應用Mipmap來渲染,從而減小內存帶寬。
  • 檢查Alpha值
若是紋理的alpha通道均爲1,則用RGB的24位紋理來代替RGBA的32位紋理。(聽說Unity內部會進行自動檢測)

 

五、光源

  • 光源「Important」個數
建議1個,通常爲方向光。「Important」個數應該越小越少。個數越多,drawcall越多。
  • Pixel Light數目
1-2個。

 

六、粒子特效

  • 屏幕上的最大粒子數
建議小於200個粒子。
  • 每一個粒子發射器發射的最大粒子數
建議不超過50個。
  • 粒子大小
若是能夠的話,粒子的size應該儘量地小。由於Unity的粒子系統的shader不管是alpha test仍是alpha blending都是一筆不小的開銷。同時,對於很是小的粒子,建議粒子紋理去掉alpha通道。
  • 儘可能不要開啓粒子的碰撞功能。
很是耗時。

 

七、音頻

  • 遊戲中播放時間較長的音樂(如背景音樂)
使用.ogg或.mp3的壓縮格式。
  • 較短音樂(如槍聲)
使用.wav和.aif的未壓縮音頻格式。

 

八、相機

  • 裁剪平面
將遠平面設置成合適的距離。遠平面過大會將一些沒必要要的物體加入渲染,下降效率。
  • 根據不一樣的物體設置不一樣的遠裁剪平面
Unity提供了能夠根據不一樣的layer來設置不一樣的view distance,因此咱們能夠實現將物體進行分層,大物體層設置的可視距離大些,而小物體層能夠設置地小些,另外,一些開銷比較大的實體(如粒子系統)能夠設置得更小些等等。

 

九、碰撞

  • 儘可能不用MeshCollider
若是能夠的話,儘可能不用MeshCollider,以節省沒必要要的開銷。若是不能避免的話,儘可能用減小Mesh的面片數,或用較少面片的代理體來代替。

 

十、其餘

  • Drawcall
儘量地減小Drawcall的數量。IOS設備上建議不超過100。減小的方法主要有以下幾種:Frustum Culling,Occlusion Culling,Texture Packing。Frustum Culling是Unity內建的,咱們須要作的就是尋求一個合適的遠裁剪平面;Occlusion Culling,遮擋剔除,Unity內嵌了Umbra,一個很是好OC庫。但Occlusion Culling也並非放之四海而皆準的,有時候進行OC反而比不進行還要慢,建議在OC以前先肯定本身的場景是否適合利用OC來優化;Texture Packing,或者叫Texture Atlasing,是將同種shader的紋理進行拼合,根據Unity的static batching的特性來減小draw call。建議使用,但也有弊端,那就是必定要將場景中距離相近的實體紋理進行拼合,不然,拼合後極可能會增長每幀渲染所需的紋理大小,加大內存帶寬的負擔。這也就是爲何會出現「DrawCall降了,渲染速度也變慢了」的緣由。

 

  • 非運動物體儘可能打上Static標籤
Unity在運行時會對static物體進行自動優化處理,因此應該儘量將非運行實體勾上static標籤。

 

  • 場景中儘量地使用prefab
儘量地使用prefab的實例化物體,以下降內存帶寬的負擔。檢查實體的PrefabType,儘可能將其變成PrefabInstance,而不是ModelPrefabInstance。



========================================分割線==================================== 

移動平臺相對於PC機,具備體積小,計算弱,帶寬少的特色。

所以作手機遊戲的開發,優化的方向,與力度對比PC遊戲都有所區別。

 

必需要作到優化流程,合理利用資源。

目前在手機上面,還不可以像PC遊戲那樣追求高質量渲染效果,爲了讓手機不那麼容易發燙,還要控制cpu,gpu,不能讓他們全速運算。

 

材質方面:

紋理方面,建議使用壓縮紋理,

上面使用ETC1,蘋果上面使用PVRTC。

 

UV座標控制在0到1之間,人物模型面數控制在1500內,骨骼控制在30個之內。

場景中使用一個主光(不能再多了)。

 

儘可能減小alphaTest和alphaBlend材質的使用。在手機上,這是很殺效率的。

 

骨骼動畫方面:

在動畫方面能夠考慮不使用插值,固定的幀率的動畫。

若是要作插值,考慮使用四元數(表示旋轉)和向量(表示位移)來作插值。

四元數作插值速度比矩陣來的快,Slerp提供了平滑插值。



========================================分割線==================================== 

優化的常規技巧
剖析你的遊戲。
不要花費時間來優化那些晦澀的代碼或者縮減圖形文件的大小,除非這是你遊戲的瓶頸。
第一次剖析你的遊戲將會使你發現你遊戲的瓶頸。Apple's Shark是一個很好的用來剖析基於OpenGL的程序的工具。
再次剖析你的遊戲。
優化以後不要忘記再剖析一次你的遊戲,這樣能夠檢查你所作的優化是否達到了預期的效果。
固然,這樣作也可能會使你發現更多的瓶頸。
流程第1、性能第二。花費時間來使你遊戲的建立儘量地流暢。
儘量快地修正遊戲中的錯誤將會使你後期更容易優化你的遊戲。
在Scene View中測試場景。
這樣作將會使你清楚瞭解這個場景中的物體或者附加在物體上的腳本是否下降了遊戲性能。
若是Scene View反應遲鈍,那麼有多是圖形方面的緣由,若是Scene View反應不遲鈍,那麼瓶頸可能出在腳本或者物理系統上。
禁用指定遊戲物體。
在play模式下,嘗試禁用並啓用遊戲物體來排查出遊戲慢的緣由。

網格
若是可能的話,把相鄰的物體(網格)合併爲一個只有一個材質的物體(網格)。好比,你的遊戲中包含一個桌子,上面有一堆東西,你徹底能夠在3D程序中將它們合併在一塊兒(這可能也須要你將這些物體的紋理合併爲一個大的紋理集)。減小須要渲染的物體的數量能夠極大地提升遊戲性能。

不要有沒必要要的網格。
若是你的遊戲場景中有一我的物,那麼他應該是一個網格。若是你有一個船,那麼它也應該只是一個網格。
每個網格只用一種材質。
使用極少的面數的網格(好比500個多邊形如下)。
最好把你人物的三角面數量控制在1500-2000個之間。
這個數量能夠說是遊戲質量和性能之間一個均衡值。若是你的模型有四邊形,那麼在導入模型的時候,引擎將會把每一個四邊形變爲兩個三角形。

光照
像素光。
像素光可讓你的遊戲看起來效果很牛逼,可是不要使用過多的像素光。
在你的遊戲中能夠使用質量管理器來調節像素光的數量來取得一個性能和質量的均衡點.

性能佔用順序:聚光燈>點光源>平行光。
一個好的點亮場景的方法就是先獲得你想要的效果,而後看看哪些光更重要;
在保持光效的前提下看看哪些光能夠去掉。

點光源和聚光燈隻影響它們範圍內的網格。
若是一個網格處於點光源或者聚光燈的照射範圍以外,而且光源的attenuate開關是打開的,那麼這個網格將不會被光源所影響,這樣就能夠節省性能開銷。
這樣作理論上來說能夠使用不少小的點光源並且依然能有一個好的性能,由於這些光源隻影響一小部分物體。
一個網格在有8個以上光源影響的時候,只響應前8個最亮的光源。

貼圖
在外觀不變的前提下,貼圖大小越小越好。
若是你的顯卡的顯存不夠大的話,你遊戲中的貼圖將會被轉存到系統內存中,在顯卡調用它們的時候再傳到顯卡中。
對於比較新的電腦來講,內存和顯卡之間有足夠的帶寬來達到一個很好的性能;
若是你很無恥地用了巨多的大圖片的話,在低顯存的電腦上運行你的遊戲的時候,你的遊戲必然會掛掉。
卻是沒有必要在圖形編輯軟件中調整貼圖的大小。你能夠在unity導入貼圖的時候進行調整。

不要使用低質量的圖片。
在小播放界面的遊戲中使用低質量的jpeg圖片或者低色彩的png圖片亦或是gif圖片沒什麼問題
在發佈遊戲的時候,引擎會自動壓縮這些圖片,多重壓縮和解壓將會下降圖片的質量,因此最好保持貼圖文件的分辨率爲原始分辨率。
這樣就會減小多重壓縮和解壓所致使的圖片失真現象。

Shaders
多重效果的shader就比看起來樣式很單一的shader要更耗費資源。
一樣在一個擁有貼圖和光反射的物體上,使用VertexLit Diffuse shader無疑是最省資源的。


========================================分割線==================================== 

在美術製做場景的過程當中,會使用到大量的粒子系統。
好比場景中的火把。在咱們的一個地下城場景中,美術們放置了大量的火把。整個場景中的各個地方,有100來個火把。

unity中,在攝像機範圍外的粒子系統雖然不會被繪製。
可是update是一直持續的。這也就意味着,這100多個火把,不管是否可見都在更新。

這個設計應該是很不合理的,在我看過的其餘引擎中,都會有一個開關,來控制不可見的粒子系統是否須要update。
有的粒子系統在不可見的時候須要更新,好比爆炸。有的不須要更新,好比火堆火把。

爲了不沒必要要的update開銷,尤爲是最後遊戲是要發佈到頁遊平臺(web player只能使用一個cpu的核)。
因而寫了一個腳本,控制不可見的粒子系統就不更新。

該腳本主要是用到了2個MonoBehaviour的函數。
OnBecameInvisible() 當變爲不可見   和   OnBecameVisible() 當變成可見。 

要這2個函數起做用的前提是,該GameObject綁定了MeshRender組件。
因此,咱們要在粒子系統的GameObject放置在一個GameObject  下,且給該GameObject綁定一個MeshRender 與 MeshFilter。
MeshFilter中的mesh能夠隨便找個cube。

在Start() 的時候,把最GameObject的scale設置爲很小,以保證該cube不被看見。
其實遍歷全部的child,把active設置爲false。

在OnBecameVisible 中 遍歷全部child,把active設置爲true。
在OnBecameInvisible中 遍歷全部child,把active設置爲false。


========================================分割線==================================== 

Unity 性能優化 Draw Call 

Unity(或者說基本全部圖形引擎)生成一幀畫面的處理過程大體能夠這樣簡化描述:引擎首先通過簡單的可見性測試,肯定攝像機能夠看到的物體,而後把這些物體的頂點(包括本地位置、法線、UV等),索引(頂點如何組成三角形),變換(就是物體的位置、旋轉、縮放、以及攝像機位置等),相關光源,紋理,渲染方式(由材質/Shader決定)等數據準備好,而後通知圖形API——或者就簡單地看做是通知GPU——開始繪製,GPU基於這些數據,通過一系列運算,在屏幕上畫出成千上萬的三角形,最終構成一幅圖像。

在Unity中,每次引擎準備數據並通知GPU的過程稱爲一次Draw Call。這一過程是逐個物體進行的,對於每一個物體,不僅GPU的渲染,引擎從新設置材質/Shader也是一項很是耗時的操做。所以每幀的Draw Call次數是一項很是重要的性能指標,對於iOS來講應儘可能控制在20次之內,這個值能夠在編輯器的Statistic窗口看到。

Unity內置了Draw Call Batching技術,從名字就能夠看出,它的主要目標就是在一次Draw Call中批量處理多個物體。只要物體的變換和材質相同,GPU就能夠按徹底相同的方式進行處理,便可以把它們放在一個Draw Call中。Draw Call Batching技術的核心就是在可見性測試以後,檢查全部要繪製的物體的材質,把相同材質的分爲一組(一個Batch),而後把它們組合成一個物體(統一變換),這樣就能夠在一個Draw Call中處理多個物體了(其實是組合後的一個物體)。

但Draw Call Batching存在一個缺陷,就是它須要把一個Batch中的全部物體組合到一塊兒,至關於建立了一個與這些物體加起來同樣大的物體,與此同時就須要分配相應大小的內存。這不只會消耗更多內存,還須要消耗CPU時間。特別是對於移動的物體,每一幀都得從新進行組合,這就須要進行一些權衡,不然得不償失。但對於靜止不動的物體來講,只須要進行一次組合,以後就能夠一直使用,效率要高得多。

Unity提供了Dynamic Batching和Static Batching兩種方式。Dynamic Batching是徹底自動進行的,不須要也沒法進行任何干預,對於頂點數在300之內的可移動物體,只要使用相同的材質,就會組成Batch。Static Batching則須要把靜止的物體標記爲Static,而後不管大小,都會組成Batch。如前文所說,Static Batching顯然比Dynamic Batching要高效得多,因而,Static Batching功能是收費的……

要有效利用Draw Call Batching,首先是儘可能減小場景中使用的材質數量,即儘可能共享材質,對於僅紋理不一樣的材質能夠把紋理組合到一張更大的紋理中(稱爲Texture Atlasing)。而後是把不會移動的物體標記爲Static。此外還能夠經過CombineChildren腳本(Standard Assets/Scripts/Unity Scripts/CombineChildren)手動把物體組合在一塊兒,但這個腳本會影響可見性測試,由於組合在一塊兒的物體始終會被看做一個物體,從而會增長GPU要處理的幾何體數量,所以要當心使用。

對於複雜的靜態場景,還能夠考慮自行設計遮擋剔除算法,減小可見的物體數量同時也能夠減小Draw Call。

總之,理解Draw Call和Draw Call Batching原理,根據場景特色設計相應的方案來儘可能減小Draw Call次數纔是王道,其它方面亦然。



Draw Call Batching (繪製調用批處理)

To draw an object on the screen, the engine has to issue a draw call to the graphics API (OpenGL ES in the case of iOS). Every single draw call requires a significant amount of work on the part of the graphics API, causing significant performance overhead on the CPU side.
在屏幕上渲染物體,引擎須要發出一個繪製調用來訪問圖形API(iOS系統中爲OpenGL ES)。
每一個繪製調用須要進行大量的工做來訪問圖形API,從而致使了CPU方面顯著的性能開銷。

Unity combines a number of objects at runtime and draws them together with a single draw call. This operation is called "batching". The more objects Unity can batch together, the better rendering performance you will get.
Unity在運行時能夠將一些物體進行合併,從而用一個繪製調用來渲染他們。這一操做,咱們稱之爲「批處理」。
通常來講,Unity批處理的物體越多,你就會獲得越好的渲染性能。

Built-in batching support in Unity has significant benefit over simply combining geometry in the modeling tool (or using theCombineChildren script from the Standard Assets package). Batching in Unity happensafter visibility determination step. The engine does culling on each object individually, and the amount of rendered geometry is going to be the same as without batching. Combining geometry in the modeling tool, on the other hand, prevents effecient culling and results in much higher amount of geometry being rendered.
Unity中內建的批處理機制所達到的效果要明顯強於使用幾何建模工具(或使用Standard Assets包中的CombineChildren腳本)的批處理效果。
這是由於,Unity引擎的批處理操做是在物體的可視裁剪操做以後進行的。
Unity先對每一個物體進行裁剪,而後再進行批處理,這樣能夠使渲染的幾何總量在批處理先後保持不變。
可是,使用幾何建模工具來拼合物體,會妨礙引擎對其進行有效的裁剪操做,從而致使引擎須要渲染更多的幾何面片。

Materials
材質
Only objects sharing the same material can be batched together. Therefore, if you want to achieve good batching, you need to share as many materials among different objects as possible.
只有擁有相同材質的物體才能夠進行批處理。
所以,若是你想要獲得良好的批處理效果,你須要在程序中儘量地複用材質和物體。

If you have two identical materials which differ only in textures, you can combine those textures into a single big texture - a process often calledtexture atlasing. Once textures are in the same atlas, you can use single material instead.
若是你的兩個材質僅僅是紋理不一樣,那麼你能夠經過 紋理拼合 操做來將這兩張紋理拼合成一張大的紋理。
一旦紋理拼合在一塊兒,你就能夠使用這個單一材質來替代以前的兩個材質了。

If you need to access shared material properties from the scripts, then it is important to note that modifyingRenderer.material will create a copy of the material. Instead, you should useRenderer.sharedMaterial to keep material shared.
若是你須要經過腳原本訪問複用材質屬性,那麼值得注意的是改變Renderer.material將會形成一份材質的拷貝。
所以,你應該使用Renderer.sharedMaterial來保證材質的共享狀態。

Dynamic Batching
動態批處理
Unity can automatically batch moving objects into the same draw call if they share the same material.
若是動態物體共用着相同的材質,那麼Unity會自動對這些物體進行批處理。

Dynamic batching is done automatically and does not require any additional effort on your side.
動態批處理操做是自動完成的,並不須要你進行額外的操做。

Tips:
提醒:
一、      Batching dynamic objects has certain overheadper vertex, so batching is applied only to meshes containing less than900 vertex attributes in total.
             批處理動態物體須要在每一個頂點上進行必定的開銷,因此動態批處理僅支持小於900頂點的網格物體。

二、      If your shader is using Vertex Position, Normal and single UV, then you can batch up to 300 verts and if your shader is using Vertex Position, Normal, UV0, UV1 and
            Tangent, then only 180 verts.
            Please note: attribute count limit might be changed in future
            若是你的着色器使用頂點位置,法線和UV值三種屬性,那麼你只能批處理300頂點如下的物體;
若是你的着色器須要使用頂點位置,法線,UV0,UV1和切向量,那你只
            能批處理180頂點如下的物體。
            請注意:屬性數量的限制可能會在未來進行改變。

四、      Don't use scale. Objects with scale (1,1,1) and (2,2,2) won't batch.
            不要使用縮放尺度(scale)。分別擁有縮放尺度(1,1,1)和(2,2,2)的兩個物體將不會進行批處理。

五、      Uniformly scaled objects won't be batched with non-uniformly scaled ones.
            統一縮放尺度的物體不會與非統一縮放尺度的物體進行批處理。
           Objects with scale (1,1,1) and (1,2,1) won't be batched. On the other hand (1,2,1) and (1,3,1) will be.
           使用縮放尺度(1,1,1)和 (1,2,1)的兩個物體將不會進行批處理,可是使用縮放尺度(1,2,1)和(1,3,1)的兩個物體將能夠進行批處理。

六、     Using different material instances will cause batching to fail.
           使用不一樣材質的實例化物體(instance)將會致使批處理失敗。

七、     Objects with lightmaps have additional (hidden) material parameter: offset/scale in lightmap, so lightmapped objects won't be batched (unless they point to same
           portions of lightmap)
           擁有lightmap的物體含有額外(隱藏)的材質屬性,好比:lightmap的偏移和縮放係數等。因此,擁有lightmap的物體將不會進行批處理(除非他們指向lightmap的同一
           部分)。

八、     Multi-pass shaders will break batching. E.g. Almost all unity shaders supports several lights in forward rendering, effectively doing additional pass for them
           多通道的shader會妨礙批處理操做。好比,幾乎unity中全部的着色器在前向渲染中都支持多個光源,併爲它們有效地開闢多個通道。

九、     Using instances of a prefab automatically are using the same mesh and material.
           預設體的實例會自動地使用相同的網格模型和材質。

Static Batching
靜態批處理

Static batching, on the other hand, allows the engine to reduce draw calls for geometry of any size (provided it does not move and shares the same material). Static batching is significantly more efficient than dynamic batching. You should choose static batching as it will require less CPU power.
相對而言,靜態批處理操做容許引擎對任意大小的幾何物體進行批處理操做來下降繪製調用(只要這些物體不移動,而且擁有相同的材質)。所以,靜態批處理比動態批處理更加有效,你應該儘可能低使用它,由於它須要更少的CPU開銷。

In order to take advantage of static batching, you need explicitly specify that certain objects are static and willnot move, rotate or scale in the game. To do so, you can mark objects as static using the Static checkbox in the Inspector:
爲了更好地使用靜態批處理,你須要明確指出哪些物體是靜止的,而且在遊戲中永遠不會移動、旋轉和縮放。想完成這一步,你只須要在檢測器(Inspector)中將Static複選框打勾便可,以下圖所示:


Using static batching will require additional memory for storing the combined geometry. If several objects shared the same geometry before static batching, then a copy of geometry will be created for each object, either in the Editor or at runtime. This might not always be a good idea - sometimes you will have to sacrifice rendering performance by avoiding static batching for some objects to keep a smaller memory footprint. For example, marking trees as static in a dense forest level can have serious memory impact.
使用靜態批處理操做須要額外的內存開銷來儲存合併後的幾何數據。在靜態批處理以前,若是一些物體共用了一樣的幾何數據,那麼引擎會在編輯以及運行狀態對每一個物體建立一個幾何數據的備份。這並不老是一個好的想法,由於有時候,你將不得不犧牲一點渲染性能來防止一些物體的靜態批處理,從而保持較少的內存開銷。好比,將濃密森裏中樹設爲Static,會致使嚴重的內存開銷。

Static batching is only available in Unity iOS Advanced.
靜態批處理目前只支持Unity iOS Advanced。



備註:最近一直在研究Unity3D的性能優化問題,這段時間可能會多翻譯這方面的文章。

前兩天,MadFinger,就是當今iOS與Android上畫質最牛逼閃閃的遊戲之一——ShadowGun的開發商,使人驚異地放出了一個ShadowGun的樣例關卡以及若干可無償使用的Shader,國外同行們的分享精神真的是使人讚歎不已。原文在這裏,如下是個人一些摘錄和筆記。

首先是一些優化常識。針對圖形方面的優化主要包括三角形數量,紋理所佔內存,以及Shader,前兩項基本沒什麼好講的,針對設備機能的限制制定相應的指標便可,因此Shader就成爲了圖形性能優化的關鍵。

Alpha blending

在Unity官方文檔中講,因爲硬件緣由,在iOS設備上使用alpha-test會形成很大的性能開銷,應儘可能使用alpha-blend代替。這裏提到,在同屏使用alpha-blend的面數,尤爲是這些面所佔屏幕面積的大小,對性能也會形成很大影響。緣由是使用alpha-blend的面會形成overdraw的增長,這尤爲對低性能設備的影響很大。不過沒有購買Pro版,沒有Occlusion Culling功能的話,就沒必要顧慮這一問題了,反正overdraw是必然的。

複雜的Per-pixel shader

Per-pixel shader即Fragment shader,顧名思義是要對每一個渲染到屏幕上的像素作處理的shader,若是per-pixel shader比較複雜且須要處理的像素不少時,也就是使用該shader的面佔屏幕面積很大時,對性能的影響甚至要超過alpha blending。所以複雜的per-pixel shader只適用於小物體。

下面是對幾個Shader的逐一講解:

Environment specular maps(Shader Virtual Gloss Per Vertex Additive)
Specular map一般都是利用貼圖的alpha通道來定義物體表面的光滑程度(反光度),這個shader的特色是per-vertex計算反光度的,有着至關不錯的效果的同時比per-pixel的shader性能要高得多。這個shader很適用於關卡環境等佔很大區域的模型。

通過優化的動態角色光照和陰影(Light probes和BRDF Shader)
傳統的Lightmaps沒法支持動態物體,對此Unity提供了Light probes技術,預先把動態物體的光照信息保存在代理對象(即Light probes)中,運行時動態物體從距離最近的Probe中獲取光照信息。

Unity自己還提供了一個效果很是棒的專爲移動設備優化過的角色Shader,支持Diffuse、Specular和Normal maps,並經過一個特殊的腳本生成貼圖用於模仿BRDF光照效果。最終產生的效果堪比次時代大做中的角色光影效果。

霧和體積光(Shader Blinking Godrays)
目前在移動設備上要開啓真正的霧效基本不可行,ShadowGun的方案是經過簡單的網格+透明貼圖(稱爲霧面)來模擬霧效。在玩家靠近時,霧面逐漸變淡,同時fog plane的頂點也會移開(即便徹底透明的alpha面也會消耗不少渲染時間)。

使用這個Shader的網格須要通過處理:

頂點的alpha值用於決定頂點是否能夠移動(在例子中0爲不可動,1爲可動)。
頂點法線決定移動的方向
而後Shader經過計算與觀察者的距離來控制霧面的淡入/淡出。
這個Shader還能夠用來作體積光和其它一些alpha效果。

飛機墜毀的濃煙效果(Shader Scroll 2 Layers Sine Alpha-blended)
經過粒子產生濃煙的代價過高,因此ShadowGun中使用了網格+貼圖動畫來製做這個效果。經過混合兩層貼圖並讓它們交錯移動來產生動畫效果。其中頂點alpha值用於讓網格的邊緣看起來比較柔和,同時使用頂點顏色來模擬從火焰到煙霧的過渡效果。

帶動態效果的天空盒(Shader Scroll 2 Layers Multiplicative)
經過兩張貼圖的混合和移動產生雲的動態效果。

旗幟和衣服的飄動效果(Shader Lightmap + Wind)
一樣利用頂點alpha值決定哪些頂點能夠移動,而後shader的參數用於調整擺動的方向和速度。
=======================分割線========================

1、程序方面
  0一、務必刪除腳本中爲空或不須要的默認方法;
  0二、只在一個腳本中使用OnGUI方法;
  0三、避免在OnGUI中對變量、方法進行更新、賦值,輸出變量建議在Update內;
  0四、同一腳本中頻繁使用的變量建議聲明其爲全局變量,腳本之間頻繁調用的變量或方法建議聲明爲全局靜態變量或方法;
  0五、不要去頻繁獲取組件,將其聲明爲全局變量;
  0六、數組、集合類元素優先使用Array,其次是List;
  0七、腳本在不使用時腳本禁用之,須要時再啓用;
  0八、能夠使用Ray來代替OnMouseXXX類方法;
  0九、須要隱藏/顯示或實例化來回切換的對象,儘可能不要使用SetActiveRecursively或active,而使用將對象遠遠移出相機範圍和移回原位的作法;
  十、儘可能少用模運算和除法運算,好比a/5f,必定要寫成a*0.2f。
  十一、對於不常常調用或更改的變量或方法建議使用Coroutines & Yield;
  十二、儘可能直接聲明腳本變量,而不使用GetComponent來獲取腳本;
iPhone
  1三、儘可能使用整數數字,由於iPhone的浮點數計算能力不好;
  1四、不要使用原生的GUI方法;
  1五、不要實例化(Instantiate)對象,事先建好對象池,並使用Translate「生成」對象;
 

2、模型方面
  0一、合併使用同貼圖的材質球,合併使用相同材質球的Mesh;
  0二、角色的貼圖和材質球只要一個,若必須多個則將模型離分離爲多個部分;
  0二、骨骼系統不要使用太多;
  0三、當使用多角色時,將動畫單獨分離出來;
  0四、使用層距離來控制模型的顯示距離;
  0五、陰影其實包含兩方面陰暗和影子,建議使用實時影子時把陰暗效果烘焙出來,不要使用燈光來調節光線陰暗。
  0六、少用像素燈和使用像素燈的Shader;
  0八、若是硬陰影能夠解決問題就不要用軟陰影,而且使用不影響效果的低分辨率陰影;
  0八、實時陰影很耗性能,儘可能減少產生陰影的距離;
  0九、容許的話在大場景中使用線性霧,這樣能夠使遠距離對象或陰影不易察覺,所以能夠經過減少相機和陰影距離來提升性能;
  十、使用圓滑組來儘可能減小模型的面數;
  十一、項目中若是沒有燈光或對象在移動那麼就不要使用實時燈光;
  十二、水面、鏡子等實時反射/折射的效果單獨放在Water圖層中,而且根據其實時反射/折射的範圍來調整;
  1三、碰撞對效率的影響很小,但碰撞仍是建議使用Box、Sphere碰撞體;
  1四、建材質球時儘可能考慮使用Substance;
  1五、儘可能將全部的實時反射/折射(如水面、鏡子、地板等等)都集合成一個面;
  1六、假反射/折射沒有必要使用過大分辨率,通常64*64就能夠,不建議超過256*256;
  1七、須要更改的材質球,建議實例化一個,而不是使用公共的材質球;
  1八、將不須射線或碰撞事件的對象置於IgnoreRaycast圖層;
  1九、將水面或相似效果置於Water圖層
  20、將透明通道的對象置於TransparentFX圖層;
  2一、養成良好的標籤(Tags)、層次(Hieratchy)和圖層(Layer)的條理化習慣,將不一樣的對象置於不一樣的標籤或圖層,三者有效的結合將很方便的按名稱、類別和屬性來查找;
  2二、經過Stats和Profile查看對效率影響最大的方面或對象,或者使用禁用部分模型的方式查看問題到底在哪兒;
  2三、使用遮擋剔除(Occlusion Culling)處理大場景,一種較原生的類LOD技術,而且可以「分割」做爲總體的一個模型。

3、其它
  場景中若是沒有使用燈光和像素燈,就不要使用法線貼圖,由於法線效果只有在有光源(Direct Light/Point Light/Angle Light/Pixel Light)的狀況下才有效果。

C#語言 優化

1、用屬性代替可訪問的字段

  一、.NET數據綁定只支持數據綁定,使用屬性能夠得到數據綁定的好處;

  二、在屬性的get和set訪問器重可以使用lock添加多線程的支持。

  2、readonly(運行時常量)和const(編譯時常量)

  一、const只可用於基元類型、枚舉、字符串,而readonly則能夠是任何的類型;

  二、const在編譯時將替換成具體的常量,這樣若是在引用中同時使用了const和readonly兩種值,則對readonly的再次改變將會改變設計的初衷,這是須要從新編譯所更改的程序集,以從新引用新的常量值。

  三、const比readonly效率高,但失去了應用的靈活性。

  3、is與as

  一、二者都是在運行時進行類型的轉換,as操做符只能使用在引用類型,而is能夠使用值和引用類型;

  二、一般的作法是用is判斷類型,而後選擇使用as或強類型轉換操做符(用operater定義的轉換)有選擇地進行。

  4、ConditionalAttribute代替#if #endif條件編譯

  一、ConditionalAttribute只用於方法級,對其餘的如類型、屬性等的添加都是無效的;而#if #endif則不受此限制;

  二、ConditionalAttribute能夠添加多個編譯條件的或(OR)操做,而#if #endif則能夠添加與(AND)[這裏能夠徹底定義爲另外一個單獨的符號];

  三、ConditioanlAttribute定義能夠放在一個單獨的方法中,使得程序更爲靈活。

  5、提供ToString()方法

  一、能夠更友好的方式提供用戶詳細的信息;

  二、使用IFormatter.ToString()方法提供更靈活的定製,若是添加IFormatProvider 和ICustomFormatter接口則更有意義的定製消息輸出。

  6、值和引用類型的區別

  一、值類型不支持多態,適合存儲應用程序操做的數據,而引用則支持多態,適用於定義應用程序的行爲;

  二、對於數組定義爲值類型能夠顯著提升程序的性能;

  三、值類型具備較少的堆內存碎片、內存垃圾和間接訪問時間,其在方法中的返回是以複製的方式進行,避免暴露內部結構到外界;

  四、值類型應用在以下的場景中:類型的職責主要是用於數據存儲;公共接口徹底由一些數據成員存取屬性定義;永遠沒有子類;永遠沒有多態行爲。

  7、值類型儘量實現爲常量性和原子性的類型

  一、使咱們的代碼更易於編寫和維護;

  二、初始化常量的三種策略:在構造中;工廠方法;構造一個可變的輔助類(如StringBuilder)。

  8、確保0爲值得有效狀態

  一、值類型的默認狀態應爲0;

  二、枚舉類型的0不該爲無效的狀態;在FlagsAttribute是應確保0值爲有效地狀態;

  三、在字符串爲爲空時能夠返回一個string.Empty的空字符串;

  9、相等判斷的多種表示關係

  一、ReferenceEquals()判斷引用相等,須要兩個是引用同一個對象時方可返回true;

  二、靜態的Equals()方法先進性引用判斷再進行值類型判斷的;

  三、對於引用類型的判斷能夠在使用值語義時使用重寫Equals()方法;

  四、重寫Equals()方法時也應當重寫GetHashCode()方法,同時提供operater==()操做。

  10、理解GetHashCode()方法的缺陷

  一、GetHashCode()僅應用在基於散列的集合定義鍵的散列值,如HashTable或Dictionary;

  二、GetHashCode()應當遵循相應的三條規則:兩個相等對象應當返回相同的散列碼;應當是一個實例不變式;散列函數應該在全部的整數中產生一個隨機的分佈;

  11、優先使用foreach循環語句

  一、foreach能夠消除編譯器對for循環對數組邊界的檢查;

  二、foreach的循環變量是隻讀的,且存在一個顯式的轉換,在集合對象的對象類型不正確時拋出異常;

  三、foreach使用的集合須要有:具有公有的GetEnumberator()方法;顯式實現了IEnumberable接口;實現了IEnumerator接口;

  四、foreach能夠帶來資源管理的好處,由於若是編譯器能夠肯定IDisposable接口時能夠使用優化的try…finally塊;

  12、默認字段的初始化優於賦值語句

  一、字段生命默認會將值類型初始化爲0,引用類型初始化爲null;

  二、對同一個對象進行屢次初始化會下降代碼的執行效率;

  三、將字段的初始化放到構造器中有利於進行異常處理。

  十3、使用靜態構造器初始化靜態成員

  一、靜態構造器會在一個類的任何方法、變量或者屬性訪問以前執行;

  二、靜態字段一樣會在靜態構造器以前運行,同時靜態構造器有利於異常處理。

  十4、利用構造器鏈(在.NET 4.0已經用可選參數解決了這個問題)

  一、用this將初始化工做交給另外一個構造器,用base調用基類的構造器;

  二、類型實例的操做順序是:將全部的靜態字段都設置爲0;執行靜態字段初始化器;執行基類的靜態構造器;執行當前類型的靜態構造器;

  將全部的實例字段設置爲0;執行實例字段初始化器;執行合適的基類實例構造器;執行當前類型的實例構造器。

  十5、利用using和try/finally語句來清理資源

  在IDisposable接口的Dispose()方法中用GC.SuppressFinalize()可通知垃圾收集器再也不執行終結操做。

  十6、儘可能減小內存垃圾

  一、分配和銷燬一個對上的對象都要花費額外的處理器時間;

  二、減小分配對象數量的技巧:常用的局部變量提高爲字段;提供一個類,用於存儲Singleton對象來表達特定類型的經常使用實例。

  三、用StringBuilder進行復雜的字符串操做。

  十7、儘可能減小裝箱和拆箱

  一、關注一個類型到System.Object的隱式轉換,同時值類型不該該被替換爲System.Object類型;

  二、使用接口而不是使用類型能夠避免裝箱,即將值類型從接口實現,而後經過接口調用成員。

  十8、實現標準Dispose模式

  一、使用非內存資源,它必須有一個終結器,垃圾收集器在完成沒有終結其的內存對象後會將實現了終結器對象的添加到終結隊列中,而後垃圾收集器會啓動一個新的線程來運行這些對象上的終結器,這種防護性的變成方式是由於若是用戶忘記了調用Dispose()方法,垃圾回收器老是會調用終結器方法的,這樣能夠避免出現非託管的內存資源不被釋放引發內存泄漏的問題;

  二、使用IDisposable.Dispose()方法須要作四個方面的工做:釋放全部的非託管資源;釋放全部的託管資源;設置一個狀態標記來表示是否已經執行了Dispose();調用GC.SuppressFinalize(this)取消對象的終結操做;

  三、爲須要多態的類型添加一個受保護的虛方法Dispose(),派生類經過重寫這個方法來釋放本身的任務;

  四、在須要IDisoposable接口的類型中,即便咱們不須要一個終結器也應該實現一個終結器。

  十9、定義並實現接口優於繼承類型

  一、不相關的類型能夠共同實現一個共同的接口,並且實現接口比繼承更容易;

  二、接口比較穩定,他將一組功能封裝在一個接口中,做爲其餘類型的實現合同,而基類則能夠隨着時間的推移進行擴展。

  二10、明辨接口實現和虛方法重寫

  一、在基類中實現一個接口時,派生類須要使用new來隱藏對基類方法的使用;

  二、能夠將基類接口的方法申明爲虛方法,而後再派生類中實現。

  二11、使用委託表達回調

  一、委託對象自己不提供任何異常捕獲,因此任何的多播委託調用都會結束整個調用鏈;

  二、經過顯示調用委託鏈上的每一個委託目標能夠避免多播委託僅返回最後一個委託的輸出。

  二12、使用事件定義外部接口

  一、應當聲明爲共有的事件,讓編譯器爲咱們建立add和renmove方法;

  二、使用System.ComponentModel.EventHandlerList容器來存儲各個事件處理器,在類型中包含大量事件時能夠使用他來隱藏全部事件的複雜性。

  二十3、避免返回內部類對象的引用

  一、因爲值類型對象的訪問會建立一個該對象的副本,因此定義一個值類型的的屬性徹底不會改變類型對象內部的狀態;

  二、常量類型能夠避免改變對象的狀態;

  三、定義接口將訪問限制在一個子集中從而最小化對對象內部狀態的破壞;

  四、定義一個包裝器對象來限制另外一個對象的訪問;

  五、但願客戶代碼更改內部數據元素時能夠實現Observer模式,以使對象能夠對更改進行校驗或相應。

  二十4、聲明式編程優於命令式編程

  能夠避免在多個相似的手工編寫的算法中犯錯誤的可能性,並提供清晰和可讀的代碼。

  二十5、儘量將類型實現爲可序列化的類型

  一、類型表示的不是UI控件、窗口或者表單,都應使類型支持序列化;

  二、在添加了NonSerializedAttribute的反序列化的屬性時能夠經過實現IDeserializationCallback的OnDeserialization()方法裝入默認值;

  三、在版本控制中能夠使用ISerializable接口來進行靈活的控制,同時提供一個序列化的構造器來根據流中的數據初始化對象,在實現時還要求SerializationFormatter異常的許可。

  四、若是須要建立派生類則須要提供一個掛鉤方法供派生類使用。

  二十6、使用IComparable和IComparer接口實現排序關係

  一、IComparable接口用於爲類型實現最天然的排序關係,重載四個比較操做符,能夠提供一個重載版的CompareTo()方法,讓其接受具體類型做爲參數;

  二、IComparer用於提供有別於IComparable的排序關係,或者爲咱們提供類型自己說沒有實現的排序關係。

  二十7、避免ICloneable接口

  一、對於值類型永遠不須要支持ICloneable接口使用默認的賦值操做便可;

  二、對於可能須要支持ICloneable接口的基類,應該爲其創造一個受保護的複製構造器,並應當避免支持IConeable接口。

  二十8、避免強制轉換操做符

  經過使用構造器來代替轉換操做符能夠使轉換工做變得更清晰,因爲在轉換後使用的臨時對象,容易致使一些詭異的BUG。

  二十9、只有當新版積累致使問題是才考慮使用new修飾符

  三10、儘量實現CLS兼容的程序集

  一、建立一個兼容的程序集須要遵循兩條規則:程序集中全部公有和受保護成員所使用的參數和返回值類型都必須與CLS兼容;任何與CLS不兼容的公有和受保護成員都必須有一個與CLS兼容的替代品;

  二、能夠經過顯式實現接口來避開CLS兼容類型檢查,及CLSCompliantAttribute不會檢查私有的成員的CLS兼容性。

  三11、儘量實現短小簡潔的方法

  一、JIT編譯器以方法爲單位進行編譯,沒有被調用的方法不會被JIT編譯;

  二、若是將較長的Switch中的Case語句的代碼替換成一個一個的方法,則JIT編譯器所節省的時間將成倍增長;

  三、短小精悍的方法並選擇較少的局部變量能夠得到優化的寄存器使用;

  四、方法內的控制分支越少,JIT編譯器越容易將變量放入寄存器。

  三12、儘量實現小尺寸、高內聚的程序集

  一、將全部的公有類以及共用的基類放到一些程序集中,把爲公有類提供功能的工具類也放入一樣的程序集中,把相關的公有接口打包到他們本身的程序集中,最後處理遍及應用程序中水平位置的類;

  二、原則上建立兩種組件:一種爲小而聚合、具備某項特定功能的程序集,另外一種爲大而寬、包含共用功能的程序集。

  三十3、限制類型的可見性

  一、使用接口來暴露類型的功能,能夠使咱們更方便地建立內部類,同時又不會限制他們在程序集外的可用性;

  二、向外暴露的公有類型越少,將來擴展和更改實現所擁有的選擇就越多。

  三十4、建立大粒度的Web API

  這是在機器之間的交易的頻率和載荷都降到最低,將大的操做和細粒度的執行放到服務器執行。

  三十5、重寫優於事件處理器

  一、一個事件處理器拋出異常,則事件鏈上的其餘處理器將不會被調用,而重寫的虛方法則不會出現這種狀況;

  二、重寫要比關聯事件處理器高效得多,事件處理器須要迭代整個請求列表,這樣佔用了更多的CPU時間;

  三、事件能在運行時響應,具備更多的靈活性,能夠對同一個事件關聯多個響應;

  四、通行的規則是處理一個派生類的事件是,重寫方式較好。

  三十6、合理使用.NET運行時診斷

  一、System.Diagnostics.Debug\Trace\EventLog爲運行時提供了程序添加診斷信息所須要的全部工具,EventLog提供入口時的應用程序能寫到系統事件日誌中;

  二、最後不要寫本身的診斷庫,.NET FCL 已經擁有了咱們須要的核心庫。

  三十7、使用標準配置機制

  一、.NET框架的System.Windows.Application類爲咱們定義了創建通用配置路徑的屬性;

  二、Application.LocalAppDataPath和Application.userDataPath 會生成本地數據目錄和用戶數據的路徑名;

  三、不要在ProgramFiles和Windows系統目錄中寫入數據,這些位置須要更高的安全權限,不要期望用戶擁有寫入的權限。

  三十8、定製和支持數據綁定

  一、BindingMananger和CurrencyManager這兩個對象實現了控件和數據源之間的數據傳輸;

  二、數據綁定的優點:使用數據綁定要比編寫本身的代碼簡單得多;應該將它用於文本數據項以外的範圍-其餘顯示屬性也能夠被綁定;對於Windowos Forms 數據綁定可以處理多個控件同步的檢查相關數據源;

  三、在對象不支持所需的屬性時能夠經過屏蔽當前的對象而後添加一個想要的對象來支持數據綁定。

  三十9、使用.NET驗證

  一、ASP.NET中有五種控件來驗證有效性,能夠用CustomValidator派生一個新類來增長本身的認證器;

  二、Windows驗證須要子System.Windows.Forms.Control.Validating些一個事件處理器。

  四10、根據須要選用恰當的集合

  一、數組有兩個比較明顯的缺陷:不能動態的調整大小;調整大小很是耗時;

  二、ArrayList混合了一維數組和鏈表的特徵,Queue和Stack是創建在Array基礎上的特殊數組;

  三、當程序更加靈活的添加和刪除項時,能夠使更加健壯的集合類型,當建立一個模擬集合的類時,應當爲其實現索引器和IEnumberable接口。

  四11、DataSet優於自定義結構

  一、DataSet有兩個缺點個:使用XML序列化機制的DataSet與非.NET 代碼之間的交互不是很好;DataSet是一個很是通用的容器;

  二、強類型的DataSet打破了更多的設計規則,其得到的開發效率要遠遠高於本身編寫的看上去更爲優雅的設計。

  四12、利用特性簡化反射

  經過設計和實現特性類,強制開發人員用他們來聲明可被動態使用的類型、方法和屬性,能夠減小應用程序的運行時錯誤,提升軟件的用戶滿意度。

  四十3、避免過分使用反射

  一、Invoke成員使用的參數和返回值都是System.Object,在運行時進行類型的轉換,但出現問題的可能性也變得更多了;

  二、接口使咱們能夠獲得一個更爲清晰、也更具可維護性的系統,反射式一個很強大的晚期綁定機制.NET框架使用它來實現Windows控件和Web控件的數據綁定。

  四十4、爲應用程序建立特定的異常類

  一、須要不一樣的異常類的惟一緣由是讓用戶在編寫catch處理器時可以方便地對不一樣的錯誤採起不一樣的作法;

  二、可能有不一樣的修復行爲時咱們才應該建立多種不一樣的異常類,經過提供異常基類所支持的全部構造器,能夠爲應用程序建立功能完整的異常類,使用InnerException屬性能夠保存更低級別錯誤條件所產生的全部錯誤信息。

  四十5、優先選擇異常安全保證

  一、強異常保證在從異常中恢復和簡化異常處理之間提供了最好的平衡,在操做由於異常而中斷,程序的狀態保留不變;

  二、對將要修改的數據作防護性的複製,對這些數據的防護性複製進行修改,這中間的操做可能會引起異常,將臨時的副本和原對象進行交換;

  三、終結器、Dispose()方法和委託對象所綁定的目標方法在任何狀況下都應當確保他們不會拋出異常。

  四十6、最小化互操做

  一、互操做有三個方面的代價:數據在託管堆和非託管堆之間的列舉成本,託管代碼和非託管代碼之間切換的成本,對開發人員來講與混合環境打交道的開發工做;

  二、在interop中使用blittable類型能夠有效地在託管和非託管環境中來回複製,而不受對象內部結構的影響;

  三、使用In/Out特性來確保最貼切的沒必要要的屢次複製,經過聲明數據如何被列舉來提升性能;

  四、使用COM Interop用最簡單的方式實現和COM組件的互操做,使用P/Invoke調用Win32 API,或者使用C++編譯器的/CLR開關來混合託管和非託管的代碼;

  四十7、優先選擇安全代碼

  一、儘量的避免訪問非託管內存,隔離存儲不能防止來自託管代碼和受信用戶的訪問;

  二、程序集在Web上運行時能夠考慮使用隔離存儲,當某些算法確實須要更高的安全許可時,應該將那些代碼隔離在一個單獨的程序集中。

  四十8、掌握相關工具與資源

  一、使用NUnit創建自動單元測試(集成在VS2010 中了);

  二、FXCop工具會獲取程序集中的IL代碼,並將其與異族編碼規則和最佳實踐對照分析,最後報告違例狀況;

  三、ILDasm是一個IL反彙編工具,能夠幫助咱們洞察細節;

  四、Shared Source CLI是一個包含.NET框架內核和C#編譯器的實現源碼。

  四十9、爲C#2.0作準備(這個規則如今已經沒什麼意義了,畢竟如今已經到了4.0 )

  五10、瞭解ECMA標準

相關文章
相關標籤/搜索