Chapter 3 Batching 的优势
这章主要讨论动态批处理(Dynamic Batching)和静态批处理(Static Batching)。GPU Instancing 和 SRP 稍后再讨论。
1. Draw Calls
- Draw Call:CPU 向 GPU 发送的渲染指令。
-
主要分两步:
- 上传纹理数据和网格数据到 GPU
- 使用纹理数据设置网格的渲染
- GPU 在切换渲染状态时消耗很大,SetPass Call 显示切换次数,比 Draw Call 还重要。
2. Materials 和 Shaders
- 每个材质球(Material)引用一个 shader,并定义该 shader 使用的属性值(如颜色、贴图)。
- 当多个对象使用相同的 Material 时,它们更容易被合批,因为 GPU 不需要频繁切换 Render State。
- 即使两个 Material 引用同一个 shader,只要它们的属性值不同(例如不同的主贴图),通常也会被视为不同的 Material,从而无法合批。
- 因此,减少 Material 数量、共享 Material 和使用图集(Atlas)是降低 Draw Call 的重要手段。
3. The Frame Debugger
使用 Frame Debugger 可以帮助我们分析渲染状态,找出不能 batching 的原因。打开方式:Window | Analysis | Frame Debugger。它会逐步显示每一帧的绘制调用,帮助观察:
- 每个对象使用了哪个 shader 和 Material
- 哪些对象被合批,哪些没有
- 不能合批的具体原因(如不同 Material、不同缩放、顶点属性过多等)

4. 动态批处理
-
特点:
- 运行时进行合批
- 可见的物体才可能进行合批
- 可动的物体也可以合批
-
需满足的条件:
- 详见 Unity 官方文档 Draw Call Batching
4.1 顶点属性要求
- 动态合批要求顶点数不能超过 300 个。
- 注意:Unity 加载的模型顶点数和模型原数据顶点数可能不一样,所以最好在 Unity 的 Inspector Preview 窗口中确认顶点数。
- 动态合批要求顶点属性不能超过 900。顶点属性计算:顶点数 × 每个顶点上的属性数。如果使用的 Shader 有 5 个属性,那么顶点数就不能超过 900 / 5 = 180 个。
4.2 Mesh Scaling(网格缩放)要求
- 带有负缩放的对象不能与全为正数缩放的对象一起合批,但可以和其他具有相同数量负轴缩放的对象合批。例如
(-1, 1, 1)可以和(1, -1, 1)合批。
4.3 动态合批要点
- 适用于大量简单模型的场景。
- 如果因为使用不同贴图导致不能合批,可以考虑将贴图合并到一张图中,并重新展 UV。
- 多使用 Frame Debugger 分析不能合批的情况。
- 有时可以调整不同材质物体间的渲染顺序来合批(比如草和石头在一起,可以先渲染草再渲染石头,让同类物体都能动态合批)。
5. 静态合批
5.1 合批要求
- GameObject 需要勾选 Static 选项。
- 需要额外的内存来存放静态批处理后的结果网格。
- 合批的顶点总数有限制:32000–64000 之间。
- 合批对象可以是不同的网格,但必须使用相同的材质球。
5.2 内存问题
- 使用静态合批很有可能增加内存。
- 因为静态合批会把需要合批对象的网格复制一份。如果有 1000 个相同的树,使用静态合批后的内存可能是不使用时的 1000 倍。
5.3 其他需要注意的点
- Draw Call 的降低只能在运行中看到。
- 运行中动态创建并标记为 Static 的对象不会自动被合批。
-
但我们可以使用
StaticBatchUtility.Combine()对动态创建的对象进行静态合批:- 需要注意,这个方式消耗很大,不宜在流畅度敏感期间使用。
- 如果使用
StaticBatchUtility.Combine()的对象没有被标记为 Static,那么它其实是可以被移动的(除了它的网格)。也就是说,可能会移动了 Collider,但网格还停留在原地。这种情况容易产生不期望的 Bug,需要额外注意。