0

所以我一直在我的纹理采样器中使用非标准化坐标,因为我发现在将纹理用作精灵图集时更容易处理纹理的某些部分。今天我修补了我的工作站并重新编译了所有东西,验证层开始报告这个错误:

验证错误:[VUID-vkCmdDrawIndexed-None-02703] 对象 0:句柄 = 0x210000000021,类型 = VK_OBJECT_TYPE_DESCRIPTOR_SET;对象 1:句柄 = 0x1c000000001c,类型 = VK_OBJECT_TYPE_IMAGE_VIEW;对象 2:句柄 = 0x1f000000001f,类型 = VK_OBJECT_TYPE_SAMPLER;| 消息 ID = 0x30c87f64 | VkDescriptorSet 0x210000000021[] 在 vkCmdDrawIndexed() 时遇到以下验证错误:绑定 #0 索引 0 中的描述符中的 VkImageView 0x1c000000001c[] 被使用无效运算符的 VkSampler 0x1f000000001f[] 使用。Vulkan 规范规定:如果绑定到此命令使用的管道绑定点的 VkPipeline 对象访问使用非标准化坐标的 VkSampler 对象,则该采样器不得与任何带有 ImplicitLod 的 SPIR-V OpImageSample* 或 OpImageSparseSample* 指令一起使用, Dref 或 Proj 以他们的名义,https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-02703

我知道在使用非标准化纹理坐标(如无 mipmap 或各向异性)时存在各种限制。这是规范中的(我认为)相关部分: https ://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSamplerCreateInfo.html

unnormalizedCoordinates 控制是否使用非标准化或标准化纹理像素坐标来处理图像的纹理像素。当设置为 VK_TRUE 时,用于查找 texel 的图像坐标范围在从零到 x、y 和 z 的图像尺寸的范围内。当设置为 VK_FALSE 时,图像坐标的范围是零到一。

当 unnormalizedCoordinates 为 VK_TRUE 时,采样器在着色器中使用的图像具有以下要求:

The viewType must be either VK_IMAGE_VIEW_TYPE_1D or VK_IMAGE_VIEW_TYPE_2D.
The image view must have a single layer and a single mip level.

当 unnormalizedCoordinates 为 VK_TRUE 时,shader 中使用采样器的图像内置函数有以下要求:

The functions must not use projection.
The functions must not use offsets.

我满足所有这些要求,除非“投影”和“偏移”是指“在渲染纹理期间发生的事情”。

如果是这种情况,并且在渲染部分纹理时不能使用非规范化纹理坐标,那么:我不明白这个功能的用途。在哪里以及为什么要使用非归一化纹理坐标?此外,许多教程会像这里一样“误导”: https ://vulkan-tutorial.com/en/Texture_mapping/Image_view_and_sampler

unnormalizedCoordinates 字段指定要使用哪个坐标系来处理图像中的纹素。如果该字段为 VK_TRUE,那么您可以简单地使用 [0, texWidth) 和 [0, texHeight) 范围内的坐标。如果它是 VK_FALSE,则使用所有轴上的 [0, 1) 范围来寻址纹素。现实世界的应用程序几乎总是使用归一化坐标,因为这样就可以使用具有完全相同坐标的不同分辨率的纹理。

这(仅作为示例)听起来像是个人喜好,而不是“方法a有效,方法b只能在特殊情况下使用,很可能不是您想要的”。确实 --> 当我将样本更改为使用非标准化纹理坐标时,会报告相同的验证错误。那么有人可以解释这里发生了什么吗?

谢谢!

4

2 回答 2

1

这是对 Khrono 论坛上一篇文章的重复,这里有一个关于非规范化纹理坐标的未解决问题。

任何形式的调用:

 vec4 val = texture( unormSampler, pixelCoord );

其中 unormSampler 包含一个未标准化的采样器,导致 SPIR-V 操作码 87,它是指令 OpImageSampleImplicitLod。vulkan 规范(如您所述)明确排除了任何非规范化纹理读取的此指令。

然而:

SPIR-V 操作码 88 是非规范化王国的密钥。OpCode 88 指令是OpImageSampleExplicitLod。Vulkan 规范中的任何地方都没有列出(据我所知),这是使用非规范化采样器的非法操作。

映射到操作码 88 的秘密 GLSL 指令是textureLod。这是使用它的代码示例。

// Set this up just like usual, except use a unnormalized sampler
layout(binding = 23) uniform sampler2D unormSampler;

void main()
{
    vec4 val = textureLod( unormSampler, pixelCoord, 0); // 0 is the mipmap level to sample from
}

我没有尝试其他 mipmap 级别(我依稀记得 Vulkan Spec 说没有带有非标准化坐标的 mipmap。)。

我确实为示例尝试了 VK_FILTER_LINEAR 和 VK_FILTER_NEAREST,它们都按预期工作。(我的测试有使用 VK_FILTER_NEAREST 时出现的工件)

以下是 GLSL、Vulkan 和非规范化采样器无法使用的内容列表:

  1. 使用 sampler2Drect – 加载 SPIR-V 模块时产生错误
  1. 使用任何版本的纹理(blablabla);– 导致操作码 87,这对于 Vulkan 规范来说是不允许的

  2. 使用 samplerBuffer——规范再次对未标准化的采样器说不

于 2021-07-16T13:46:47.800 回答
1

在着色器中,使用纹理(sampler2D,uv)访问纹理

嗯,有你的问题。GLSL 是针对 OpenGL 而不是 Vulkan 编写的。因此,它不知道 Vulkan 允许 OpenGL 通常不允许的某些事情。在 OpenGL 中,texture函数总是使用归一化的纹理坐标。唯一不是这样的情况是您使用的是矩形纹理,这是与 2D 纹理不同的纹理类型。它们是没有 Vulkan 模拟的 OpenGL 功能,因为在 Vulkan 中,您可以将任何纹理视为“矩形纹理”(“矩形纹理”的唯一真正特征是您可以使用非归一化纹理坐标)。

我在GL_KHR_vulkan_glsl 扩展中没有看到允许texture函数使用非标准化纹理坐标的机制。所以你必须找到另一种方法来生成你的 SPIR-V,或者你需要直接编写 SPIR-V。

于 2021-01-19T15:24:51.040 回答