1.抛开UGUI的概念,什么是drawcall?什么是批处理?他俩有啥关系?

CPU告诉GPU“可以渲染这个模型”的过程或者说这个命令叫做Draw Call(我们在Stats面板上看到的Batches其实就是Draw Call的调用次数)。在NGUI里甚至有UIDrawCall这个具体的类去抽象一次drawcall。

批处理(UGUI里类似的行为叫合批)就是把渲染时使用相同材质(Shader)、相同贴图的3D模型的网格合并在一起,成为一个大网格,然后再调用一次Draw Call,直接渲染这一个大网格。

关系就是,批处理是降低CPU发起drawcall次数的手段。

2.Unity中我怎么直观的去检查它?

frame debugger可以查看一帧整体的绘制流程,从而观察到UGUI层调了多少次Draw Mesh、每次是怎么样的。

profiler可以更直接的看到一个Canvas下的batch 0、batch 1…

3.基础的UGUI合批规则

无论是UGUI还是NGUI,都以一个基础的合批规则:当前渲染的UI组件与上一个UI组件的material+shader(也就是材质球)、texture(贴图)都需要一致。满足了这个最基本要求才能合批。

4.进阶的UGUI合批规则

首先我们要明确UGUI中Canvas下可以嵌套子Canvas,但是合批是以Canvas(不包含子Canvas)为单位的(子Canvas会是另外一个批次了)。除此之外,合批的操作是在子线程完成的。这段的理解要结合图,详见
① 既然合批是以Canvas为单位,第一步自然就是把所有Canvas给找出来,然后剔除掉不必渲染的Canvas(透明度为0,长宽为0,在RectMask2D控件下,且在RectMask2D的区域外)
② 然后计算Canvas下各UI控件的深度值Depth(需要注意的是Image的属性里面也有个depth,两者不是同一个东西)

③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元素和已计算的底层UI元素(平方复杂度),源码中使用分组计算包围盒矩形的方法加快计算,即16个UI元素为一组计算Group 网格Rect,检查是否与底层UI元素相交时,先计算是否与底层Group相交,如果相交再与Group中的元素做判定。
④各个UI的Depth计算完毕后,依次按照Depth、material ID、texture ID、RendererOrder(即UI层级队列顺序,即Hierarchy面板上的顺序)排序(条件的优先级依次递减,且均为从小到大排序)。然后剔除Depth = -1的UI元素,得到Batch前的UI 元素队列,这个队列被称之为VisiableList。
⑤得到VisiableList之后,判断VisiableList中相邻的元素是否能够合批(相同的材质和贴图)。需要注意这里不再考虑Depth是否相同,只要两个元素相邻然后材质和贴图相同,即使两个元素的Depth不相同,这两个元素也能合批。然后一个批次一个批次的合并网格,提交GPU进行渲染。

除此之外,需要注意的是,合批是将同一Canvas下多个UI的网格合并在一起,如果其中任何一个元素的材质、网格顶点、位置(Transform)甚至颜色或者在该Canvas下动态创建或删除UI元素都将导致该Canvas重新计算合批(需要注意的是仅仅会影响这一个Canvas,子Canvas或父Canvas以及其他Canvas不会重新计算),重新生成新的网格,这个重新计算生成网格的过程被称为rebuild。所以,这也是为什么做UI提倡动静分离(动态部分和静态部分分别用不同的Canvas),层级尽量减少(层级多了,重新计算更耗时)的原因。

5.总结合批规则

合批是自己Canvas内部的规则,排序规则:计算得到的Depth > material ID > texture ID > RendererOrder。计算Depth时会16个UI元素为一组最为包围盒检测,计算Depth和Mesh(UGUI本质)是否相交也有关。会剔除透明度为0、长宽为0、在RectMask2D下在Mask外的UI组件。