1.DrawCall
1-1.什么是DrawCall:
CPU調(diào)用命令GPU進(jìn)行渲染的操作。
1-2..CPU和GPU并行工作的原理:
CPU和GPU并行工作依賴一個(gè)東西:命令緩沖區(qū)(Command Buffer)。命令緩沖區(qū)包含了一個(gè)命令隊(duì)列,由CPU向其中添加命令,而由GPU從中讀取命令。添加和讀取的過程是相互獨(dú)立的,因此命令緩沖區(qū)可以使CPU和GPU相互獨(dú)立工作。當(dāng)CPU需要渲染一些對(duì)象時(shí),它可以向命令緩沖區(qū)添加命令,而GPU完成了上一次的渲染任務(wù)后,它就可以從命令隊(duì)列里取出一個(gè)命令并執(zhí)行它。
1-3.為什么要優(yōu)化DrawCall?
CPU處理提交drawCall的操作是串行的,大量的提交零散的DrawCall,GPU在提交的DrawCall隊(duì)列里可以多次處理多個(gè)DrawCall。而GPU渲染的并行速度是很快的,大量的DrawCall會(huì)導(dǎo)致GPU等待CPU。優(yōu)化DrawCall可以讓CPU與GPU的執(zhí)行效率增大。
2.Ugui的DrawCall
2-1.Ugui的DrawCall與畫布排序原則
Ugui畫布排序是按類型排序的,只要兩種UI元素不發(fā)生重疊,Ugui會(huì)自動(dòng)按類型合并DrawCall,在界面設(shè)計(jì)與UI原型設(shè)計(jì)時(shí)應(yīng)該避免多個(gè)UI元素重疊的問題,這樣可減少后期的優(yōu)化壓力。
Mask組件
Mask組件基于模板緩存制作的。一個(gè)Mask組件會(huì)產(chǎn)生4個(gè)DrawCall
一、RectMask2D
RectMask2D不需要依賴一個(gè)Image組件,其裁剪區(qū)域就是它的RectTransform的rect大小。
性質(zhì)1:RectMask2D節(jié)點(diǎn)下的所有孩子都不能與外界UI節(jié)點(diǎn)合批且多個(gè)RectMask2D之間不能合批。
性質(zhì)2:計(jì)算depth的時(shí)候,所有的RectMask2D都按一般UI節(jié)點(diǎn)看待,只是它沒有CanvasRenderer組件,不能看做任何UI控件的bottomUI。
二、Mask
Mask組件需要依賴一個(gè)Image組件,裁剪區(qū)域就是Image的大小。
性質(zhì)1:Mask會(huì)在首尾(首=Mask節(jié)點(diǎn),尾=Mask節(jié)點(diǎn)下的孩子遍歷完后)多出兩個(gè)drawcall,多個(gè)Mask間如果符合合批條件這兩個(gè)drawcall可以對(duì)應(yīng)合批(mask1 的首 和 mask2 的首合;mask1 的尾 和 mask2 的尾合。首尾不能合)
性質(zhì)2:計(jì)算depth的時(shí)候,當(dāng)遍歷到一個(gè)Mask的首,把它當(dāng)做一個(gè)不可合批的UI節(jié)點(diǎn)看待,但注意可以作為其孩子UI節(jié)點(diǎn)的bottomUI。
性質(zhì)3:Mask內(nèi)的UI節(jié)點(diǎn)和非Mask外的UI節(jié)點(diǎn)不能合批,但多個(gè)Mask內(nèi)的UI節(jié)點(diǎn)間如果符合合批條件,可以合批。
從Mask的性質(zhì)3可以看出,并不是Mask越多越不好,因?yàn)镸ask間是可以合批的。得出以下結(jié)論:
當(dāng)一個(gè)界面只有一個(gè)mask,那么,RectMask2D 優(yōu)于 Mask
當(dāng)有兩個(gè)mask,那么,兩者差不多。
當(dāng) 大于兩個(gè)mask,那么,Mask 優(yōu)于 RectMask2D。
2-2合并圖集
注意動(dòng)態(tài)加載的圖與模塊相關(guān)的圖分離。太大的圖集不在動(dòng)態(tài)加載行列產(chǎn)生內(nèi)存浪費(fèi)。這些可根據(jù)自己的策略做選擇。
2-3動(dòng)靜分離
這里指的是所有的UI資源,包括元素,圖片,圖集等。
這里優(yōu)化點(diǎn)有兩個(gè):
1.Canvas.BuildBatch
2.Canvas.SendWillRenderCanvases
優(yōu)化網(wǎng)格重建
一般把動(dòng)態(tài)的元素放在一個(gè)Canvas里,沒有動(dòng)態(tài)效果的靜態(tài)元素放在Canvas。移動(dòng)位置,縮放大小,這些都會(huì)觸發(fā)網(wǎng)格重建。
但是如果只是非常大量的動(dòng)態(tài)元素,每個(gè)掛載Canvas是會(huì)產(chǎn)生大量的DrawCall,可以考慮使用代碼動(dòng)態(tài)掛載Canvas。達(dá)到動(dòng)靜分離的目的,不需要時(shí)再刪除Canvas。
UI上全用Image 的Color屬性,會(huì)直接修改UI網(wǎng)格的頂點(diǎn)顏色屬性,會(huì)觸發(fā)網(wǎng)格重建。所以這里我們可以給image加入一個(gè)材質(zhì),直接修改這個(gè)材質(zhì)上的color屬性。這個(gè)不會(huì)直接修改頂點(diǎn)屬性。不會(huì)觸發(fā)網(wǎng)格重建,從而達(dá)到優(yōu)化目的。
避免使用OutLine,Shadow組件。使用Text Mesh Pro代替
避免頻繁使UI元素SetActive(開、關(guān)),會(huì)造成網(wǎng)格重建,考慮使用CanvasGroup。
3.OverDrall
*這個(gè)模塊的優(yōu)化,遵循的原則是,重疊的元素越少,越不容易產(chǎn)生OverDrall。
3-1.Image相關(guān)優(yōu)化
3-1-1Image組件使用Image Type為Sliced:去掉Image的 Fill Center模式(九宮格),可以鏤空一些UI元素的中間不需要拉伸的區(qū)域,可以減少OverDrall的產(chǎn)生。
3-1-2 Image組件使用Image Type為Slimple:復(fù)雜的圖案,中間或者邊上有很多透明區(qū)域的圖,可以使用Use Sprite Mesh這個(gè)選項(xiàng)。打上勾,可以按網(wǎng)格方式渲染圖片,犧牲內(nèi)存來優(yōu)化這部分OverDrall。(unity2017以上版本才有此功能,以下版本可以網(wǎng)上參考實(shí)現(xiàn)的代碼)
3-1-3 使用Image組件接收Ugui點(diǎn)擊事件,實(shí)現(xiàn)界面事件的方式。Image只要打開,不管設(shè)置的圖片是否為空,依然會(huì)產(chǎn)生OverDrall。如果在項(xiàng)目中存在大量的這種元素。優(yōu)化的作用還是可觀的。建議繼承unity類來解決。
可以參考錢康來寫的如下代碼:
using UnityEngine;
using System.Collections;
namespace UnityEngine.UI
{
public class Empty4Raycast : MaskableGraphic
{
protected Empty4Raycast()
{
useLegacyMeshGeneration = false;
}
protected override void OnPopulateMesh(VertexHelper toFill)
{
toFill.Clear();
}
}
}
4.減少CPU耗時(shí)
減少Raycast Target
Raycast Target即使在你沒使用時(shí),依然會(huì)產(chǎn)生CPU計(jì)算。這樣的東西是沒必要的,雖然一個(gè)這樣的計(jì)算微乎其微。但是優(yōu)化的東西,就是一點(diǎn)點(diǎn)積累的。--不以善小而不為,不以惡小而為之。這里建議在項(xiàng)目前期就加入去除Raycast Target工具,這里可以參考我的另一個(gè)文章:Ugui創(chuàng)建組件去除RaycastTarget 屬性
如果項(xiàng)目到達(dá)中期,那就借助工具優(yōu)化吧:RaycastTarget檢測(cè)小工具