Unity3D :關於UGUI的網格重建、動靜分離
前言:
無論是網上的攻略還是以前的經驗來說,都說UGUI需要進行動靜分離。也就是說同一個介面下的UI,可活動的元素放在一個Canvas下,不可活動的元素放在另一個Canvas下。雖然兩個Canvas打斷了合批,但是卻減少了網格的重建時間,總體上是有優化的。
究其原因,是因為在同一個Canvas下的某個元素髮生變化時,同一Canvas下的所有元素都會進行網格重建(ReBatch)。而靜態的元素在邏輯上是不需要重建的,因為他們都沒變過,所以需要分開。
但是我在實際進行測試的時候(5.6.6)卻發現在Profile中沒有體現:
建立了200個圖片,其中100個在活動,另外100個靜止。無論是怎麼劃分Canvas,其Rebuild次數始終為200(每一個Image的重建需要呼叫2次Rebuild)。簡單地說,你動靜分離也好,不分離也好,都是變化幾個元素重建幾次,而且從CPU時間來看也沒有任何區別。那是不是說動靜分離沒什麼用了?反正分不分都一樣。
這不是和之前的經驗不一樣嗎?每次面試的時候都有答動靜分離……
正文:
後來在網上諮詢了各路大佬,最終了解到了其中的原因。下面談談我自己的理解(可能有誤,知道大概意思就好)。
參考:
《Fill-rate, Canvases and input》:https://unity3d.com/cn/learn/tutorials/topics/best-practices/fill-rate-canvases-and-input?playlist=30089&tdsourcetag=s_pcqq_aiomsg
《Making the UI Backend Faster》:
《關於Unity中的UGUI優化,你可能遇到這些問題》:https://blog.uwa4d.com/archives/QA_UGUI-1.html
1、網格重建的過程:
UGUI的網格重建分為2部分,一個是ReBatch,一個是ReBuild。
當你的Canvas下的一個元素髮生變化了,就會重新繪製當前Canvas下的所有的可繪製元素,不管其是否變化過。重新計算其圖片、位置、縮放、文字等等元素。這一部分就是ReBatch。之前的動靜分離的工作都是在優化ReBatch,而在之前的Unity(5.2 以前)都還能在Profile裡面看到 Canvas.BuildBatch這個方法的效能消耗。然而這之後的Unity便不能看到他的消耗,只能看到他的一個幾乎不耗時的工作分配(JobAlloc.Grow),至少在5.6.6是這樣的。
而Rebuild在ReBatch之後,是每個UI元素自己的操作。比如A元素變了,而B元素沒有變,那麼A元素就自己改一下自己就好了。至於哪些元素需要Rebuild,則在 Canvas.BuildBatch 裡面就計算好了。
2、5.2以後對Canvas.BuildBatch做的優化
在5.2之後對 Canvas.BuildBatch 流程做了優化,一部分是演算法的優化,另一部分是流程的優化。
演算法不討論。流程方面,在CPU超過一個核心的情況下,Unity將Canvas.BuildBatch流程放在在主執行緒之外,使用多執行緒進行計算。由於不再佔用主執行緒的時間,因此BuildBatch的消耗就可以忽略不計了。由於在另外的執行緒裡面,所以只要那個執行緒沒有超負荷,我們在主執行緒看到的Profile怎麼看都不會有差。
根據文章 《Fill-rate, Canvases and input》的介紹來看,反正是沒有必要建立那麼多的Canvas,幾個畫布就OK了:
In Unity 5.2, the batching code was substantially rewritten, and is considerably more performant compared to Unity 4.6, 5.0 and 5.1. Further, on devices with more than 1 core, the Unity UI system will move most of the processing to worker threads. In general, Unity 5.2 reduces the need for aggressively splitting a UI into dozens of Sub-canvases. Many UIs on mobile devices can now be made performant with as few as two or three Canvases.
總結:
新版的Unity(5.2+)將 Canvas.BuildBatch 放在了其他執行緒進行操作,而現在的手機一般都是多核(驍龍650就是6核了),電腦也是,所以動靜分離的優化不會對幀率造成影響。過多的Canvas反而會打斷合批,增加DrawCall,其實也是需要取捨的。不過即便在別的執行緒裡面操作,也是要進行運算的,運算多一些CPU發熱手機就會降頻,這也是很麻煩的事情。
只能說動靜分離之類的操作在新的版本下沒有那麼有必要,但是也不是沒有沒有用,有點雞肋。
不過在測試的時候,如果使用了上千個變化的UI元素和上千個不變的元素進行測試,還是能發現動靜分離的差別的。其實這個原因猜測是用於計算Canvas.BuildBatch的執行緒耗時已經超過了主執行緒,造成掉幀。不過在一邊的遊戲中,是不存在這麼多UI元素的,所以也不用擔心。