UGUI合批
UGUI渲染的顺序,就是在Hierarchy窗口中由上到下的顺序,也就是从后向前渲染,因为前面说过,UI是在透明物体的渲染队列当中渲染的。
合批规则
在合批之前,UGUI按照下面的顺序对UI进行分类排序:
判断深度(Depth)——判断材质ID——判断贴图ID——判断渲染顺序(也就是在Hierarchy窗口中的顺序)
在UGUI当中,每个UI的Depth是自己计算的(NGUI是开发者自己填写)
经过上面的筛选,内部会生成一个排序后的List用于判断合批,如果发现在这个List内前后两个UI的材质ID和贴图ID相同,那么这些UI就进行合批(batch),在一次渲染中全部渲染出来。注意Hierarchy窗口内Canvas下UI的顺序和两个UI是否合批没有直接关系。
Depth生成
UI分类排序的第一步,就是确定每一个UI的Depth。
首先,在同一个Canvas下,被关闭的UI的Depth数值为-1,从前面的UGUI源码中可以知道,Depth为-1的UI组件是不会被渲染的。
然后,在Canvas从上到下,越靠上的一般为背景,如果这个UI的“后面(里摄像机较远的一面)”没有其他需要渲染的UI组件,那么这个UI的Depth设为0。
注意这里的“UI的后面”,是前面的UI的Mesh是否覆盖了后面的UI的Mesh,并不是用UI的Rect来判断的
接着向下,如果当前UI的后面,有其他的多个UI组件,那么分别和后面这些UI组件进行比较:
如果当前UI的材质ID和贴图ID和后面的某一个UI相同,那么当前UI的Depth和后面UI的Depth相同;
如果当前UI的材质ID和贴图ID和后面的某一个UI不同,那么当前UI的Depth是后面UI的Depth + 1。
把这个Depth记录下来,当前UI再比较其他的后面的UI组件,在最后得出的Depth集合中,找出最大的Depth,就是当前UI的Depth。
注意,这里不讨论UI的贴图相同但材质不同,或者材质相同但贴图不同的情况。
例:
如上图所示,我们观察一下Depth生成的顺序:
- 白色图片后面什么也没有,Depth是0
- text后面是白色图片,text材质和贴图和白色图片不同,Depth是1
- 红色图片后面是text和白色图片,和text相比,材质和贴图不同,Depth是text的Depth加1,也就是2;和白色图片相比,材质和贴图相同,Depth和白色图片相同,也就是0。最后取最大的Depth,那么红色图片的Depth就是2。
- 黄色图片后面是红色图片,材质和贴图相同,Depth和红色图片相同,也就是2。
- 蓝色图片后面是黄色图片,材质和贴图相同,Depth和黄色图片相同,也就是2。
像上面提到的,“UI的后面”,是前面的UI的Mesh是否覆盖了后面的UI的Mesh,并不是用UI的Rect来判断的,如果我们修改了Text的位置,那么Depth就会改变。
需要注意的是,上面所有的判断Depth的操作,只是一种测试,并不是真正的合批操作。
在确定完了Depth之后,会根据这些信息把UI放在一个List里面,比如在本例中,这个List先把Depth小的UI放进去,即先把白色图片和Text放进去,对于红黄蓝深度相同的UI,先判断这些UI的材质ID或贴图ID(深度相同,贴图和材质可能不同),按照材质和贴图顺序把UI放进List里;如果材质和贴图相同,再按照在Hierarchy窗口的层级顺序将UI放进List当中。
最后会得到一个排好序的List,这个List才是进行最后合批判断的List。
在这个List当中,先剔除深度是-1的UI元素,然后会判断每一个元素之后相邻的元素是否能合批(也是对比材质贴图),然后给这些元素批次号(从0开始),再执行真正的合批操作。
合批的批次号和UI的深度值不是一个概念。
不要被这里举的例子套进去,实际UI渲染中,有些UI即使不相邻,也可能Depth相同,所以有在这个List内再次判断是否能合批的操作。
Frame Debugger
打开Unity的Frame Debugger,在Editor模式下Enable,可以看到合批后的UGUI是如何被一层层渲染的。
Profiler
打开Unity的Profiler,打开Editor模式,然后找到UI Detail,能看到打断各个合批的原因,各个批次里有多少个GameObject以及各个批次中每个GameObject的名字。
合批特殊的例子
下面的排列中,UI图片的排序是有问题的:
可以看到图中的text和白色图片后面都没有东西,此时打开Frame Debugger或Profiler都会发现此时的渲染批次是3。深度如上图标记所示,Unity先渲染了白色图片,然后是text,最后是蓝色图片。但是看我们Hierarchy下,text明明在最上方,它却并不在最终合批List的开头。
我们希望白色图片和蓝色图片能够合批,让Unity先渲染text。方法也很简单,把蓝色图片和白色图片赋予相同的Texture。
注意此时,三张图片的Depth没有改变,只是在最终的List当中,由于白色图片指定了特定的Texture,text成功放在最终合批List的开头了。
总结
两个UI能不能合批,完全取决于最终的合批List中紧挨着的两项UI元素能不能合批,和UI的Depth以及在Hierarchy窗口的层级关系没有直接联系。