前言
本文仅限作者理解如若有什么地方不合理或者有疑惑欢迎各位评论或者私聊讨论。ok我直接看脑图,
我这里呢是把优化区分为4个模块下面我们对每一个模块进行解释与分析。
1.DrawCall优化
对于draw call的解释在这里就不再多说了相信大家也都知道是什么意思,当然我在脑图中也有说到,DrawCall的优化在网是也是有很多的我这里只是挑出几个地方来说,
图集
当然首当其冲的当时是打包图集,因为图集是很有效的降低draw call,如果两张图片在同一个图集中,那么在渲染过程中可以进行合批,(举个例子:两张图片在一个图集是那么draw call就是1 ,不在一个图集时那么两张图片draw call就是2)当然在图集的打包中也要主要图集的大小,当然如果有项目需求也可以进行动态打图集,在一些文字上的使用我们也可以使用图片文字,
Mask组件
看到Mask组件有些同学可能就觉得很奇怪,解释起来也不难,主要是因为添加Mask的UI元素无法与外界UI元素合批,Mask组件还会额外增加2个DrawCall.(简单点说就是有mask组件的ui元素只能与有mask组件的ui元素进行合批,mask本身就会增加draw call)所以对于有mask需求时要谨慎使用
层级关系
都知道Unity的渲染顺序是依照Hierarchy面板的ui顺序,所以我们在UI的排版很重要,很有可能你的一个不小心把两本身可以合批的UI打断了合批,
特效清理
这个呢也是我在网上看到的,意思就是有些时候我们在UI上的特效使用过后对于一下不上常用的特效没有及时的进行处理
2.OverDraw的优化
前面大家也看来很多的文字了总需要来点图片视觉吧,我们可以把unity的Scene窗口的模式条件为OverDraw,然后创建image发现有image的地方会有红色的透明,那么当多个Image叠加的时候就会叠加区域就会越来越明显,这个就是我们的给GPU带来的渲染消耗。
我这里是有两个解决方案,
1.在外面使用Image的Type为Sliced时我们可以将FillCenter设为false(当然只是适用与一些特殊地方,比如:选中框........)
2.就是在网上钱康大大提供的PolygonImage,主要是用来干嘛的呢,就是来进行多边形渲染,当个我们的图片有的地方是透明掏空的地方可以不进行渲染,
看到下图中的翅膀图案图片的左上后右下都已经被掏空了,(当然代码也是不能少的哈)
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// author: Kanglai Qian, SoulGame
/// date: 2016-3-6
/// a Simple script to support Polygon Sprites for UGUI Image in Unity 5
/// just drag it to GameObjects with Image attached
[AddComponentMenu("UI/Effects/PolygonImage",16)]
[RequireComponent(typeof(Image))]
#if UNITY_5_1
public class PolygonImage : BaseVertexEffect
#else
public class PolygonImage : BaseMeshEffect
#endif
{
protected PolygonImage(){ }
#if UNITY_5_1
public override void ModifyVertices(List<UIVertex> verts)
#else
public override void ModifyMesh(VertexHelper vh)
#endif
{
Image 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 UNITY_5_1
if (verts.Count != 4)
{
return;
}
UIVertex vertice;
Vector2 lb = verts[0].position;
Vector2 rt = verts[2].position;
#else
if (vh.currentVertCount != 4)
{
return;
}
UIVertex vertice = new UIVertex();
vh.PopulateUIVertex(ref vertice, 0);
Vector2 lb = vertice.position;
vh.PopulateUIVertex(ref vertice, 2);
Vector2 rt = vertice.position;
#endif
// 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++)
{
vertice = new UIVertex();
// 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(lb.x, rt.x, x), Mathf.Lerp(lb.y, rt.y, y));
vertice.color = image.color;
vertice.uv0 = sprite.uv[i];
vertices.Add(vertice);
}
len = sprite.triangles.Length;
#if UNITY_5_1
verts.Clear();
for (int i = 0; i < len; i+=3)
{
verts.Add(vertices[sprite.triangles[i + 0]]);
verts.Add(vertices[sprite.triangles[i + 1]]);
verts.Add(vertices[sprite.triangles[i + 2]]);
// a degeneration quad :(
verts.Add(vertices[sprite.triangles[i + 0]]);
}
# else
var triangles = new List<int>(len);
for (int i = 0; i < len; i++)
{
triangles.Add(sprite.triangles[i]);
}
vh.Clear();
vh.AddUIVertexStream(vertices, triangles);
#endif
}
}
3..事件检测
这个主要是我们在制作项目中有些UI选手只是来做显示效果但是我们并不需要对它们进行特殊操作,(比如说背景什么的)所以就可以将不需要检测事件的组件的graphic的Raycast Target选项去掉勾选,因为这个检测是实时在检测的。当然有些时候我们要他可以检测事件但是不要他显示时,我们也可以再利用钱康大大提供的另一个代码,下面看代码。(要知道白嫖是程序员的必修课,当然白嫖也要带上大家,嘿嘿~)
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Empty4Raycast : MaskableGraphic
{
protected Empty4Raycast()
{
useLegacyMeshGeneration = false;
}
protected override void OnPopulateMesh(VertexHelper toFill)
{
toFill.Clear();
}
}
4.UI重建
ok经过前面的文字,图片,代码终于来到了这最后一个UI的重建,关于解释呢再脑图里有提到咱就直接上干货啦,
动静分离
动静分离就好比DrawCall优化中的图集一样重要。我这里咱们就简单的解释,都知道重建是以Canvas为单位,那么只要这个canvas需要重建不管里面其他是改变还是未改变的UI都会进行重构,进行布局,渲染,采用动静分离就是为了让一些不需要经常重构的UI不受影响,(就是可以使用两个canvas一个只放静态不改变的UI另一个放需要经常改变的UI)这样一个canvas重建不会使静态UI也进行重构。
最后是一个小的注意点,我们就那image来解释说明把,image大家都熟悉不过当我们去改变它的Color属性时,这个image就会导致整个canvas进行重建,这个时候我们其实是可以给这个image添加材质球进行修改材质球上的颜色(这里就不给图片演示啦,比较简单)。
总结
到这里本文就算是结束啦,在脑图中其实已经写的很清楚这篇文章也只是对脑图的解释和概括。对于UGUI的优化还有很多需要大家学习,特别是draw call网上有很多优化的案例可以看看我这个只是挑了挑给大家解释一下,我也是对我说了解知道的进行了整理,如果还想往下深挖的话可以去看一下UGUI的源码,最后如果觉得本文有帮助到你欢迎点赞收藏!!!