1.對於DrawCall的認識:
DrawCall即為由CPU下達命令,調用OpenGL或DirectX接口進行解析並由GPU進行渲染顯示的過程稱為一次DrawCall。
在Unity中查看DrawCall參數,Window / Profiler 或者Ctrl+7 快捷鍵打開 Profiler性能分析器面板。
在程序運行狀態,如下圖即為DrawCall參數:
當然,在保證游戲流暢度的基礎上DrawCall越小越好!
2.Statistics統計面板的認識:
在程序運行狀態下,Game窗口點擊Stats打開統計面板,參數如下:
FPS(幀數):越大越好
CPU(處理器計算速度):越低越好
render thread(渲染線程,GPU渲染所需要的時間):越低越好
Batches(渲染批次):與DrawCall關聯,是Unity自動分類的渲染批次
Tris(三角面數):相機視野范圍內的三角面數量
Verts(頂點數):相機視野范圍內的頂點數量
SetPass calls:Unity中的Shader中包含很多Pass塊,每當GPU即將去運行一個Pass塊之前,就會產生一個“SetPass call”,在描述性能開銷上更有說服力
3.資源優化:
Mesh方面:
動態模型:
面片數<3000, 材質數<3, 骨骼數<50
靜態模型:
頂點數<500
Audio方面:
長時間音樂(背景音樂)壓縮格式:mp3
短時間音樂(攻擊等等)一般不壓縮存儲格式為:wav
導入到Unity后的編輯面板顯示為:
Decompress On Load:適用於小文件
Compressed in Memory:使用於大文件
Streaming:以流的形式便加載邊播放(對CPU消耗較大一般不采用)
Texture方面:
貼圖長度<1024(對手機而言)
Shader方面:
盡量減少復雜的數學運算
盡量減少Discard操作
減少冗余資源和重復資源方面:
A.Resources目錄下的資源不管是否被引用,都會打包進安裝包,不使用的資源不要放在Resources目錄下
B.不同目錄下的相同資源文件,如果都被引用,那么都會打包進資源包,造成冗余,保證同一個資源文件在項目中只存放在一個目錄位置
4.LOD層級細節技術:
此技術需要美工的配合,提供給程序多個不同三角面數的模型
在場景中新建一個空的游戲物體,並添加LOD Group組件,如下圖所示:
並將美工提供的三種不同精度的模型按照精度的大小依次拖入到LOD0、LOD1、LOD2中
此時,場景中渲染顯示的模型會根據相機與模型的距離進行切換顯示,具體的切換顯示距離可拖動組件中的條形框大小進行自定義,這樣便達到了近處渲染精模,遠處渲染粗模甚至不渲染來減少GPU消耗的目的
5.OcclusionCulling遮擋剔除技術:
當場景中有大量模型需要渲染時,應用遮擋剔除可實現減少DrawCall提升性能的效果
首先選中所有需要進行遮擋剔除的模型,並設置其occluder(遮擋體)和occludee(被遮擋體),有的物體可以是遮擋體同時也是被遮擋體。
接下來Window / Occlusion Culling 打開遮擋剔除面板如下圖:
選中遮擋剔除選項,烘焙
烘焙完成后,設置好顯示視野的相機
6.Lightmapping光照貼圖技術:
首先將需要進行光照貼圖的游戲物體設置為Lightmap Static
其次將用於光照貼圖的所有光源設置為Baked模式
最后Window / Lighting 打開燈光面板,進行烘焙,面板如下
其中Build后會在當前場景所在的文件夾中生成一個光照貼圖文件,我們也可以點擊Clear Baked Data 按鈕進行光照貼圖的清理操作
之后無論場景中的光源是否激活,均顯示光照效果,效果圖如下:
·
7.Mesh合並:
當場景中模型非常多,不妨試一下模型合並技術,可以在3dMax或其他建模軟件上進行操作,也可在Unity中進行操作,這里我僅介紹Unity中的模型合並方法。
前提:合並的物體必須是相同的材質,否則合並之后賦值多個材質並不能起到優化作用
首先,將下述代碼放在Assets / Editor 文件夾下
其次,在場景中需要合並的模型放在一個空物體下
然后,點擊選中空物體並點擊上方的菜單欄按鈕MeshCombine / CombineChildren進行合並所有子物體Mesh
最后,自行更改模型中的材質,位置等參數即可
1 using UnityEngine; 2 using System.Collections; 3 using UnityEditor; 4 5 public class CombineMesh : MonoBehaviour { 6 7 //菜單按鈕靜態觸發 8 [MenuItem( "MeshCombine/CombineChildren")] 9 static void CreatMeshCombine() 10 { 11 //獲取到當前點擊的游戲物體 12 Transform tSelect = (Selection.activeGameObject).transform; 13 14 //如果當前點擊的游戲物體無子物體,則無操作 15 if (tSelect.childCount < 1) 16 { 17 return; 18 } 19 20 21 //確保當前點擊的游戲物體身上有MeshFilter組件 22 if (!tSelect.GetComponent<MeshFilter>()) 23 { 24 tSelect.gameObject.AddComponent<MeshFilter>(); 25 } 26 //確保當前點擊的游戲物體身上有MeshRenderer組件 27 if (!tSelect.GetComponent<MeshRenderer>()) 28 { 29 tSelect.gameObject.AddComponent<MeshRenderer>(); 30 } 31 //獲取到所有子物體的MeshFilter組件 32 MeshFilter[] tFilters = tSelect.GetComponentsInChildren<MeshFilter>(); 33 34 //根據所有MeshFilter組件的個數申請一個用於Mesh聯合的類存儲信息 35 CombineInstance[] tCombiners = new CombineInstance[tFilters.Length]; 36 37 //遍歷所有子物體的網格信息進行存儲 38 for (int i = 0; i < tFilters .Length ; i++) 39 { 40 //記錄網格 41 tCombiners[i].mesh = tFilters[i].sharedMesh; 42 //記錄位置 43 tCombiners[i].transform = tFilters[i].transform.localToWorldMatrix; 44 } 45 //新申請一個網格用於顯示組合后的游戲物體 46 Mesh tFinalMesh = new Mesh(); 47 //重命名Mesh 48 tFinalMesh.name = "tCombineMesh"; 49 //調用Unity內置方法組合新Mesh網格 50 tFinalMesh.CombineMeshes(tCombiners); 51 //賦值組合后的Mesh網格給選中的物體 52 tSelect.GetComponent<MeshFilter>().sharedMesh = tFinalMesh; 53 //賦值新的材質 54 tSelect.GetComponent<MeshRenderer>().material = new Material(Shader.Find("VertexLit")); 55 } 56 57 }
效果圖如下:
8.資源池的利用:
當有游戲物體需要頻繁的創建刪除的時候,不妨試試資源池,可以節約性能。
例子:射擊游戲中的子彈