在 Vulkan 中实现 "Instanced rendering" 的正确方法是什么?
What's the correct way to implement "Instanced rendering" in Vulkan?
我目前正在尝试有效地渲染多个立方体,所以我想知道如何在 Vulkan 中使用这个 "Instanced Rendering"。
我目前只知道渲染大量(相同)对象的两种方法:
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 负载仍然困扰着我。
所以我听说了这个 "Instanced rendering",它应该以某种方式告诉我们用一个命令来绘制所有立方体,为它提供模型矩阵的集合(可能仍然是一个缓冲区)。
如何做到这一点,防止我的程序使用单个调用在单个命令缓冲区中注册数千个 '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[=28= 开头的实例 ID ]
[1] https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdDrawIndexed.html
我目前正在尝试有效地渲染多个立方体,所以我想知道如何在 Vulkan 中使用这个 "Instanced Rendering"。
我目前只知道渲染大量(相同)对象的两种方法:
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 负载仍然困扰着我。
所以我听说了这个 "Instanced rendering",它应该以某种方式告诉我们用一个命令来绘制所有立方体,为它提供模型矩阵的集合(可能仍然是一个缓冲区)。
如何做到这一点,防止我的程序使用单个调用在单个命令缓冲区中注册数千个 '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[=28= 开头的实例 ID ]
[1] https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdDrawIndexed.html