资料
Unity3D UGUI系列之合批_unity ui合批-CSDN博客
Unity 3D - Mask和RectMask2D区别-CSDN博客
分析工具
Frame Debugger
查看每个批次渲染情况
Profiler-UI
可看到每帧批次和draw call
UI合批机制和原理
合批流程
描述:将一些元素合并起来,一次渲染绘制多个图形。这将大大降低draw call
基础条件:图形相邻,并且材质,图片完全相同。UGUI会根据材质,图片,层级顺序,遮罩情况等排序,之后将可合批的内容合批。将多个图片打成图集可视为一张图,从而合批。
完整流程:
1.合批以 Canvas为单位,子canvas会视为另一个合批过程。不渲染的canvas会被剔除:透明度为0,长宽为0,在RectMask2D控件下且在RectMask2D的区域外
2.计算depth。depth描述了遮挡关系,如果两个相同图片中间夹了另一张图,他们是不能合批的。
3.各个UI的Depth计算完毕后,依次按照Depth、material ID、texture ID、RendererOrder(即UI层级队列顺序,即Hierarchy面板上的顺序)排序(条件的优先级依次递减,且均为从小到大排序)。然后剔除Depth = -1的UI元素,得到Batch前的UI 元素队列,这个队列被称之为VisiableList。
4.依次检查VisiableList的相邻元素,如果能合批就合批。
- 注意:如果其中任何一个元素的材质、网格顶点、位置(Transform)甚至颜色或者在该Canvas下动态创建或删除UI元素都将导致该Canvas重新计算合批。可通过动静分离隔离动态与静态元素。
- 注意:排序按照texture ID,因此有时会导致图片交换,打断合批。
- 注意:文本的不同字体视为不同的图,使用不同字体会打断合批。
depth计算规则:
按照Hierarchy中从上往下的顺序依次遍历Canvas下所有UI元素
对于当前的UI元素CurrentUI
i.如果CurrentUI不渲染,则Depth = -1
ii.如果CurrentUI要渲染,但CurrentUI下面没有其他UI元素与其相交,则Depth = 0
iii.如果CurrentUI要渲染,下面只有一个UI元素(LowerUI)与其相交,且CurrentUI与LowerUI可以合批(材质和贴图完全相同),则CurrentUI.Depth = LowerUI.Depth;如果两者不能合批,CurrentUI.Depth= LowerUI.Depth + 1
iv.如果CurrentUI要渲染,下面有n个元素与其相交,则按照步骤iii,分别计算出n个Depth(Depth_1、Depth_2、Depth_3...),然后CurrentUI.Depth取其最大值,即CurrentUI.Depth = max(Depth_1, Depth_2, Depth_3,...)
上面步骤中的"下面"和"相交"要明确下意思,这两个概念很重要。
CurrentUI下面的UI,指Hierarchy面板中,在CurrentUI之上的元素。
两个UI元素相交,是指这两个元素的网格有相交(有重叠部分),一定要注意不是两个元素的Rect区域相交。
- 注意:源码中16个元素打组合并计算包围盒
遮罩对合批的影响
两种遮罩:mask和rectmask2D
|--------|-----------------------------------------|----------------|
| | mask | rectmask2D |
| 原理 | 模板测试 | 矩形裁剪 |
| 功能 | 可实现不规则遮罩,支持3D | 仅能实现矩形遮罩,不支持3D |
| 依赖组件 | 需要Image | 无 |
| 增加的批次 | 增加两个批次,用于写入和清空模板缓存,即增加两个材质。如果嵌套,每层加两个批次 | 不增加批次 |
| 对批次的影响 | 外部元素不能和内部元素合批,内部元素可合批 ||
| 对批次的影响 | 相邻mask内元素也不能合批 | 相邻mask内元素可以合批 |
| 性能 | 性能更差 | 性能更优 |
案例测试
一下为一些基本请求的测试,参考层级结构和结果看看实际合批情况,和上文都符合了。
可行的优化方法
- 使用图集,尽量满足合批原理,减少材质贴图种类。
- 像道具图标这种用不了时,可考虑动态图集
- 不同UI字体不可合批,可考虑使用图片替代字体
- 避免频繁修改ui结构,这个流程最常见的就是动画控制。位置,大小,透明度,颜色都会导致重新合批。
- 避免同一个canvasUI元素过多
- 使用canvas隔离合批
- 优先使用rectmask2D,减少使用mask
- 控制canvas的透明度,而不是图形的颜色
- 禁用画布组件来取代隐藏根物体节点(存疑,因为禁用后可减少子物体update)