像素值在 DirectX 11 HLSL 着色器中的行为如何?

How do pixel values behave in DirectX 11 HLSL shaders?

在像素着色器中采样纹素值时,采样器总是 returns float4。但是,纹理本身可能包含基于 DXGI_FORMAT 的多种格式中的任何一种。任何 _UNORM 格式都将确保 float4 中的所有值都在 0 和 1 之间,这似乎相当简单。回到 DirectX9 时代,几乎假设,无论像素格式如何,所有值sampled 总是介于 0 和 1 之间。

DirectX 11 似乎不是这种情况。例如,使用 DXGI_FORMAT_R32_FLOAT 格式的纹理似乎能够存储任何有效的 32 位浮点数,这确实从一般角度来看是有意义的,因为您可能根本没有使用该纹理(或缓冲区)进行渲染。

那么,如果渲染管线没有使用 0 到 1 的范围,那么当您对诸如 R32_FLOAT 这样的任意范围具有任意范围时,渲染管线如何确定输出的像素值?它似乎不是 -FLT_MAX 到 +FLT_MAX,因为我可以使用 0.0-65.0 之间的值渲染这种类型的纹理,并且我确实在最终结果中看到了红色。但是调试像素着色器并查看源纹理时,只有真正接近 65.0 的值才真正显示为红色。但是,后台缓冲区上的最终渲染结果中有很多红色。

这是一个示例源纹理,如 VS 图形调试器中所示:

如果我只使用像素着色器的基本采样器输出将它渲染到屏幕上,我会得到:

后台缓冲区格式为 R10G10B10A10_UNORM。

那么它如何决定浮点纹理的“最大强度”是多少?同样,如果您使用其中一种 _SINT 格式,它是如何处理的?

  • 如果对纹理进行采样,returned 值不会限制在任何特定范围内。如果纹理格式可以包含 0..1 范围之外的值,Sample/Load 方法将 return 这些值保持不变
  • 当您的像素着色器 return 是一个值时,该 returned 值将被限制在您的渲染目标支持的任何范围内。如果您在 R32_FLOAT 上渲染,您的渲染值将不会被限制,并且 'valid range' 确实是 -FLT_MAX 到 +FLT_MAX。然后 VS 图形调试器仅根据实际存储在纹理中的最低值和最高值显示范围内的纹理,因此您可以在调试器中以有意义的方式查看纹理。另一方面,您的 Back-Buffer 格式使用 UNORM 格式,因此它只能包含 0..1 范围内的值,这意味着每个大于 1 的值都将被限制为 1,这就是为什么在你的屏幕是红色的。