Unity GUI 优化
1.概念
同一 Canvas 下,满足合批规则的多个 UI 元素的网格数据合并到一个顶点缓冲区,仅用一个 DrawCall 提交 GPU 渲染。
2. 合批条件
- 处在同一 Canvas 下
- 共享同一个图集(或相同贴图)以及相同的材质实例
注:相同 Shader 的不同材质实例也不会合批。
- VisibleList 中元素相邻(连续)且 Depth 相同(不被穿插)
3. 合批流程
- 按照 Hierarchy 窗口的层级做深度优先搜索,确定基础的渲染顺序(层级越靠上,越优先渲染)。
- 计算各元素的 Depth。
Depth 计算说明
- 不渲染(
active = false、alpha = 0、完全在裁剪区域外)→ Depth = -1,且不参与合批- 没相交 → Depth = 0
- 相交(网格重叠)时:
- 若二者相同材质实例且同一图集(相同贴图) → 两者 Depth 相等
- 否则,在上方的元素 Depth 需在另一方基础上 +1
- 按照 Depth → Mat ID → Texture ID → Renderer Order(Inspector 面板的顺序)从小到大排序,得到 VisibleList。
注:计算 Depth 时已在考虑材质与纹理;此处的比较是在 Depth 相同的情况下进行。
- 依次检查 VisibleList 的相邻元素是否满足合批条件。
4. 优化方案
- 动静分离(动态与静态 UI 使用不同 Canvas)
- 多个 Canvas 会打断合批,但可减少网格重建所需时间。
- 动态元素还可能破坏 VisibleList,从而增加 DrawCall。
注:Text 与 Image 分离依然有意义——将两种纹理不同的 UI 元素各自挂到两个 Canvas。Text 与 Image 穿插会导致合批中断。
- 避免 UI 元素过多与层级过于复杂,影响合批速度。
- 文本最好用 TextMeshPro 或者图片。
- 减少 Mask 组件使用(增加 2 个 DrawCall,隔离合批空间)。
- 使用图集。
5. 重建
概念
CPU 计算网格;UI 元素的 RectTransform 尺寸与锚点变化、视觉元素的改变,都会使得同一 Canvas 下的所有元素发生网格重建。
注:Unity 将网格重建放在子线程上执行,以降低重建消耗;因此 Unity 官方并不强制要求使用多个 Canvas 来规避重建。
要点速查
| 主题 | 要点 |
|---|---|
| 合批本质 | 同 Canvas + 同材质实例 + 同图集/贴图 + VisibleList 相邻且 Depth 相同 |
| Depth | 重叠且材质/图集不同 → Depth +1,打断合批 |
| 多 Canvas | 打断合批,但利于动静分离、减少重建范围 |
| Text / Image | 分 Canvas,避免穿插 |
| Mask | 慎用,+2 DrawCall |
| 重建 | 同 Canvas 内 RectTransform / 视觉变化会触发全 Canvas 重建 |