动态合批
在动态场景中,例如一场激烈的战斗,许多箭矢在空中飞行,数量众多且材质相同,但由于它们处于运动状态,无法使用静态合批。此时,如果逐个绘制这些箭矢,将会产生大量的绘制命令,导致性能下降。为了解决这个问题,动态合批应运而生。
动态合批的工作原理
动态合批的核心思想是在程序运行时对可合批的对象进行整理和合并,而不是在预处理阶段进行打包。具体流程如下:
-
整理可合批对象:
- 在每次绘制前,动态合批会将可以合并的对象整理在一起。这些对象通常具有相同的材质和简单的网格结构。
-
合并顶点属性:
- 动态合批不会创建新的网格,而是将参与合批的对象的顶点属性连续填充到一个共享的顶点和索引缓冲区中。这样,GPU可以将这些对象视为一个整体进行绘制。
-
发送绘制命令:
- 最后,向GPU发送一次绘制命令,完成所有合批对象的整体绘制。这种方式显著减少了绘制命令的调用次数,提高了渲染效率。
动态合批的注意事项
尽管动态合批相对简单,但在实现过程中仍需注意以下两点:
-
合批并非在绘制前“合并网格”:
-
动态合批不会在绘制前创建新的网格,而是将顶点属性填充到共享的缓冲区中。Unity引擎为每种可以动态合批的渲染器分配了公用的顶点和索引缓冲区,这样可以避免频繁创建缓冲区,提升性能。
-
例如,
MeshRenderer
和SpriteRenderer
在动态合批时使用相同的公用顶点和索引缓冲区,而ParticleSystemRenderer
则使用不同的缓冲区。
-
-
处理顶点的空间变换:
-
在填充数据到缓冲区之前,动态合批会处理每个顶点的信息,将其空间变换到世界坐标系下。这是因为这些对象可能不属于相同的父节点,无法进行统一的空间转换。因此,在送入渲染管线前,必须将每个顶点的坐标转换为世界坐标系下的坐标。
-
在Unity中,合并后对象的顶点着色器内传入的模型矩阵(M矩阵)通常是单位矩阵,以确保正确的空间变换。
-
总结
动态合批是一种有效的渲染优化技术,适用于那些材质相同但处于运动状态的物体。通过在运行时整理和合并顶点属性,动态合批能够显著减少绘制命令的调用次数,从而提升渲染性能。然而,开发者在实现动态合批时需要注意顶点属性的处理和空间变换,以确保渲染的正确性和效率。
Unity动态合批的条件
在Unity中,动态合批是一种优化渲染性能的技术,但它有一些特定的条件和限制。了解这些条件对于有效使用动态合批至关重要。以下是一些主要的动态合批条件:
-
材质球相同:
- 参与动态合批的对象必须使用相同的材质。这是因为动态合批的目的是减少绘制命令的数量,而不同的材质会导致需要分别处理每个材质的绘制。
-
Mesh顶点数量限制:
- 每个参与合批的Mesh的顶点数量不能超过300个。这是为了确保合批的效率和性能。如果顶点数量超过这个限制,合批将会失败。
-
顶点属性限制:
- 每个Mesh的顶点属性总数不能超过900个。这包括位置、法线、UV坐标等所有顶点属性的总和。如果超过这个限制,合批也会失败。
-
缩放限制:
- 参与合批的对象的缩放不能为负值。具体来说,x、y、z三个方向的缩放值的乘积不能为负。这是因为负缩放会导致渲染结果的不确定性,影响合批的有效性。
-
不支持的变换:
- 动态合批不支持具有不同父节点的对象,因为它们的空间变换可能不同,无法统一处理。
-
不支持的渲染状态:
- 某些渲染状态(如混合模式、深度测试等)可能会影响合批的成功与否。确保所有参与合批的对象具有相同的渲染状态。
了解合批失败原因
虽然记住所有的动态合批条件可能比较困难,但你可以通过Unity的Frame Debugger工具来帮助你理解合批失败的原因。Frame Debugger会提供详细的信息,说明为什么某些对象未能合批。通过这些提示,你可以反向了解合批的条件,并在开发过程中进行相应的调整。
总结
动态合批是提升Unity渲染性能的重要技术,但它有一些特定的条件和限制。了解这些条件可以帮助你更有效地使用动态合批,优化游戏性能。通过Frame Debugger获取合批失败的原因,可以进一步加深对动态合批规则的理解,而不必死记硬背每一个条件。
动态合批与静态合批的差别
动态合批和静态合批都是用于优化渲染性能的技术,但它们在实现方式和使用场景上有显著的差别。以下是它们之间的主要区别:
-
内存管理:
- 动态合批:不会创建常驻内存的“合并后网格”。在运行时,动态合批只是在绘制时临时合并顶点数据,因此不会显著增加内存使用,也不会影响打包时的包体大小。
- 静态合批:会在打包时创建合并后的网格,并将其存储在内存中。这意味着静态合批会增加内存占用,并可能影响包体大小。
-
顶点转换:
- 动态合批:在绘制前,会将每个顶点转换到世界坐标系下,然后再填充到顶点和索引缓冲区。这使得动态合批能够处理不同父节点的对象。
- 静态合批:合并后的子网格不接受任何变换操作,只有手动合批后的Root节点可以被操作。因此,静态合批的顶点和索引缓冲区中的信息不会被修改,Root的变换信息通过Constant Buffer传入。
-
性能开销:
- 动态合批:主要的性能开销在于遍历顶点进行空间变换时对CPU的消耗。由于每次绘制都需要进行这些变换,动态合批在CPU性能上可能会有较大的开销。
- 静态合批:没有顶点空间变换的开销,因为静态合批在合并时已经处理了所有的变换。因此,静态合批在性能上通常更高效,尤其是在处理大量静态对象时。
-
缓冲区使用:
- 动态合批:使用根据渲染器类型分配的公共缓冲区。不同类型的渲染器共享相同的顶点和索引缓冲区,以减少内存占用。
- 静态合批:使用自己专用的缓冲区。每个静态合批的对象都有自己的缓冲区,这样可以更好地管理和优化静态对象的渲染。
总结
动态合批和静态合批各有优缺点,适用于不同的场景。动态合批适合于需要频繁变换的动态对象,而静态合批则更适合于不需要变换的静态对象。了解它们之间的差别可以帮助开发者在游戏开发中选择合适的合批策略,以优化性能和资源使用。