在 Vulkan 中实现“实例渲染”的正确方法是什么?

Sho*_*ing 8 c++ instance vulkan

我目前正在尝试有效地渲染多个立方体,所以我想知道如何在 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);
Run Code Online (Sandbox Code Playgroud)

但是,对于很多多维数据集,这会导致 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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

rat*_*eak 8

您将顶点属性之一设置为具有VkVertexInputBindingDescription::inputRate == VK_VERTEX_INPUT_RATE_INSTANCE。然后,将偏移和旋转所需的数据放入属性中。

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

  • 在glsl中我认为是gl_InstanceID (4认同)

Ada*_*amM 6

在你的代码中:

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