1、UGUI簡介html
UGUI是Unity官方推出的UI系統,集成了所見即所得的UI解決方案, 其功能豐富而且使用簡單,同時其源代碼也是開放的,下載地址:https://bitbucket.org/Unity-Technologies/ui/srcandroid
相比於NGUI,UGUI有如下幾個優勢:git
1. 所見即所得的編輯方式,在Scene窗口中便可編輯。github
2. 智能的Sprite packer能夠將圖片按tag自動生成圖集而無需人工維護,生成的圖集合並方式比較合理,無冗餘資源。canvas
3. 渲染順序與GameObject的Hierarchy順序相關,靠近根節點顯示在底層,而靠近葉子節點顯示在頂層;這樣的渲染方式使得調整UI的層級比較方便和直觀。緩存
4. RectTranForm及錨點系統更適合於2D平面佈局,而且很是方便多分辨率屏幕自適配。性能優化
2、UI製做規範和指導方法網絡
本文是關於UGUI優化的,或許你會以爲UI的製做規範及指導方法與優化無關,其實不少性能問題每每是資源的不合理使用形成的,好比使用了尺寸過大的圖片、引用了過多的圖集以及加載了沒必要要的資源等。若是從設計和製做UI一開始就遵照特定的規範,則能夠規避沒必要要的性能開銷。筆者根據參與的多個項目總結了如下幾點通用的規範和指導方法(這些規範適用於全部項目,無論你使用UGUI仍是NGUI)。ide
1. 合理的分配圖集函數
合理的分配圖集能夠下降drawcall和資源加載速度;具體細節以下:
● 同一個UI界面的圖片儘量放到一個圖集中,這樣能夠儘量的下降drawcall。
● 共用的圖片放到一個或幾共享的圖集中,例如通用的彈框和按鈕等;相同功能的圖片放到一個圖集中, 例如裝備圖標和英雄頭像等;這樣能夠下降切換界面的加載速度。
● 不一樣格式的圖片分別放到不一樣的圖集中,例如透明(帶Alpha)和不透明(不帶Alpha)的圖片,這樣能夠減小圖片的存儲空間和佔用內存。(UGUI的sprite packer會自動處理這種狀況)
2. resources目錄中應該只保存prefab文件,其它非prefab文件(例如動畫,貼圖,材質等)應放到resource目錄以外
由於隨着項目的迭代,可能會致使部分資源(動畫,貼圖)等失效,若是這些文件放在resource目錄下,在打包時,unity會將resource目錄下文本所有打成一個大的AssetBundle包(非resouce目錄下的文件只有在引用到時纔會被打到包裏),從而出現冗餘,增長沒必要要的存儲空間和內存佔用。能夠經過如下代碼(Mac環境下)在控制檯窗口中查看當前目錄下全部非prefab資源的代碼:
find . -type f | egrep -v "(prefab|prefab\.meta|meta)$"
例如在筆者的一次掃描中,發如今了以下結果:
3. 關卡內的UI資源不要與外圍系統UI資源混用
在關卡內,須要加載大量的角色及場景資源,內存比較吃緊,通常在進入關卡時,都會手動釋放外圍系統的資源,以便使關卡內有更多的內存可使用。若是戰鬥內的UI與外圍系統的UI使用相同圖集裏的圖片,則有可能會使得外圍系統的圖片資源釋放不成功。對於關卡內與外圍共用的UI資源須要特殊處理,通常來講複製一份出來專門給關卡內使用是比較好的選擇。
4. 適當的下降圖片的尺寸
有時UI系統的背景可能會使用全屏大小的圖片,好比在Iphone上使用1136*640大小的圖片;使用這樣尺寸的圖片代價是很昂貴的,能夠和美術同窗商量適當的下降圖片的精度,使用更低尺寸的圖片。
5. 在android設備上使用etc格式的圖片
目前,幾乎全部android設備都支持etc1格式的圖片,etc1的好處是第個像素點只戰用0.5個字節而普通rgba32的圖片每一個像素點佔4個字節,也就說一張1024*1024圖片若是使用rgba32的格式所佔用的內存爲4M而etc1格式所佔用的內存僅爲0.5M。可是使用etc1格式的圖片有兩個限制——長和寬必須是POT的(2的N次方)而且不支持alpha通道,所以使用etc1時須要額外的一張圖來存儲alpha通道,而且使用特殊的shader來對alpha採樣。具體的細節可參考:http://malideveloper.arm.com/resources/sample-code/etcv1-texture-compression-and-alpha-channels/
6. 刪除沒必要要的UI節點、動畫組件及資源
隨着項目的迭代,可能有部分ui節點及動畫已經失效,對於失效的節點及動畫必定要刪除,在不少項目中,有部分同窗爲了方便省事,只是將失效的節點及動畫disable了。這樣作雖然在運行時不會對cpu形成太多負擔,可是在加載時會增長沒必要要的加載時間以及內存佔用。對於廢棄的UI圖片資源,雖然未放到Resource目錄最終不會打到包裏,可是在Editor模式下仍然會打到圖集中從而影響優化決策。筆者寫了一個掃描未使用到UI貼圖資源的工具,代碼地址:https://github.com/neoliang/FindUnUsedUITexture;
另外,對於廢棄的腳本,可能還會有某些對象持有對它的引用,而加載這樣的對象也比較耗時,筆者也寫了一個掃描廢棄腳本的工具,代碼地址:https://github.com/neoliang/MissingScriptFinder
3、CPU優化
通常來講,優化cpu性能應該先用profiler定位到性能熱點,找到消耗最高的函數,而後再想辦法下降它的消耗。通過筆者屢次使用profiler對UGUI的分析來看,其CPU性能開銷高主要緣由之一是Canvs對UI網格的重建,有不少狀況會觸發Canvas對網格的重建,例如Image,Text等UI元素的Enable及UI元素的長、寬或Color屬性的變化等。Canvas中UI Mesh頂點較多的話,則該項將會出現較高的CPU開銷。在Unity的Profiler中則對應的是Canvas.SendWillRenderCanvases或Canvas.BuildBatch佔用過多的時間。
Canvas.BuildBatch主要功能是合併Canvas節點下全部UI元素的網格,合併後的網格會緩存起來,只有其下面的UI元素的網格發生改變時纔會從新合併。而UI元素的網絡變化主要是由於Canvas.SendWillRenderCanvases調用時,rebuild了Layout或者craphic。該函數的調用過程時序圖以下:
1.該過程由CanvasUpdateRegistry監聽Canvas的WillRenderCanvases(上圖中1)而執行,主要是對前標記爲dirty的layout和craphic執行rebuild。引發layout和graphic的dirty主要緣由是由於Canvas樹形結構下的UI元素髮生了變化(例如增長刪除UI對象,UI元素的頂點,rec尺寸改變等)調用了Graphic.SetDirty(實際上最終都會調用CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild)。
2. 在rebuild layout以前會對Layout rebuild queue中的元素依據它們在heiarchy中的層次深度進行排序(上圖中的2),排列的結果是越靠近根的節點越會被優先處理。
3. rebuild layout(上圖中的3),主要是執行ILayoutElement和ILayoutController接口中的方法來計算位置,Rect的大小等佈局信息。
4. rebulid graphic(上圖中的4),主要是調用UpdateGeometry重建網格的頂點數據(上圖中5)以及調用UpdateMeterial更新CanvasRender的材質信息(上圖中6)。
基於以上UGUI的網格更新原理,咱們能夠作如下優化:
a. 使用盡量少的UI元素;在製做UI時,必定要仔細查檢UI層級,刪除不沒必要要的UI元素,這樣能夠減小深度排序的時間(上圖中的2)以及Rebuild的時間(上圖中的3,4)。
b. 減小Rebuild的頻率,將動態UI元素(頻繁改變例如頂點、alpha、座標和大小等的元素)與靜態UI元素分離出來,放到特定的Canvas中。
c. 謹慎使用UI元素的enable與disable,由於它們會觸發耗時較高的rebuild(圖中的三、4),替代方案之一是enable和disableUI元素的canvasrender或者Canvas。
d. 謹慎使用Text的Best Fit選項,雖然這個選項能夠動態的調整字體大小以適應UI佈局而不會超框,但其代價是很高的,Unity會爲用到的該元素所用到的全部字號生成圖元保存在atlas裏,不但增長額外的生成時間,還會使得字體對應的atlas變大。
e.謹慎使用Canvas的Pixel Perfect選項,該選項會使得ui元素在發生位置變化時,形成layout Rebuild。(好比ScrollRect滾動時,若是開啓了Canvas的pixel Perfect,會使得Canvas.SendWillRenderCanvas消耗較高)
f. 使用緩存池來保存ScrollView中的Item,對於移出或移進View外的的元素,不要調用disable或enable,而是把它們放到緩存池裏或從緩存池中取出複用。
g. 除了rebuild過程以外,UGUI的touch處理消耗也可能會成爲性能熱點。由於UGUI在默認狀況下會對全部可見的Graphic組件調用raycast。對於不須要接收touch事件的grahic,必定要禁用raycast。對於unity5以上的能夠關閉graphic的Raycast Target而對於unity4.6,能夠給不須要接收touch的UI元素加上canvasgroup組件。
unity5.x
unity4.6
4、GPU優化
通常來講,形成GPU性能瓶頸主要有兩個緣由:複雜的vertext或pixel shader計算以及overdraw形成過多的像素填充。在默認狀況下UGUI中全部UI元素使用都使用UI/Defaut shader,所以在優化時可優先考慮解決Overdraw問題。Overdraw主要是由於大量UI元素的重疊引發的,查看overdraw比較簡單,在scene窗口中選擇overdraw模式,場景中越亮的地方表示overdraw越高(以下圖)。
爲了下降overdraw,能夠作以下優化:
1. 禁用不可見的UI,好比當打開一個系統時若是徹底擋住了另一個系統,則能夠將被遮擋住的系統禁用。
2. 不要使用空的Image,在Unity中,RayCast使用Graphi做爲基本元素來檢測touch,在筆者參與的項目中,不少同窗使用空的image並將alpha設置爲0來接收touch事件,這樣會產生沒必要要的overdraw。經過以下類NoDrawingRayCast來接收事件能夠避免沒必要要的overdraw。
3. public class NoDrawingRayCast : Graphic
4. {
5. public override void SetMaterialDirty()
6. {
7. }
8. public override void SetVerticesDirty()
9. {
10. }
11. protected override void OnFillVBO(List<UIVertex> vbo)
12. {
13. vbo.Clear();
14. }
}
5、總結
優化UGUI性能沒有萬能的方法,筆者這些經驗總結也只能做爲參考。優化性能每每是在各類選擇之間作出平衡,好比drawcall與rebuild平衡、內存打敗與cpu消耗平衡以及UI圖片精度與紋理大小的平衡等。每一次優化都有可能使得瓶頸出如今其它的環節上,要善於使用profiler,找到性能熱點,對症下藥。
6、關於資源佔用問題
UI資源優化是UGUI性能優化的重點,騰訊WeTest也在資源方面提供了性能的測試。如下經過「紋理」資源,介紹騰訊WeTest性能測試在資源方面的測試狀況。
一、登陸http://wetest.qq.com/cube/ ,點擊「Android版 下載」,或者在頁面末尾掃描二維碼直接下載騰訊WeTest的手遊客戶端性能分析工具Cube。打開工具,選擇「Unity資源分析」。
二、上傳測試報告後,咱們能夠經過測試報告,瞭解unity遊戲的資源狀況。
資源結論概況
進入資源數據的報告以後,首先能夠看到全部資源數據的概況結果,整體上了解存在問題的數據,繼續下拉,能夠了解該指標的具體狀況。
資源數據概況
下面將以「紋理資源」爲例,對cube資源測試報告進行解讀。
紋理資源
Cube測試報告的「紋理資源」,根據騰訊標準,是指望<50MB的,從下圖可見,若是超出紅色虛線,就說明紋理資源存在超標。
點擊具體數據點,獲取具體資源數據
另外,點擊圖表中的綠色線條中的具體數據點,能夠看到這個點的當前數據,全部數據根據資源大小進行排序
全部數據根據資源大小進行排序
在這個表之下,有一個「資源大小top20」的表格,羅列了資源排名前20的資源內容。其中資源大小超過建議值的會呈現紅色,資源大小非2的n次冪的呈現黃色。點擊任意一個資源名稱,能夠在圖表上觀察這個資源所影響的區域:
點擊具體資源瞭解影響區域
瞭解資源調用的影響區域
針對手遊的性能優化,騰訊WeTest平臺的Cube工具提供了基本全部相關指標的檢測,爲手遊進行最高效和準確的測試服務,不斷改善玩家的體驗。目前功能還在免費開放中。
體驗地址:http://wetest.qq.com/cube/
幫助中心:http://wetest.qq.com/help/documentation/10096.html
若是對使用當中有任何疑問,歡迎聯繫騰訊WeTest企業qq:800024531