对 srgb 格式使用 VK_IMAGE_TILING_LINEAR?

Using VK_IMAGE_TILING_LINEAR for srgb formats?

所以我仍在尝试找出渲染纹理的色彩空间,以及如何创建没有色带的图像。在我的 gbuffer 中,我将 VK_FORMAT_R8G8B8A8_UNORM 和 VK_IMAGE_TILING 用于我的反照率纹理,并将 VK_FORMAT_A2B10G10R10_UNORM_PACK32 和 VK_IMAGE_TILING_OPTIMAL 用于我的法线和发射渲染纹理。对于我的亮度纹理(包含在场景中被视为 "bright" 的像素值)和辉光渲染纹理(用于稍后添加到最终场景的光晕效果的最终纹理),我使用 VK_FORMAT_R8G8B8A8_SRGB 和VK_IMAGE_TILING_OPTIMAL(虽然看着这个,我可能应该将我的明亮和最终纹理改为 R16G16B16A16 浮点格式)。我得到的绝对不是我想要的:

然而,将我的法线、发射、发光和亮度纹理的平铺更改为 VK_IMAGE_TILING_LINEAR,却得到了不错的结果,但以牺牲性能为代价:

不过它的好处(对于左上角的奇怪边框感到抱歉,在 MS 画图上被裁剪了...),图像没有色带,例如 when 相反为了将这些格式用于我的纹理,我使用 VK_FORMAT_R8G8B8A8_UNORM 和 VK_IMAGE_TILING_OPTIMAL:

您是否可以看到头盔左上角和头盔下方(黑管所在的位置)出现条纹。当然,我听说过从 post

中避免 VK_IMAGE_TILING_LINEAR

一般来说,我无法确定在使用 srgb 纹理时避免使用 VK_IMAGE_TILING_LINEAR 的最佳方法是什么?我仍然想保留 srgb 给我的漂亮清晰的图像,但我不确定如何解决这个问题。 link 可能确实有解决方案,但我不太确定是否有办法将它应用到我的 gbuffer。

我还想澄清一下 VK_IMAGE_TILING_OPTIMAL 适用于基于 Nvidia 的 GPU(好吧,在 GTX 870M 上测试过),但抱怨对 srgb 格式使用 VK_IMAGE_TILING_LINEAR,然而,intel基于 gpus 的 VK_IMAGE_TILING_LINEAR 可以很好地工作,当使用 VK_IMAGE_TILING_OPTIMAL.

时,有点像 post 上面的第一张图片

该引擎是定制的,请随时在此查看 link

如果你喜欢一些代码,我在 Engine/Renderer/Private/Renderer.cpp 文件中使用了一个名为 SetUpRenderTextures() 的函数,在第 1396 行下:

      VkImageCreateInfo cImageInfo = { };
  VkImageViewCreateInfo cViewInfo = { };

  // TODO(): Need to make this more adaptable, as intel chips have trouble with srgb optimal tiling.
  cImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  cImageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
  cImageInfo.imageType = VK_IMAGE_TYPE_2D;
  cImageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
  cImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  cImageInfo.mipLevels = 1;
  cImageInfo.extent.depth = 1;
  cImageInfo.arrayLayers = 1;
  cImageInfo.extent.width = m_pWindow->Width();
  cImageInfo.extent.height = m_pWindow->Height();
  cImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  cImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  cImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;

  cViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 
  cViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
  cViewInfo.image = nullptr; // No need to set the image, texture->Initialize() handles this for us.
  cViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
  cViewInfo.subresourceRange = { };
  cViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  cViewInfo.subresourceRange.baseArrayLayer = 0;
  cViewInfo.subresourceRange.baseMipLevel = 0;
  cViewInfo.subresourceRange.layerCount = 1;
  cViewInfo.subresourceRange.levelCount = 1;

  gbuffer_Albedo->Initialize(cImageInfo, cViewInfo);
  gbuffer_Emission->Initialize(cImageInfo, cViewInfo);

  cImageInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
  cViewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
  cImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
  GlowTarget->Initialize(cImageInfo, cViewInfo);
  // It's probably best that these be 64bit float formats as well...
  pbr_Bright->Initialize(cImageInfo, cViewInfo);
  pbr_Final->Initialize(cImageInfo, cViewInfo);

  cImageInfo.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
  cImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
  cViewInfo.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;

  gbuffer_Normal->Initialize(cImageInfo, cViewInfo);
  gbuffer_Position->Initialize(cImageInfo, cViewInfo);

所以是的,破败。如何避免对 srgb 纹理使用线性图像平铺?这是硬件特定的东西吗,是强制性的吗?另外,对于我在这个问题上的任何形式的无知,我深表歉意。

谢谢:3

必须支持此组合,因此您第一张图片中的损坏是应用程序错误或驱动程序错误。

所以 VK_FORMAT_R8G8B8A8_SRGB 在您的 Nvidia GPU 上使用 VK_IMAGE_TILING_OPTIMAL 而不是在您的 Intel GPU 上?但是 VK_FORMAT_R8G8B8A8_SRGB 可以在 Intel GPU 上与 VK_IMAGE_TILING_LINEAR 一起使用吗?

如果是这样,这听起来像是您缺少或不正确的图像布局过渡。与 Nvidia 相比,Intel 对正确处理这些问题更为敏感。验证层会抱怨什么吗?您需要确保图像在渲染时为 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,在从中采样时为 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL