我有一个由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。

最佳答案

您的代码容易出现精度损失:您要在(65536+256)之前添加一个相对较大的数字,而在depthSample.r < 1之前添加一个较小的数字。

另外,请确保您的(u,v)位于纹理元素的中心,以避免过滤或将Sample替换为 Load

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

您也可以使用浮点格式纹理代替R8G8B8A8。

关于c++ - 在DirectX中将uint打包和解压缩到float4中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17497437/

10-13 00:08