合批
一、什么是合批
- 合批的本质:在满足条件的情况下,将多次绘制请求合并处理,减少 CPU 向 GPU 提交绘制命令的次数。
- 合批的目的:降低 Draw Call 和渲染状态切换带来的 CPU 开销,提高整体渲染效率。
- 合批成立的前提:多个物体的渲染状态足够接近,例如材质、Shader、贴图、光照信息等一致。
二、为什么要合批
- 一次渲染调用会经过: Application -> Runtime -> Driver -> GPU
- 每一次 Draw Call 都不是直接由 GPU 执行,中间还会经过运行时和驱动层。
- Runtime 会先把渲染 API 转换成设备无关命令,再交给 Driver。
- Driver 再将这些命令翻译成 GPU 能识别的指令。
- Draw Call 性能消耗大的重要原因之一,是 CPU 在 Runtime 和 Driver 交互过程中存在较高的提交和状态切换成本。
- 如果场景中批次过多,CPU 会花很多时间处理这些渲染提交,导致渲染效率下降。
三、解决渲染batch(批次)过多的主要方法
- 合批优化
- 优化Driver,降低驱动层性能消耗。
四、Draw Call 为什么会有性能消耗
- 每次渲染命令提交都需要 CPU 参与。
- 命令从 Runtime 到 Driver 的过程中,会带来额外的处理成本。
- 如果每个渲染 API 调用都立即发送到底层,会导致大量重复提交。
- Runtime 中的 CommandBuffer 会把不需要立刻提交的命令先缓冲起来,在合适时机统一发送,从而减少提交成本。
五、合批分类
- 离线合批
- 实时合批
- 实时合批又分为:
- 静态合批
- 动态合批
六、离线合批
1. 适用场景
- 适合静态模型和场景物件
- 例如:地表装饰物、石头、砖块、场景摆件等
2. 常见方式
- 美术在建模工具中直接合批,例如 3D Max 、 Maya
- 使用引擎插件或工具,例如 Unity 的 MeshBaker 、 DrawCallMinimizer
- 根据项目需求,自制离线合批工具
3. 特点
- 提前完成合并,运行时压力更小
- 适合内容稳定、结构清晰的静态场景
七、静态合批
1. 概念
- 在 Unity 中,将物体勾选为 Static 后,Unity 会在构建时自动生成合并后的网格数据。
- 场景加载时,一次性提交这些合并后的顶点数据,减少运行时的提交开销。
2. 条件
- 物体必须标记为 Static
- 通常需要共享相同材质
- 合批后的物体不能再随意移动、旋转、缩放
3. 优点
- 减少 CPU 提交渲染命令的成本
- 降低批次之间的渲染状态切换
- 适合静态场景优化
4. 缺点
- 会增加包体大小
- 会增加运行时内存占用
- 需要额外内存存储合并后的几何体
- 如果原本多个对象共享同一份网格,静态合批后可能为每个对象生成副本,带来更大的内存开销
- 在重复物体非常多的场景中,例如森林,静态合批可能造成明显内存压力
5. 限制
- 大多数平台上有 64k 顶点 和 64k 索引 的限制
6. 理解要点
-
静态合批本质上是 空间换时间
-
它的核心价值是降低 CPU 侧提交和状态切换成本
八、动态合批
1. 概念
- 动态合批用于优化共享同一材质的动态物体。
- 它会在绘制前,把多个小模型的顶点变换到世界空间,然后通过一次绘制提交多个对象。
2. 原理
- 顶点变换操作由 CPU 完成
- Unity 在 CPU 侧先处理这些小网格,再统一提交给 GPU
3. 优点
- 减少小型动态物体的 Draw Call
- 对数量多、顶点少的动态物体有一定优化效果
4. 缺点
- 会增加 CPU 的顶点处理负担
- 如果模型稍微复杂,动态合批的收益可能不明显
5. 常见限制条件
- 单个模型通常要求在 900 顶点 以下
- 如果使用 顶点坐标 + 法线 + UV ,通常最多约 300 顶点
- 如果再使用 UV0 + UV1 + 切线 ,通常最多约 150 顶点
- 两个模型的缩放必须一致,否则不能合批
- 材质球实例必须相同
- 如果使用了 Lightmap,相关数据必须一致才有机会合批
- 使用 Multi-pass Shader 的物体通常不能动态合批
- 延迟渲染下通常无法进行动态合批
6. 理解要点
- 动态合批适合的是 小而多 的动态物体
- 动态合批并不是免费优化,因为 CPU 需要额外做顶点处理
九、静态合批与动态合批对比
静态合批
- 适合不移动的物体
- 主要在构建阶段或加载阶段准备数据
- 优点是 CPU 提交成本低
- 缺点是内存占用较高
动态合批
- 适合运行中会变化的小型物体
- 主要在运行时由 CPU 动态处理
- 优点是减少小物体的绘制提交
- 缺点是 CPU 计算压力增加
十、学习这部分时要抓住的核心
- 合批优化的重点通常在 CPU
- 并不是所有减少 Draw Call 的方法都会提升性能
- 如果为了合批导致内存暴涨、剔除效果变差,反而可能得不偿失
- 判断是否值得合批,必须结合场景实际瓶颈分析
十一、一句话总结
- 合批的本质是: 用更少的渲染提交和更少的状态切换,提高渲染效率
- 静态合批是: 空间换时间
- 动态合批是: 用 CPU 预处理小模型,减少提交次数