本文將介紹一些提升Unity UI性能的技巧。更多優化技巧,可以觀看下方的視頻,內容是Unity工程師Ian Dundore在Unite Europe 2017的演講《使用Unity性能提升技巧》。

  

  劃分畫布

  問題:UI Canvas上有一個或多個元素變化時,會污染整個畫布。

  畫布(Canvas)是Unity UI的基本組件。它會生成網格來呈現放置在畫布上的UI元素,當UI元素變化時,它會重新生成網格並向GPU發起繪圖調用,從而顯示出UI。

  生成這些網格會消耗大量性能,需要將UI元素收集到批處理中,從而儘可能減少繪圖調用。因爲批處理的生成過程性能消耗較大,通常只在必要時候才重新生成。問題在於,當畫布上有一個或多個元素變化時,必須重新分析整塊畫布,才能得到繪製元素的最優方法。

  許多用戶將整個遊戲的UI都放到一塊畫布,上面擺放了成百上千個元素。因此當修改其中一個元素時,會產生持續數毫秒的CPU使用量飆升情況。

  解決方案:劃分畫布

  每塊畫布上的元素都與其它畫布的元素相隔離,所以我們可以使用工具來切分畫布,從而解決Unity UI的批處理問題。

  我們也可以通過嵌套畫布來解決,這樣允許設計師創建大型分層UI,而且不必擔心不同內容出現在多個畫布上。子畫布的內容與父畫布和同級畫布相互隔離,它們會保持自帶幾何體,執行自己的批處理。

  當使用子畫布分離畫布時,嘗試根據畫布更新時間來分組。例如:分離動態元素和靜態元素。

  Graphic Raycaster的最佳用法

  問題:Graphic Raycaster有哪些最佳用法?

  Graphic Raycaster組件能夠將輸入內容轉換爲UI事件,它會把觸屏輸入轉爲事件,然後發送給相關UI元素。每個接收輸入內容的畫布都需要Graphic Raycaster組件,包括子畫布。

  儘管該組件名爲Graphic Raycaster,但它卻不是個光線投射器,默認情況下它只會測試UI圖形。該組件會獲取特定畫布上輸入信息相關的UI元素集,然後執行交點測試,它會針對Graphic Raycaster的畫布上每個交互式UI元素的RectTransform,檢查輸入事件發生的位置。

  解決方案:關閉靜態或非交互式元素的Raycast Target。

  例如:有一個帶文字的按鈕,關閉該元素的Raycast Target會直接減少Graphic Raycaster每幀進行的交點測試次數。

  問題:有時候Graphic Raycaster會充當光線投射器使用。

  如果將畫布上的渲染模式設爲世界空間攝像機(Worldspace Camera)或屏幕空間攝像機(Screen Space Camera),此時可以設置阻擋遮罩(Blocking Mask)。

  阻擋遮罩決定光線投射器是通過2D物理還是3D物理投射光線,從而瞭解特定物理對象是否阻擋用戶與UI交互。

  解決方案:通過2D或3D物理投射光線會消耗不少性能,所以要謹慎使用該功能。

  儘量減少Graphic Raycaster的數量,不要將Graphic Raycaster添加到非交互式UI畫布上,因爲這樣做無法檢查交互事件。

  避免使用Camera.main

  問題:世界空間畫布需要了解交互事件來自哪個攝像機。

  當設置畫布進行渲染時,不管該畫布是在世界空間還是攝像機的屏幕空間,都可以指定用於爲UI中Graphic Raycaster生成交互事件的攝像機。渲染模式爲“Screen Space - Camera”的畫布需要使用該設置,該設置名爲“Render Camera”。

  然而在渲染模式爲“World Space”的畫布上,該設置是可選的,名爲“Event Camera”。

  如果將世界空間畫布的Event Camera字段留空,這不意味着該畫布不會接收事件。它會使用遊戲的主攝像機。爲了確定哪個攝像機是主攝像機,該畫布會訪問Camera.main屬性。

  根據Unity所使用的代碼路徑,每幀中每有一個Graphic Raycaster和世界空間畫布,該畫布會訪問7到10次Camera.main。每次訪問Camera.main都會調用Object.FindObjectWithTag。這個做法在運行時並不合適。

  解決方案:避免使用Camera.main。

  緩存攝像機的引用,然後創建系統來跟蹤主攝像機。如果使用世界空間畫布,要指定Event Camera,不要將該屬性留空。如果需要修改Event Camera,編寫代碼來更新Event Camera屬性。

  避免使用佈局分組

  問題:每個影響佈局的UI元素都會至少執行一次GetComponents調用。

  當修改佈局系統的一個或多個子元素時,會使佈局變髒。修改後的子元素會使擁有該元素的佈局系統(Layout System)無效化。

  簡單介紹一下佈局系統:佈局系統是一組連續的佈局分組(Layout Group),它們在佈局元素(Layout Element)之上。佈局元素不只是名爲Layout Element的組件,它們還包括UI圖像、文字和Scroll Rect組件,而且Scroll Rect同時也是佈局分組。

  回到問題本身,每個使佈局變髒的UI元素都會至少執行一次GetComponents調用,該調用會在佈局元素父對象上尋找有效的佈局分組。找到有效佈局分組後,它會繼續遍歷Transform層級,直到停止尋找分組或是到達層級的根部分,無論先滿足哪個條件都會停止尋找過程。因此。每個佈局分組會給每個子佈局元素的改變過程添加一次GetComponents調用,使嵌套佈局分組的性能變差。

  解決方案:避免使用佈局分組。

  使用錨點進行比例佈局。在擁有動態元素數量的活躍UI上,考慮編寫代碼來計算佈局,僅在需要時運行該代碼,而不是每次發生改變的時候。

  巧妙地聚集UI對象

  問題:用錯誤的方法聚集UI對象。

  通常情況下,用戶通過重置父對象來聚集UI對象,然後再禁用對象,但這樣會造成不必要的污染。

  解決方案:首先禁用對象,然後將其父對象重置爲對象池。

  這樣操作僅會改變一次原有的層級,但在重置父對象時,要避免二次改變原有的父對象,也不要改變新的層級。如果要從對象池移除對象,首先重置它的父對象,然後更新數據,再啓用該對象。

  如何隱藏畫布

  問題:如何隱藏畫布?

  有時需要隱藏UI元素和畫布,要怎樣高效完成該任務呢?

  解決方案:禁用Canvas組件。

  禁用Canvas組件會阻止畫布向GPU發起繪圖調用,所以該畫布不再可見。然而,此時該畫布不會丟棄它的頂點緩衝區,它會保留所有網格和頂點,當重新啓用時不會觸發重構過程,它只會重新繪製畫布內容。

  此外,禁用Canvas組件不會觸發Canvas層級上性能消耗較大的OnDisable/OnEnable回調。禁用子組件時要小心,注意它是否運行性能消耗較大的每幀代碼。

  UI元素上Animator的最佳用法

  問題:如何在UI上使用Animator?

  Animator每幀都會改變元素,即使動畫中的數值沒有變化。Animator沒有空指令檢查。

  解決方案:

  只在頻繁變化的動態元素上加入Animator。對於很少變化的元素,或是僅響應事件時才變化的元素,請自行編寫代碼或補間系統,你可以在Asset Store資源商店找到許多補間系統插件。

  小結

  提升Unity UI性能的技巧就爲大家分享到這裏,更多關於Unity的優化技巧請訪問Unity官方中文論壇(UnityChina.cn) !

  《行屍走肉:行軍作戰》移動端優化經驗

  在Unity中對森林植被進行優化

  全新優化解決方案:Amplify Impostors

  Unity MMORPG遊戲優化經驗分享

  揭祕《死者之書》之風、場景地形及優化技巧

  UPA性能分析工具使用詳解

  Unity與DeepMind合作推動人工智能研究

  從CAD到Unity-助力汽車行業的實時3D技術

  官方活動

  Unity官方教師培訓報名火熱進行中

  Unity將在10月22-26日,舉辦爲期5天的專業的Unity官方教師培訓課程,誠邀廣大教師與Unity一同學習分享最新技術!

  報名

  https://connect.unity.com/events/2018jiaoshipeixun

  Unity重磅教育活動來襲

  Unity近期將在南京、南昌、上海開展重磅教育活動,歡迎教育領域的領導、專家、教師團隊蒞臨交流!

  優惠活動|Unity訂閱新起航,開啓您的創作之旅

  現在訪問Unity在線商店(store.unity.com),成功訂閱Unity Pro專業版、Unity Plus加強版即可享受全新增值服務組合。11月18日之前訂閱,更有指定插件資源限時贈送。

  活動https://store.unity.com/cn

查看原文 >>
相關文章