在DirectX中将uint打包并解压缩到float4中

时间:2013-07-05 22:07:04

标签: c++ directx direct3d hlsl

我有一个纹理图集,我是从一组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位模板)。输入深度值是uints,就像颜色一样,当然在深度情况下,值将分布在四个颜色通道上,并且在着色器中我想要一个介于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,但它足以使输出看起来很糟糕。

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

我正在着色模型4级9_3和C ++ 11中工作。

1 个答案:

答案 0 :(得分:1)

您的代码容易出现精确丢失:您需要添加一个相对较大的数字(65536+256)和一小部分depthSample.r < 1

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

由于您使用的是SM4,因此可以使用asuintasfloat功能重新解释强制转换。

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

相关问题