1
votes

I have a texture atlas that I'm generating from an array of uints. Sampling from it in my pixel shader, colors are coming out correctly. Here's the relevant 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));
}

This works great. With color working, I've extended the texture atlas to include depth information as well. There are only a few thousand depth values that I want, well under 24 bits worth (my depth buffer is 24 bits wide + an 8 bit stencil). The input depth values are uints, just like the colors, though of course in the depth case the values are going to be spread over four color channels and in the shader I want a single float between 0 and 1, so that will need to be computed from the sample. Here's the additional pixel shader code:

// 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;

The long constant here is 16777216/255, which should map the full uint range down to a unorm.

Now, when I'm generating the texture, if I constrain the depth values to the range of 0..2048, the output depth is correct. However, if I allow the upper limit of the range to increase (even if it's simply by taking the input values and performing a left shift by 16), then the output depths will be slightly off. Not by much, just +/- 0.002, but it's enough to make the output look terrible.

Can anybody spot my bug here? Or, more generally, is there a better way of packing and unpacking uints into textures?

I'm working in shader model 4 level 9_3 and C++ 11.

1

1 Answers

1
votes

Your code is prone to precision loss: you're adding a relatively large number up to (65536+256) and a small number depthSample.r < 1.

Also, make sure your (u,v) are in the center of the texel to avoid filtering or replace Sample with Load.

Since you're using SM4 you can use the functions asuint and asfloat to reinterpret cast.

You can also use float format textures instead of R8G8B8A8.