使用动态批处理¶
动态批处理将兼容的网格分组为批次并合并其渲染数据,使 Kanzi 能够以更少的绘制调用渲染多个网格。
减少绘制调用可以降低提交渲染命令和更改渲染状态的 CPU 开销,从而在包含许多兼容网格的场景中提升渲染性能。
动态批处理也会带来 CPU 处理开销。特别是重建批次会增加 CPU 负载,因此动态批处理可能不太适合频繁创建或销毁对象的内容。
要使用动态批处理,请为要批处理的网格启用动态批处理,配置动态批处理渲染通道,设置批次大小,并调整批处理网格所使用的着色器。
要使用动态批处理,您必须:
为要批处理的网格启用 Dynamic Batching 属性。
使用动态批处理渲染通道渲染这些网格。
根据一个批次中对象的最大数量设置 Batch Uniform Count。
手动或使用 Kanzi Studio 中的着色器转换工具调整批处理网格所使用的着色器。
性能示例¶
在运行 Android 12 的设备(SM8475 / Adreno 730)上进行的测试中,启用动态批处理使应用程序的平均 CPU 使用率降低了约 27.8%,而帧率保持在约 30 FPS。
两次运行各持续约 300 秒,帧率上限为 30 FPS,禁用了 TAA 和 MSAA,并禁用了 Idle。未使用动态批处理的运行包含 150 个样本;使用动态批处理的运行包含 133 个样本。表中显示的是样本平均值。
指标 |
未使用动态批处理 |
使用动态批处理 |
|---|---|---|
应用程序 CPU 使用率(100% = 一个 CPU 核心) |
24.43% |
17.64% |
帧速率 |
29.98 FPS |
29.99 FPS |
GPU Busy |
67.74% |
69.14% |
剖析程序报告的图形内存 |
1087.30 MB |
1092.83 MB |
在此测试中,主要优势是在相同帧速率下降低了应用程序 CPU 使用率。GPU Busy 增加了 1.40 个百分点,报告的图形内存增加了 5.53 MB。结果取决于场景和目标设备。请对您的内容进行剖析,以确定动态批处理是否能提高性能。
动态批处理的条件和限制¶
动态批处理根据网格的渲染属性对网格进行分组。某些属性决定网格能否放入同一批次,而一致的顶点特性有助于减少额外处理。
材质 (Material)¶
动态批处理按材质名称对网格进行分组。如果网格的材质名称相同,并且满足其他批处理条件,则可以将这些网格考虑放入同一批次。
混合模式¶
同一批次中的所有网格必须使用相同的混合模式。
将不透明网格和透明网格放在不同的批次中。例如,为不透明网格和透明网格使用不同的标签或对象源。
请参阅 使用 Tag Filter。
顶点特性¶
为获得最佳效果,请为批次中的所有网格使用相同的顶点特性。
当批次中的网格具有不同的顶点特性时,动态批处理会将顶点特性数量最多的网格用作标准网格。
对于批次中的其他网格:
如果标准网格具有某个其他网格没有的顶点特性,动态批处理会为该网格创建该特性并用
0填充。如果其他网格具有标准网格没有的顶点特性,动态批处理会丢弃该特性。
为减少额外处理并避免丢弃顶点数据,请为同一批次中的网格使用一致的顶点特性。对于有特殊顶点特性要求的网格,例如使用两组纹理坐标的网格,请考虑不启用动态批处理。
请参阅 优化网格。
不支持的网格¶
动态批处理不支持:
蒙皮网格。
使用变形的网格。
不要为这些网格启用 Dynamic Batching。
配置动态批处理¶
为网格启用动态批处理¶
要为网格启用动态批处理:
选择要进行批处理的网格。
在 Properties 中,启用 Dynamic Batching 属性。
Dynamic Batching 默认处于禁用状态。
只有启用了 Dynamic Batching 的网格才会参与动态批处理。
选择动态批处理渲染通道¶
Kanzi 提供以下动态批处理渲染通道:
动态批处理渲染通道 (Dynamic Batching Render Pass)
动态批处理 UBO 渲染通道 (Dynamic Batching UBO Render Pass)
用材质动态批处理渲染通道 (Dynamic Batching With Material Render Pass)
用材质动态批处理 UBO 渲染通道 (Dynamic Batching UBO With Material Render Pass)
动态批处理节点列表渲染通道 (Dynamic Batching Node List Render Pass)
使用 Dynamic Batching Render Pass 或 Dynamic Batching UBO Render Pass 代替绘图对象渲染通道 (Draw Objects Render Pass)。
使用 Dynamic Batching With Material Render Pass 或 Dynamic Batching UBO With Material Render Pass 代替用材质渲染通道绘制对象 (Draw Objects With Material Render Pass)。配置 With Material 变体的方式与配置常规的用材质渲染通道绘制对象 (Draw Objects With Material Render Pass) 相同。
常规变体与 UBO 变体的主要区别在于着色器存储和接收批处理数据的方式。
使用动态批处理渲染通道 (Dynamic Batching Render Pass)¶
- 如果要将每个网格的批处理数据存储在常规 Uniform 数组中,请使用 Dynamic Batching Render Pass。
您希望使用更简单的着色器数据布局。
批处理使用的每网格数据量相对较少。
您不需要将批处理数据存储在 Uniform 缓冲区对象中。
如果没有使用 UBO 动态批处理的特定原因,请使用 Dynamic Batching Render Pass。
使用动态批处理 UBO 渲染通道 (Dynamic Batching UBO Render Pass)¶
Dynamic Batching UBO Render Pass 将动态批处理数据存储在 Uniform 缓冲区对象 (UBO) 中。
- 在以下情况下,请考虑使用 Dynamic Batching UBO Render Pass:
您希望将批处理数据保存在 Uniform 块中。
着色器包含更多每个批次都要更新的数据。
在目标设备上进行剖析的结果表明,UBO 路径更适合该渲染工作负载。
常规变体与 UBO 变体的主要区别在于着色器数据布局:
Dynamic Batching Render Pass 和 Dynamic Batching With Material Render Pass 使用常规 Uniform 数组。
Dynamic Batching UBO Render Pass 和 Dynamic Batching UBO With Material Render Pass 使用
DynamicBatchUBOUniform 块。
对于性能敏感的工程,请在目标设备上对这两种方法进行剖析,并使用对您的内容性能更好的那一种。
使用 With Material 和 Node List 变体¶
如果需要与用材质渲染通道绘制对象 (Draw Objects With Material Render Pass) 等效的动态批处理渲染通道,请使用 Dynamic Batching With Material Render Pass。
对于 UBO 变体,请使用 Dynamic Batching UBO With Material Render Pass。
配置这些渲染通道的方式与配置常规的用材质渲染通道绘制对象 (Draw Objects With Material Render Pass) 相同。
如果渲染通道树使用节点列表渲染通道收集要进行动态批处理的网格,请将其替换为 Dynamic Batching Node List Render Pass。配置它的方式与配置常规的节点列表渲染通道相同。
如果渲染通道树没有为这些网格使用节点列表渲染通道,则无需进行此更改。
With Material 变体与其对应的动态批处理渲染通道具有相同的动态批处理、批处理 Uniform 数量和着色器要求。
配置渲染通道¶
为动态批处理配置渲染通道:
将渲染这些网格的渲染通道替换为相应的动态批处理渲染通道:
对于常规动态批处理,将绘图对象渲染通道 (Draw Objects Render Pass) 替换为 Dynamic Batching Render Pass;对于 UBO 动态批处理,则替换为 Dynamic Batching UBO Render Pass。
对于常规动态批处理,将用材质渲染通道绘制对象 (Draw Objects With Material Render Pass) 替换为 Dynamic Batching With Material Render Pass;对于 UBO 动态批处理,则替换为 Dynamic Batching UBO With Material Render Pass。
配置 With Material 变体的方式与配置常规的用材质渲染通道绘制对象 (Draw Objects With Material Render Pass) 相同。
在动态批处理渲染通道中,将 Object Source 设置为收集要进行批处理的网格的对象源。
例如,使用标签过滤器 (Tag Filter) 收集网格。请参阅 使用 Tag Filter。
备注
已启用 Dynamic Batching 的网格必须使用动态批处理渲染通道进行渲染,并且该网格使用的材质着色器必须支持动态批处理。如果常规的绘图对象渲染通道 (Draw Objects Render Pass) 收集了此类网格,该网格仍保留在 Preview 的场景中,但不会显示。如果动态批处理渲染通道收集了该网格,但其材质着色器尚未针对动态批处理进行调整,该网格同样不会在 Preview 中显示。启用 Dynamic Batching 后,请同时配置渲染通道和材质着色器。
设置 Batch Uniform Count¶
Batch Uniform Count 设置动态批处理渲染通道在一个批次中可以处理的最大对象数。该值必须与着色器中相应批处理数组的尺寸一致。
要设置 Batch Uniform Count:
确定在动态批处理渲染通道所使用的标签或对象源中,可同时可见的静态和动态批处理对象的最大数量。
将 Batch Uniform Count 设置为不小于该数量的值。
例如,如果批处理对象的最大数量为 25,请将 Batch Uniform Count 设置为至少
25。
非 UBO 和 UBO 动态批处理的常规变体和 With Material 变体均使用 25 作为默认的 Batch Uniform Count。
如果目标设备支持,您可以使用更大的值。请避免使用不必要的过大值。一般而言,请使用 100 或更小的值。
可用的最大值取决于目标设备上可用的 Uniform 资源。
备注
Batch Uniform Count 必须与着色器中每个相应批处理数组的尺寸一致。
例如,当 Batch Uniform Count 设置为 25 时,常规动态批处理着色器使用:
uniform highp mat4 BatchWorldMatrix[25];
uniform highp mat4 BatchNormalMatrix[25];
如果将 Batch Uniform Count 更改为 50,请将相应的着色器数组尺寸也更改为 50。
对于 UBO 动态批处理,同样适用此要求:
layout(std140, binding = 2) uniform DynamicBatchUBO
{
highp mat4 BatchNormalMatrix[25];
highp mat4 BatchWorldMatrix[25];
};
调整着色器以支持动态批处理¶
动态批处理网格所使用的材质着色器必须支持动态批处理。
仅启用 Dynamic Batching 并配置动态批处理渲染通道是不够的。如果材质着色器尚未针对动态批处理进行调整,即使动态批处理渲染通道收集了该网格,该网格也不会显示在 Preview 中。
您可以通过以下任一方式调整着色器:
使用 Kanzi Studio 中的着色器转换工具。
手动修改着色器。
请尽可能使用着色器转换工具。当该工具无法处理特定于着色器的要求时,请手动修改着色器。
不要将动态批处理着色器更改应用于与动态批处理不兼容的材质。例如,不要修改 DefaultBlit 或位块传送渲染通道 (Blit Render Pass) 所使用的其他材质。
手动修改着色器以支持常规动态批处理¶
使用 GLSL ES 3.10¶
#version 310 es
添加 BatchId¶
添加 BatchId 顶点特性:
in int BatchId;
BatchId 标识着色器使用其逐网格数据的批处理网格。使用 BatchId 对批处理数组进行索引。
使用批处理矩阵¶
声明世界矩阵数组和法线矩阵数组。对于值为 25 的 Batch Uniform Count:
uniform highp mat4 BatchWorldMatrix[25];
uniform highp mat4 BatchNormalMatrix[25];
使用 BatchId 获取当前网格的矩阵:
mat4 WorldMatrix = BatchWorldMatrix[BatchId];
mat4 NormalMatrix = BatchNormalMatrix[BatchId];
例如,在变换顶点位置时使用 WorldMatrix:
gl_Position =
kzProjectionMatrix *
kzCameraMatrix *
WorldMatrix *
vec4(objPos, 1.0);
当着色器变换法线时,请使用 BatchNormalMatrix[BatchId],而不是常规的逐对象法线矩阵。请参阅 编辑着色器。
完整着色器示例¶
以下示例展示了针对常规动态批处理调整后的完整顶点着色器和片段着色器。
顶点着色器 (Vertex Shader):
#version 310 es
precision mediump float;
in vec3 kzPosition;
in vec2 kzTextureCoordinate0;
in int BatchId;
uniform highp mat4 kzProjectionCameraWorldMatrix;
uniform vec2 TextureOffset;
uniform vec2 TextureTiling;
uniform highp mat4 kzCameraMatrix;
uniform highp mat4 kzProjectionMatrix;
uniform highp mat4 BatchWorldMatrix[25];
flat out highp int vBatchID;
out vec2 vTexCoord;
void main()
{
mat4 WorldMatrix = BatchWorldMatrix[BatchId];
vBatchID = BatchId;
vTexCoord = kzTextureCoordinate0 * TextureTiling + TextureOffset;
gl_Position =
kzProjectionMatrix *
kzCameraMatrix *
WorldMatrix *
vec4(kzPosition.xyz, 1.0);
}
片段着色器 (Fragment Shader):
#version 310 es
precision mediump float;
uniform sampler2D Texture;
uniform float BlendIntensity[25];
in vec2 vTexCoord;
flat in highp int vBatchID;
out highp vec4 outColor;
void main()
{
vec4 color = texture(Texture, vTexCoord);
outColor = color * BlendIntensity[vBatchID];
}
手动修改着色器以支持 UBO 动态批处理¶
UBO 动态批处理使用与常规动态批处理相同的 BatchId 索引原理,但将批处理矩阵存储在 DynamicBatchUBO Uniform 块中。
使用 GLSL ES 3.10¶
#version 310 es
添加 BatchId¶
添加 BatchId 顶点特性:
in int BatchId;
声明 DynamicBatchUBO¶
在 DynamicBatchUBO 中声明批处理矩阵:
layout(std140, binding = 2) uniform DynamicBatchUBO
{
highp mat4 BatchNormalMatrix[25];
highp mat4 BatchWorldMatrix[25];
};
数组尺寸必须与 Dynamic Batching UBO Render Pass 中的 Batch Uniform Count 一致。
将 BatchId 用于 UBO 矩阵¶
使用 BatchId 获取当前网格的矩阵:
mat4 WorldMatrix = BatchWorldMatrix[BatchId];
mat4 NormalMatrix = BatchNormalMatrix[BatchId];
如果需要在片段着色器中使用批次 ID,请在顶点着色器中声明此 output:
flat out highp int vBatchID;
在顶点着色器的 main 函数中赋值:
vBatchID = BatchId;
完整着色器示例¶
以下示例展示了针对 UBO 动态批处理调整后的完整顶点着色器和片段着色器。
顶点着色器 (Vertex Shader):
#version 310 es
precision mediump float;
in vec3 kzPosition;
in vec2 kzTextureCoordinate0;
in int BatchId;
uniform highp mat4 kzProjectionCameraWorldMatrix;
uniform vec2 TextureOffset;
uniform vec2 TextureTiling;
uniform highp mat4 kzCameraMatrix;
uniform highp mat4 kzProjectionMatrix;
layout(std140, binding = 2) uniform DynamicBatchUBO
{
highp mat4 BatchWorldMatrix[25];
};
flat out highp int vBatchID;
out vec2 vTexCoord;
void main()
{
mat4 WorldMatrix = BatchWorldMatrix[BatchId];
vBatchID = BatchId;
vTexCoord = kzTextureCoordinate0 * TextureTiling + TextureOffset;
gl_Position =
kzProjectionMatrix *
kzCameraMatrix *
WorldMatrix *
vec4(kzPosition.xyz, 1.0);
}
片段着色器 (Fragment Shader):
#version 310 es
precision mediump float;
uniform sampler2D Texture;
uniform float BlendIntensity;
in vec2 vTexCoord;
flat in highp int vBatchID;
out highp vec4 outColor;
layout(std140, binding = 2) uniform DynamicBatchUBO
{
highp mat4 BatchWorldMatrix[25];
};
void main()
{
vec4 color = texture(Texture, vTexCoord);
outColor = color * BlendIntensity;
}
分别控制批处理网格的材质属性¶
同一批次中的网格可以使用相同的材质,同时其材质属性仍可具有不同的值。
例如,如果每个网格需要不同的值:
uniform float BlendIntensity;
请将该 Uniform 改为数组:
uniform float BlendIntensity[25];
数组大小必须与 Batch Uniform Count 一致。
以下示例使用常规的 Uniform 数组语法。使用 UBO 动态批处理时,BatchId 索引原理相同。
将 BatchId 传递给片段着色器¶
如果片段着色器需要每个网格各自的值,请将批次 ID 从顶点着色器传递给片段着色器。
在顶点着色器中声明:
flat out highp int vBatchID;
在顶点着色器的 main 函数中赋值:
vBatchID = BatchId;
在片段着色器中声明:
flat in highp int vBatchID;
使用 vBatchID 索引每个网格各自的值。例如,将:
BlendIntensity
替换为:
BlendIntensity[vBatchID]
例如:
uniform float BlendIntensity[25];
...
float intensity = BlendIntensity[vBatchID];
使用 flat 限定符,使整数批次 ID 不会在顶点着色器和片段着色器之间进行插值。
使用着色器转换工具¶
Kanzi Studio 提供着色器转换工具,可调整已启用 Dynamic Batching 的网格所使用的材质。使用这些工具时,您可以跳过上述大部分手动着色器更改。
要转换材质以进行动态批处理:
在主菜单中,选择与动态批处理渲染通道相对应的工具:
对于 Dynamic Batching Render Pass 和 Dynamic Batching With Material Render Pass,选择 Tools > Dynamic Shaders。
对于 Dynamic Batching UBO Render Pass 和 Dynamic Batching UBO With Material Render Pass,选择 Tools > Dynamic UBO Shaders。
在 Material 列表中,选择要转换的材质。
该列表包含已启用 Dynamic Batching 的网格所使用的材质。
升级所选材质以进行动态批处理。
Kanzi Studio 会打开变量选择窗口。初始升级和 Update Variables 使用相同的变量选择布局。
在 All Variables 中,Kanzi Studio 将着色器变量分为以下几组:
Variables already present on the node:Kanzi Studio 检测到已在网格上设置的材质属性所对应的变量。
Other Variables:可选择用于动态批处理的其他着色器变量。
在 All Variables 中,选择批次中每个网格必须具有单独值的变量。
Kanzi Studio 会将所选变量添加到 Selected Variables。
该工具会将所选的每网格变量转换为批处理数组,并使用批次 ID 对其进行索引。
检查 Selected Variables,然后点击 OK。
Kanzi Studio 会更新着色器以进行动态批处理。
备注
Kanzi Studio 处理完着色器后,预览可能不会立即更新。如果预览仍显示之前的结果,请重新启动预览。
更新批处理变量¶
转换材质以进行动态批处理后,着色器转换工具会提供 Update Variables 命令。
当您添加或更改材质属性时,或者当您要更改为动态批处理而处理的着色器变量时,请使用 Update Variables。
要更新批处理变量:
在 Tools > Dynamic Shaders 或 Tools > Dynamic UBO Shaders 中,在 Material 列表中选择已转换的材质。
点击 Update Variables。
Kanzi Studio 打开 Update Batched Variables 窗口。该窗口使用与初始材质升级相同的变量选择布局。
在 All Variables 中,选择要处理的变量。
Kanzi Studio 检测到已在网格上设置的材质属性所对应的变量列在 Variables already present on the node 下。其他变量列在 Other Variables 下。
Selected Variables 列表显示为动态批处理选择的变量。
点击 OK 以更新着色器。
还原材质¶
要还原转换工具所做的动态批处理着色器更改,请在着色器转换工具中选择已转换的材质,然后点击 Revert Material。
更改批处理 Uniform 数量¶
Dynamic Shaders 和 Dynamic UBO Shaders 工具生成大小为 25 的批处理数组。
如果将 Batch Uniform Count 设置为 25 以外的值,请在着色器中手动更改所生成的批处理数组大小,使其与该值一致。
注意事项¶
着色器范围¶
仅对动态批处理网格所使用的材质应用着色器转换和手动着色器更改。
用于特殊渲染操作的材质(例如位块传送渲染通道 (Blit Render Pass) 所用的材质)不适合动态批处理。例如,不要对 DefaultBlit 应用动态批处理着色器更改。
重新批处理的开销¶
动态批处理可减少绘制调用,并降低提交渲染命令和更改渲染状态的 CPU 开销。但动态批处理本身也会带来 CPU 处理开销。
对于频繁创建或销毁对象、因而必须经常重建批次的内容,动态批处理可能并不适用。请对目标场景进行剖析,以确定动态批处理是否能提升性能。