10

我正在在模型的多个网格上渲染不同的纹理,但我对这些过程没有太多线索。有人建议为每个网格创建自己的描述符集并调用 vkCmdBindDescriptorSets() 和 vkCmdDrawIndexed() 进行渲染,如下所示:

    // Pipeline with descriptor set layout that matches the shared descriptor sets
vkCmdBindPipeline(...pipelines.mesh...);
...
// Mesh A
vkCmdBindDescriptorSets(...&meshA.descriptorSet... );
vkCmdDrawIndexed(...);
// Mesh B
vkCmdBindDescriptorSets(...&meshB.descriptorSet... );
vkCmdDrawIndexed(...);

但是,上述方法与 chopper 示例和 vulkan 的示例完全不同,这让我不知道从哪里开始更改。我非常感谢任何帮助引导我走向正确方向的帮助。

干杯

4

2 回答 2

11

您有一个概念对象,它由具有不同纹理需求的多个网格组成。处理这种情况的一般方法是:

  1. 更改对象各部分之间的描述符集。很痛苦,但它适用于所有支持 Vulkan 的硬件。

  2. 使用阵列纹理。每个单独的网格从阵列纹理中的特定层获取其数据。当然,这会限制您让每个子网格使用相同大小的纹理。但它适用于所有支持 Vulkan 的硬件(最多 128 个数组元素,最少)。特定网格的数组层可以作为推送常量提供,或者如果可用的话,可以作为基本实例提供。

    请注意,如果您设法通过基本实例来实现,那么您可以使用多重绘制间接命令渲染整个对象。尽管尚不清楚短的多重绘制间接是否比仅将短的绘图命令序列烘焙到命令缓冲区中更快。

  3. 正如Sascha Willems建议的那样,使用采样器阵列。据推测,子网格的数组索引作为推送常量或多重绘制的绘制索引提供。问题是,无论该数组索引是如何提供的,它都必须是一个动态统一的表达式。并且 Vulkan 实现不需要允许您使用动态统一表达式索引采样器数组。基本要求只是一个常量表达式。

    这将您限制在支持该shaderSampledImageArrayDynamicIndexing功能的硬件上。所以你必须提出这个要求,如果它不可用,那么你必须使用#1 或#2 来解决这个问题。或者只是不要在该硬件上运行。但是最后一个意味着您不能在任何移动硬件上运行,因为它们中的大多数还不支持此功能

    请注意,我并不是说您不应该使用这种方法。我只是想让你知道有成本。有很多硬件无法做到这一点。所以你需要为此做好计划。

于 2016-04-21T22:38:54.233 回答
4

我猜是我提出上述代码片段的人;)

这只是一种方法。您不必为每个网格或每个纹理创建一个描述符集。例如,如果您的网格使用 4 个不同的纹理,您可以一次将它们全部绑定到不同的绑定点并在着色器中选择它们。

如果你看一下 NVIDIA 的 Chopper 样本,他们会以几乎相同的方式进行操作,只是增加了一些抽象。

该示例还为使用的纹理设置描述符集:

VkDescriptorSet *textureDescriptors = m_renderer->getTextureDescriptorSets();

几行之后绑定它们:

VkDescriptorSet sets[3] = { sceneDescriptor, textureDescriptors[0], m_transform_descriptor_set };
vkCmdBindDescriptorSets(m_draw_command[inCommandIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, sets, 0, NULL);

然后使用绑定的描述符集渲染网格:

vkCmdDrawIndexedIndirect(m_draw_command[inCommandIndex], sceneIndirectBuffer, 0, inCount, sizeof(VkDrawIndexedIndirectCommand));
vkCmdDraw(m_draw_command[inCommandIndex], 1, 1, 0, 0);

如果您查看initDescriptorSets,您会发现它们还为立方体贴图、地形等创建了单独的描述符集。

LunarG 示例应该类似,但如果我没记错的话,它们从不使用多个纹理?

于 2016-04-21T17:20:40.137 回答