鏈接1:Unity 優(yōu)化之UGUI (2017年版【一】) - 簡(jiǎn)書(shū)
視頻地址:https://v.qq.com/x/page/l0329fvbrfn.html
盡可能的讓UI元素合批
首先創(chuàng)建一個(gè)新的場(chǎng)景,攝像camera為Solod Color


可以看到場(chǎng)景中的Barches為1,這是因?yàn)閏amera在做Clear操作
?

然后創(chuàng)建兩個(gè)Button 去掉對(duì)應(yīng)的Text,運(yùn)行unity發(fā)現(xiàn)產(chǎn)生的Batches變?yōu)?
?

當(dāng)兩個(gè)Button進(jìn)行重疊的是時(shí)候,Batches并沒(méi)有變化
?

但是對(duì)有Text的兩個(gè)Button進(jìn)行上面的操作,就會(huì)出現(xiàn)不一樣的效果,重疊后的Batches和未重疊Batches不一致
?

?

按照公開(kāi)課中的說(shuō)法,這種重疊的做法會(huì)打破原有的拓?fù)渑判颍═ext2 與Button2合并),造成Draw Call的合并失敗(Text -Button -Text - Button),當(dāng)然在Hierarchy視圖中也要盡量按照這種拓?fù)渑判虻姆绞竭M(jìn)行UI的層級(jí)擺放。
結(jié)論:在進(jìn)行UI設(shè)計(jì)額時(shí)候盡量少使用來(lái)自不同Atlas的材質(zhì),也盡量避免這種傾軋的情況(Scene視圖調(diào)節(jié)為Writeframe模式可以更容易查看),盡可能把所有的文字放到圖片之上,使用同種字體,更容易進(jìn)行合批
?

接下來(lái)要說(shuō)的就是Mask組件
在一個(gè)新的場(chǎng)景中放圖兩個(gè)Image,然后設(shè)置統(tǒng)一的Packing Tag
?

而且也要在Editor Settings開(kāi)啟圖集選項(xiàng)
?

運(yùn)行前后對(duì)應(yīng)可發(fā)現(xiàn)兩張圖片進(jìn)行了合批
?

?

然后在場(chǎng)景中添加一個(gè)對(duì)應(yīng)的Mask,發(fā)現(xiàn)Batches有所變化,兩個(gè)圖片也進(jìn)行了合批
?

把其中一個(gè)圖片放到mask的遮罩中,發(fā)現(xiàn)圖片無(wú)法合批
?

結(jié)論: 首先一個(gè)Mask組件就會(huì)產(chǎn)生一個(gè)Draw Call,而且在Mask中的圖片無(wú)法與外界的圖片進(jìn)行合批
減少Overdraw
?

根據(jù)上圖的顯示,調(diào)節(jié)到OverDraw模式,顏色越鮮亮的地方造成的OverDraw越大,隨之帶來(lái)的GPU壓力也是越大的
下面來(lái)說(shuō)減少OverDraw的一些策略
在ImageType選項(xiàng)為Sliced的情況下,不需要Fill Center 的時(shí)候去掉勾選
?

作者錢康來(lái)重寫Image相關(guān)組件降低性能消耗
Code Empty4Raycast
using UnityEngine;
using System.Collections;
namespace UnityEngine.UI
{
public class Empty4Raycast : MaskableGraphic
{
protected Empty4Raycast()
{
useLegacyMeshGeneration = false;
}
protected override void OnPopulateMesh(VertexHelper toFill)
{
toFill.Clear();
}
}
}
Code Code PolygonImage
using System.Collections.Generic;
namespace UnityEngine.UI
{
[AddComponentMenu("UI/Effects/PolygonImage", 16)]
[RequireComponent(typeof(Image))]
public class PolygonImage : BaseMeshEffect
{
protected PolygonImage()
{ }
// GC Friendly
private static Vector3[] fourCorners = new Vector3[4];
private static UIVertex vertice = new UIVertex();
private RectTransform rectTransform = null;
private Image image = null;
public override void ModifyMesh(VertexHelper vh)
{
if (!isActiveAndEnabled) return;
if (rectTransform == null)
{
rectTransform = GetComponent<RectTransform>();
}
if (image == null)
{
image = GetComponent<Image>();
}
if (image.type != Image.Type.Simple)
{
return;
}
Sprite sprite = image.overrideSprite;
if (sprite == null || sprite.triangles.Length == 6)
{
// only 2 triangles
return;
}
// Kanglai: at first I copy codes from Image.GetDrawingDimensions
// to calculate Image's dimensions. But now for easy to read, I just take usage of corners.
if (vh.currentVertCount != 4)
{
return;
}
rectTransform.GetLocalCorners(fourCorners);
// Kanglai: recalculate vertices from Sprite!
int len = sprite.vertices.Length;
var vertices = new List<UIVertex>(len);
Vector2 Center = sprite.bounds.center;
Vector2 invExtend = new Vector2(1 / sprite.bounds.size.x, 1 / sprite.bounds.size.y);
for (int i = 0; i < len; i++)
{
// normalize
float x = (sprite.vertices[i].x - Center.x) * invExtend.x + 0.5f;
float y = (sprite.vertices[i].y - Center.y) * invExtend.y + 0.5f;
// lerp to position
vertice.position = new Vector2(Mathf.Lerp(fourCorners[0].x, fourCorners[2].x, x), Mathf.Lerp(fourCorners[0].y, fourCorners[2].y, y));
vertice.color = image.color;
vertice.uv0 = sprite.uv[i];
vertices.Add(vertice);
}
len = sprite.triangles.Length;
var triangles = new List<int>(len);
for (int i = 0; i < len; i++)
{
triangles.Add(sprite.triangles[i]);
}
vh.Clear();
vh.AddUIVertexStream(vertices, triangles);
}
}
}
減少Raycast Target
在對(duì)應(yīng)的Text Image和Rawimage中都有Raycast Target選項(xiàng),這個(gè)選項(xiàng)負(fù)責(zé)接收我們所點(diǎn)擊的事件,但是項(xiàng)目中我們有些UI元素是不需要這些東西,所有可以去掉,減少不必要的性能消耗,可以用RaycastTarget檢測(cè)小工具,他可以在對(duì)應(yīng)的editor模式下,把開(kāi)啟Raycast Target選項(xiàng)的UI以藍(lán)色線框的形式顯示出來(lái),方便大家檢查遺漏的關(guān)閉的UI元素
?

避免網(wǎng)格重建(Canvas.BuildBatch)
?

Canvas.BuildBatch
現(xiàn)在untiy2017版本中Canvas.BuildBatch的主要耗時(shí)已經(jīng)放到了多線程中
網(wǎng)格重建的意思是把Canvas下所有的ui合成一個(gè)Mesh,當(dāng)有UI元素更改的時(shí)候就會(huì)重建這個(gè)Mesh,造成性能消耗。 采取的對(duì)應(yīng)策略就是【動(dòng)靜分離】,在經(jīng)常變動(dòng)的UI元素(位置、顏色、圖片等)上添加Canvas組件,就可以避免因?yàn)閁I的改變?cè)斐烧麄€(gè)Mesh全部重建。當(dāng)然對(duì)于數(shù)量較多需要進(jìn)行顏色漸變的UI元素都添加上canvas顯然不合適,因?yàn)樘砑觕anvas會(huì)增加DrawCall。所以我們需要采用另一個(gè)策略,在Image上添加一個(gè)自定義的material,然后更改這個(gè)material的Tint屬性,這樣既能滿足顏色漸變,又能避免網(wǎng)格頻繁重建造成的性能消耗(實(shí)質(zhì)是避免修改網(wǎng)格上的頂點(diǎn)屬性,造成網(wǎng)格重建)
?

?

?

額外注意的地點(diǎn)
避免使用OutLine組件
避免使用Shadow組件
應(yīng)對(duì)策略:使用Text Mesh Pro插件是一個(gè)不錯(cuò)的選擇(現(xiàn)在已經(jīng)免費(fèi))
避免頻繁使UI元素SetActive(開(kāi)、關(guān)),會(huì)造成網(wǎng)格重建
減少Raycast Target
在對(duì)應(yīng)的Text Image和Rawimage中都有Raycast Target選項(xiàng),這個(gè)選項(xiàng)負(fù)責(zé)接收我們所點(diǎn)擊的事件,但是項(xiàng)目中我們有些UI元素是不需要這些東西,所有可以去掉,減少不必要的性能消耗,可以用RaycastTarget檢測(cè)小工具,他可以在對(duì)應(yīng)的editor模式下,把開(kāi)啟Raycast Target選項(xiàng)的UI以藍(lán)色線框的形式顯示出來(lái),方便大家檢查遺漏的關(guān)閉的UI元素
?

避免網(wǎng)格重建(Canvas.BuildBatch)
?

Canvas.BuildBatch
現(xiàn)在untiy2017版本中Canvas.BuildBatch的主要耗時(shí)已經(jīng)放到了多線程中
網(wǎng)格重建的意思是把Canvas下所有的ui合成一個(gè)Mesh,當(dāng)有UI元素更改的時(shí)候就會(huì)重建這個(gè)Mesh,造成性能消耗。 采取的對(duì)應(yīng)策略就是【動(dòng)靜分離】,在經(jīng)常變動(dòng)的UI元素(位置、顏色、圖片等)上添加Canvas組件,就可以避免因?yàn)閁I的改變?cè)斐烧麄€(gè)Mesh全部重建。當(dāng)然對(duì)于數(shù)量較多需要進(jìn)行顏色漸變的UI元素都添加上canvas顯然不合適,因?yàn)樘砑觕anvas會(huì)增加DrawCall。所以我們需要采用另一個(gè)策略,在Image上添加一個(gè)自定義的material,然后更改這個(gè)material的Tint屬性,這樣既能滿足顏色漸變,又能避免網(wǎng)格頻繁重建造成的性能消耗(實(shí)質(zhì)是避免修改網(wǎng)格上的頂點(diǎn)屬性,造成網(wǎng)格重建)
?

?

?

額外注意的地點(diǎn)
避免使用OutLine組件
避免使用Shadow組件
應(yīng)對(duì)策略:使用Text Mesh Pro插件是一個(gè)不錯(cuò)的選擇(現(xiàn)在已經(jīng)免費(fèi))
避免頻繁使UI元素SetActive(開(kāi)、關(guān)),會(huì)造成網(wǎng)格重建