unityUGUI源码:https://github.com/Unity-Technologies/uGUI.git 官方API:https://docs.unity3d.com/cn/2018.4/ScriptReference/Canvas.html
Canvas基础知识
在这里只能讲一些思路,具体实现还是得看项目中运用相对应的处理方式去处理 Canvas是Unity渲染系统给层状几何体( layered geometry(几何) )提供的可以被画入、被放在上面或者放在世界空间的底层Unity组件。Canvas负责将它包含的几何体组合成batch,生成合适的渲染命令发送给Unity图形系统。这个过程在底层的C++代码中完成,这个过程被称为一次rebatch或者一次batch build。当一个Canvas被标记为包含需要rebatch的几何体时,这个Canvas被认为是dirty的。
几何图形由Canvas Renderer 组件提供给 Canvases 。
Sub-canvas只是一个嵌套在另一个 Canvas 组件中的 Canvas 组件。子画布将他们的孩子与他们的父母隔离开来;肮脏的孩子不会强迫父母重建其几何形状,反之亦然。在某些极端情况下这是不正确的,例如当父 Canvas 的更改导致子 Canvas 被调整大小时。
Graphic是 Unity UI C# 库提供的基类。它是为 Canvas 系统提供可绘制几何图形的所有 Unity UI C# 类的基类。大多数内置的 Unity UI 图形都是通过MaskableGraphic子类实现的,这允许它们通过IMaskable接口进行屏蔽。Drawable的主要子类是Image和Text ,它们提供了它们的同名组件。
Layout components control RectTransform 的大小和定位,通常用于创建需要相对大小或相对定位其内容的复杂布局。布局组件仅依赖于 RectTransforms,并且只影响其关联的 RectTransforms 的属性。它们不依赖于 Graphic 类,可以独立于 Unity UI 的 Graphic 组件使用。
Graphic 和 Layout 组件都依赖于CanvasUpdateRegistry类,该类未在 Unity 编辑器的界面中公开。此类跟踪必须更新的 Layout 组件和 Graphic 组件的集合,并在其关联的 Canvas 调用willRenderCanvases事件时根据需要触发更新。
渲染细节
在 Unity UI 中编写用户界面时,请记住所有由 Canvas 绘制的几何图形都将在透明队列中绘制。也就是说,Unity UI 生成的几何图形将始终使用 alpha 混合从后到前绘制。从性能的角度来看,要记住的重要一点是,从多边形栅格化的每个像素都将被采样,即使它完全被其他不透明的多边形覆盖。在移动设备上,这种高水平的过度绘制会迅速超过 GPU 的填充率容量。
批量构建过程(画布)
批处理构建过程是 Canvas 组合表示其 UI 元素的网格并生成适当的渲染命令以发送到 Unity 的图形管道的过程。此过程的结果将被缓存并重复使用,直到 Canvas 被标记为脏,只要其组成网格之一发生更改,就会发生这种情况。 画布使用的网格取自附加到画布但不包含在任何子画布中的一组画布渲染器组件。 计算批次需要按深度对网格进行排序,并检查它们是否存在重叠、共享材料等。此操作是多线程的,因此其性能在不同的 CPU 架构之间通常会有很大差异,尤其是在移动 SoC(通常只有很少的 CPU 内核)和现代桌面 CPU(通常有 4 个或更多内核)之间。
重建过程(图形)
重建过程是重新计算 Unity UI 的 C# 图形组件的布局和网格的地方。这是在CanvasUpdateRegistry类中执行的。请记住,这是一个 C# 类,它的源代码可以在Unity 的 Bitbucket上找到。 在CanvasUpdateRegistry中,感兴趣的方法是PerformUpdate 。每当 Canvas 组件调用WillRenderCanvases事件时,都会调用此方法。此事件每帧调用一次。 PerformUpdate 运行一个三步过程: 通过ICanvasElement.Rebuild方法请求脏布局组件重建其布局。 任何已注册的 Clipping 组件(例如 Masks)都被要求剔除任何被剪裁的组件。这是通过 ClippingRegistry.Cull 完成的。 脏图形组件被要求重建它们的图形元素。 对于布局和图形重建,该过程分为多个部分。布局重建分三个部分(PreLayout、Layout 和 PostLayout)运行,而图形重建分两个部分(PreRender 和 LatePreRender)运行。
布局重建
要重新计算包含在一个或多个布局组件中的组件的适当位置(以及可能的大小),有必要以适当的分层顺序应用布局。在 GameObject 层次结构中更接近根的布局可能会改变可能嵌套在其中的任何布局的位置和大小,因此必须首先计算。 为此,Unity UI 按其在层次结构中的深度对脏布局组件列表进行排序。层次结构中较高的项目(即具有较少父变换的项目)被移动到列表的前面。 然后请求布局组件的排序列表来重建它们的布局;这是由 Layout 组件控制的 UI 元素的位置和大小实际改变的地方。有关单个元素的位置如何受布局影响的更多详细信息,请参阅 Unity 手册的UI 自动布局部分。
图形重建
重建 Graphic 组件时,Unity UI 将控制权传递给ICanvasElement接口的Rebuild方法。Graphic 实现了这一点,并在重建过程的 PreRender 阶段运行两个不同的重建步骤。 如果顶点数据已被标记为脏(例如,当组件的 RectTransform 已更改大小时),则重新构建网格。 如果材质数据已被标记为脏(例如,当组件的材质或纹理已更改时),则附加的 Canvas Renderer 的材质将被更新。 图形重建不会以任何特定顺序通过图形组件列表进行,也不需要任何排序操作。
优化
- Cavas的Render Mode是Overlay模式时,永远覆盖在其他物体之上,不受摄像机depth影响
- Cavas的Render Mode都是Screen Space-Camera时的渲染顺序: 依次由选取的摄像机Render Camera的Depth值、Cavas的Sorting Layer先后顺序(可上下拖动调节顺序)、Order in Layer值决定
同一canvas下: 改变控件transform的SiblingIndex, transform.GetSiblingIndex(); transform.SetSiblingIndex(int index); //index值越大,越后渲染,层级越大,越显示在前面 不同Canvas下: 设置Canvas下的Sort Order //Sort Order值越大,越后渲染,层级越大,越显示在前面 所以,在设计UI的时候要注意每个item(比如这里的Button)中的使用不同图集的UI元素越少越好,且在排列的时候尽量让来自不同图集的UI元素不重叠,一旦重叠,会打乱原来的渲染拓扑关系,造成DC上升 - Canvas里面添加其他UI元件的时候,这些元件实际上就是被这个Canvas统和在一起了。比如,同一个Canvas里面有100个Image,Canvas将会把100个单独的Mesh合并成一个大的ShareMesh,用于渲染。如果刚好这100个Image都是使用了相同的图片或者是同一个图集里面的图片,那么由于使用的Mesh只有一个(ShareMesh),材质球都是同一个(内置的默认材质球),贴图也是同一张,所以得到的结果就是,DrawCall只有一个。
这实际上就是UGUI最基本的优化思路了。合并ShareMesh、合并图集,减少DrawCall,动静分离等 动静分离: 在UGUI中,网格的更新或重建(为了尽可能合并UI部分的DrawCall)是以Canvas为单位的,且只在其中的UI元素发生变动(位置、颜色等)时才会进行。因此,将动态UI元素与静态UI元素分离后,可以将动态UI元素的变化所引起的网格更新或重建所涉及到的范围变小,从而降低一定的开销。而静态UI元素所在的Canvas则不会出现网格更新和重建的开销。 先写这些,后面再加
官方介绍挺详细的:https://learn.unity.com/tutorial/optimizing-unity-ui#5c7f8528edbc2a002053b59f
|