1

我有一个从一组 uint 生成的纹理图集。在我的像素着色器中对其进行采样,颜色正确显示。这是相关的HLSL:

Texture2D textureAtlas : register(t8);
SamplerState smoothSampler : register(s9)
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
}
struct PS_OUTPUT
{
    float4 Color : SV_TARGET0;
    float Depth : SV_DEPTH0;
}
PS_OUTPUT PixelShader
{
    // among other things, u and v are calculated here
    output.Color = textureAtlas.Sample(smoothSampler, float2(u,v));
}

这很好用。通过颜色处理,我扩展了纹理图集以包含深度信息。我想要的只有几千个深度值,远低于 24 位(我的深度缓冲区是 24 位宽 + 8 位模板)。输入深度值是 uint,就像颜色一样,当然在深度情况下,这些值将分布在四个颜色通道上,并且在着色器中我想要一个介于 0 和 1 之间的浮点数,因此需要从样本计算。这是附加的像素着色器代码:

// u and v are recalculated for the depth portion of the texture atlas
float4 depthSample = textureAtlas.Sample(smoothSampler, float2(u,v));
float depthValue = 
    (depthSample.b * 65536.0 +
     depthSample.g * 256.0 +
     depthSample.r)
    / 65793.003921568627450980392156863;
output.Depth = depthValue;

这里的长常量是 16777216/255,它应该将整个 uint 范围映射到一个 unorm。

现在,当我生成纹理时,如果我将深度值限制在 0..2048 的范围内,则输出深度是正确的。但是,如果我允许范围的上限增加(即使它只是通过获取输入值并执行左移 16),那么输出深度将略微偏离。不是很多,只是+/- 0.002,但足以让输出看起来很糟糕。

有人可以在这里发现我的错误吗?或者,更一般地说,有没有更好的方法将 uint 打包和解包到纹理中?

我正在使用着色器模型 4 级别 9_3 和 C++ 11。

4

1 回答 1

1

您的代码容易出现精度损失:您将相对较大的数字添加到 ( 65536+256) 和较小的数字depthSample.r < 1

此外,请确保您(u,v)位于纹素的中心,以避免过滤或替换SampleLoad.

由于您使用的是 SM4,因此您可以使用函数asuintasfloat重新解释演员表。

您还可以使用浮点格式纹理而不是 R8G8B8A8。

于 2013-07-06T00:46:59.523 回答