這兩天跑項目性能,發(fā)現(xiàn)不少問題,其中某系統(tǒng)UI的DrawCall占到了135個之高,給項目的大佬們跪了Orz...UGUI是到這邊項目來之后才接觸的,對它DrawCall合并的規(guī)則有一點點了解,嘗試優(yōu)化的時候發(fā)現(xiàn)能改的地方不多,也就能降低5-10個左右...
下面記錄下一番求助、查找、測試得出的結(jié)論,時間不多,這里沒有原理性的內(nèi)容,全是規(guī)則用來指導(dǎo)日常開發(fā),相對還比較實用吧。
首先感謝丑哥提供的Gad解析文章,還有他的個人博客,高大上又實用。
下面進(jìn)入正題。
1、UGUI元素Depth計算
UGUI內(nèi)部實現(xiàn)用到了Depth(層)的概念,感覺和NGUI開放出來的Depth作用類似,不過一個是內(nèi)部計算得到,一個是手動控制(在這方面NGUI還是非常方便的,真的?。。。?。
UGUI會遍歷所有UI元素(以深度優(yōu)先排序),對當(dāng)前每一個UI元素(CurUI)進(jìn)行如下計算:
- 如果不渲染:CurUI.depth = -1
- 如果渲染,且底下沒有其他元素與其相交(Rect Intersects):CurUI.depth = 0
- 如果底下有元素與其相交,且底下元素Depth最大(MaxLowerDepth)的只有一個,且CurUI與這個元素可以Batch:CurUI.depth = MaxLowerDepth
- 其他:CurUI.depth = MaxLowerDepth + 1
稍微解釋下第3條,如果CurUI下面疊了多個元素,這些元素的最大層是MaxLowerDepth,如果有多個元素的層都是MaxLowerDepth,那么CurUI和下面的元素是無法合批的;如果只有一個元素的層是MaxLowerDepth,并且這個元素和CurUI的材質(zhì)、紋理相同,那么它們就能合批。
2、DrawCall合批(Batch)
上面Depth的計算是合批的關(guān)鍵,得出Depth后合批流程如下:
- 使用多條件Depth、MaterialID、TextureID、RendererOrder(HierarchyOrder)對UI元素進(jìn)行排序(條件的優(yōu)先級依次遞減)
- 剔除depth == -1的元素,得到Batch前的UI元素隊列(VisiableList)
- 對VisiableList中相鄰且可以Batch(相同Material和Texture等)的UI元素合批
3、Mask的坑
UGUI的Mask可以做出很好的遮罩裁剪效果,然而在DrawCall合并上是個大坑...
下面記錄了自己試驗(Unity5.4.1)得出的一些結(jié)論,使用的時候加小心吧。
Mask和RectMask2D最好對比著看,相同序號的內(nèi)容講的是同一個方面。
3.1 Mask
- Mask組件會占用兩個DrawCall,一個在底下設(shè)置Stencil Buffer,一個在頂上還原Stencil Buffer,Mask下的子元素夾在中間
- 如果多個Mask綁定的Image組件,屬于同一個Atlas,那么Mask之間的元素可以進(jìn)行合并(包括Mask自己產(chǎn)生的2個DrawCall);否則不能合并
- Mask外的元素和Mask內(nèi)的元素,無法合批。
- Mask完全裁剪的元素,依然占據(jù)DrawCall
- Hierarchy中被Mask分割的元素,可以正常合批
- Mask裁剪掉的部分還會影響其他元素的Depth計算,而它自己的也會受到其他元素的影響。即:裁剪掉到部分只是不可見,對Depth計算沒有任何影響。
3.2 RectMask2D
- RectMask2D本身不占DrawCall
- RectMask2D之間無法合并DrawCall
- RectMask2D外的元素和RectMask2D內(nèi)的元素,無法合批
- RectMask2D完全裁剪的元素,不再占用DrawCall,也完全不參與Depth計算
- Hierarchy中被RectMask2D分割的元素,如果Depth、Atlas與RectMask2D下的某元素相同,則無法合批。
- RectMask2D裁剪掉的部分,依然參與Depth計算
- 如果RectMask2D上綁定了Image,那么多個RectMask2D的Image如果屬于同一個Atlas可以合并
解釋下第5條,如果同一個圖集上可合批的元素,在Hierarchy中被一個RectMask2D分割在上下兩部分,那么這些元素的合批有可能被打斷。什么情況下會被打斷呢?用N代表要合批元素所在的層,如果RectMask2D中第N層的元素和外面要合批的元素屬于同一個圖集(Atlas),那么這個合批就會被打斷。
4、其他
- UI元素Position的Z值不為0時,會被視為3D UI,不參與合批。父節(jié)點Z != 0,則下面的元素都無法合批了。
- UI元素Rotation的X和Y修改后,若元素不在UI平面內(nèi),則無法合批,原因同上。
例:X=0、X=180時,元素始終保持在UI平面內(nèi),合批是正常的;X=1,元素與UI平面相交,此時無法合批。