一、基本概念
在正式学习UGUI性能优化之前,需要先了解一些基本的概念
- 网格
无论是3D物体还是2D物体,都是由网格绘制而成。需要绘制的网格越多,性能消耗越大。
将Unity编译器调整到Wireframe模式,可以查看当前场景元素的网格组成

下面是一个默认的Image和一个默认的Text网格数量的对比

- Draw Call
Draw Call指在渲染流水线中,CPU向GPU发送的一条指令。通过这条指令,CPU可以通知GPU渲染指定的图元列表

- 填充率
填充率是指显卡每帧或每秒能够渲染的像素数量。如果一个像素被重复渲染了多次,那么它必然会占用更多的资源。
在Unity编译器中开启Overdraw模式,可以查看有哪些像素存在重复渲染

我们将两个Image的一部分重叠放置,就可以观察到重叠部分的颜色会更深一些

- 批处理
批处理就是我们常听的Batch,或者合批。批处理就是把渲染时使用相同材质(Shader)、相同贴图的3D模型的网格合并在一起,成为一个大网格,然后再调用一次Draw Call,直接渲染这一个大网格。这样做可以降低Draw Call的数量,以优化性能。
二、网格重建
在UGUI中,Canvas负责将其下的子UI元素进行合批操作,也就是Batch。当子UI元素发生了变化时,Canvas就需要重新进行Batch操作。Batch操作具体到各个子元素上,就是执行它们各自的Rebuild操作,重新计算元素的布局和网格。Batch和Rebuild加起来构成了所谓的网格重建。
下面我们通过代码跟踪一下整个过程
2.1 Batch
首先在Canvas类中,当Canvas需要进行网格重建时,会调用SendWillRenderCanvases()方法
[RequiredByNativeCode]
private static void SendWillRenderCanvases()
{
Canvas.WillRenderCanvases willRenderCanvases = Canvas.willRenderCanvases;
if (willRenderCanvases == null)
return;
willRenderCanvases();
}
Canvas.willRenderCanvases这个事件是在CanvasUpdateRegistry这个类中注册的。CanvasUpdateRegistry采用了单例模式。它相当于UI元素与Canvas之间的中介,UI元素可以通过它来注册自己的Rebuild方法。
public class CanvasUpdateRegistry
{
private static CanvasUpdateRegistry s_Instance;
// ...
protected CanvasUpdateRegistry()
{
Canvas.willRenderCanvases += PerformUpdate;
}
}
CanvasUpdateRegistry内部提供了两个队列用来保存需要重建的布局元素(通过LayoutGroup布局改变的UI)和Graphics元素(Image、Text等)。UI元素通过CanvasUpdateRegistry暴露的注册API,来将自己添加到这两个队列中。
private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>();
private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>();
接下来是重头戏PerformUpdate(),也就是被注册到Canvas.willRenderCanvases事件的方法。它主要分为三部分,我通过注释的方式予以体现
private void PerformUpdate()
{
UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Lay

最低0.47元/天 解锁文章
9972

被折叠的 条评论
为什么被折叠?



