它是否能够在包含一个管道的一个渲染过程中调用 vkCmdDrawIndexed 的多个绘制调用?

Is it able to call multiple drawcalls of vkCmdDrawIndexed in one render pass containing one pipeline?

我有两个网格,包含相同的 material 模板但参数不同。我想一个一个地画出这两个网格。比如伪代码likes

BeginRenderPass
BindPipeline

for(auto& mesh : meshes)
{
    BindVertexBuffers(mesh.vertexBuffer)
    AddUniformBufferDescriptorSet(mesh.material)
    UpdateDescriptorSets
    BindIndexBuffer(mesh.indexBuffer)
    DrawIndexed(mesh.indexCount, 1, 0, 0, 0)
}

vkCmdEndRenderPass

我将所有网格的顶点缓冲区绑定到相同的绑定索引,并对所有统一对象使用相同的描述符集。存在一些验证错误:

验证层:验证错误:[UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkDescriptorSet] 对象 0:句柄 = 0x40b43c0000000049,类型 = VK_OBJECT_TYPE_DESCRIPTOR_SET;对象 1:句柄 = 0x1c40e53df48,类型 = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0xe8616bf2 |您正在将 vkCmdBindVertexBuffers() 添加到 VkCommandBuffer 0x1c40e53df48[],这是无效的,因为绑定的 VkDescriptorSet 0x40b43c0000000049[] 已被销毁或更新。

如何实现上面的伪代码?

这是我的发现(错误)。 ~~首先,结论是我不能像上面的伪代码那样实现多个绘制调用。~~ 因为,根据 vkUpdateDescriptorSets ,它会使用于绑定描述符集的命令缓冲区无效,这将禁用记录下一次调用.因此,出现验证错误。

我可以使用单独的 material 参数绘制多个网格。

有两种方法:

  • 在shader中使用push_constant配置material参数,在draw call前通过vkCmdPushConstants设置相应的参数值。
  • 在着色器中使用统一缓冲区数组,其中每个元素都是一组 material 参数。添加一个名为“material id”的附加输入属性来索引相应的统一缓冲区。然后在一次调用 vkUpdateDescriptorSets 中更新统一缓冲区数组。当前命令缓冲区仍然可以记录下一个绘图调用命令。

第一种方式受到Sascha_Willems的启发,第二种方式是我成功实现的

补充(更正)

我还尝试在一次渲染过程中的两次绘制调用中的每一次之前更新并绑定相应的描述符集。最后,它起作用了。请注意,需要创建两个具有相同布局绑定的独立描述符集,但需要将图形管道声明为仅包含一个描述符集。