在 Vulkan 中实施"Instanced rendering"的正确方法是什么?

What's the correct way to implement "Instanced rendering" in Vulkan?

本文关键字:方法 是什么 Instanced Vulkan rendering      更新时间:2023-10-16

我目前正在尝试高效地渲染多个多维数据集,所以我想知道如何在Vulkan中使用这种"实例化渲染"。

我目前只知道两种渲染大量(相同)对象的方法:

1) 多个描述符集;

2) 具有动态统一/动态偏移的单个描述符集;

在第一种情况下,浪费了大量内存,因为多维数据集每个只需要一个不同的模型矩阵,但仍然使用一个完整的DescriptorSet:此外,因为我在每帧注册一个新的命令缓冲区,所以每个多维数据集都要花费2个Cmd调用:

vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSet, 0, nullptr);
vkCmdDraw(commandBuffer, numberOfVertices, 1, 0, 0);

但是,对于许多多维数据集来说,这会导致相当大的CPU负载和内存浪费。

在第二种情况下,我只需要一个DescriptorSet,将模型矩阵注册为Dynamic Uniform,并用所有模型矩阵填充它;然而,我仍然需要(稍作修改)为每个立方体调用相同的2个"Cmd":

vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSet, 1, index);
vkCmdDraw(commandBuffer, numberOfVertices, 1, 0, 0);

和以前一样,对于许多多维数据集,尽管使用唯一的DescriptorSet节省了大量内存,但CPU负载仍然困扰着我

所以我听说了这种"实例化渲染",它应该用一个命令来绘制所有的立方体,为它提供一个模型矩阵的集合(可能仍然是一个缓冲区)。

如何做到这一点,防止我的程序使用单个调用在单个命令缓冲区中注册数千个"Cmd"?谢谢

您将其中一个顶点属性设置为具有VkVertexInputBindingDescription::inputRate == VK_VERTEX_INPUT_RATE_INSTANCE。然后将必要的数据偏移并旋转到属性中。

另一个选项是使用内置的顶点着色器变量,该变量指示正在处理的实例。您可以使用它来索引到SSBO或UBO中,以获得所需的数据。

在您的代码中:

vkCmdDrawIndexed(command_buffer, indices_size, instance_count, 0, 0, instance_first_index);

  • instance_count:要绘制的实例数
  • instance_first_index:第一个实例将具有此id

在顶点着色器中,可以使用变量gl_InstanceIndex,该变量包含以instance_first_index开头的实例id

[1]https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdDrawIndexed.html