With my hardware limitation for CS5 I'm using R32_UINT in my shaders to store compacted colors and normasl as 555 bits each. My packing is using uint3 and the result is of poor quality. I'm planning to store the color as 565 bits and normals as 77 bits + 2 bits, one for a sign (of normal z) and one for a mask, but in a R16_UNORM each that gives me better quality and pack the two in my R32_UINT.
below the packing/unpacking funcs for float3 color to 565 bits as R16_unorm and back that works with correct quality in my other shaders. I also added the expected coding for the Normals to Nxy 77 bits
float C3_R16(float3 Color)
{
uint3 uColor = uint3(min(Color,float3(1.0, 1.0, 1.0))*float3(31.0, 63.0, 31.0));
return float(uColor.r | (uColor.g<<5) | (uColor.b<<11))/65535.0;
}
float3 R16_C3(float Pack)
{
uint iPack = uint(Pack);
return float3(iPack&0x1F, (iPack>>5)&0x3F, (iPack>>11)&0x1F)/float3(31,63,31);
}
float N2_R16(float3 Normal)//unchecked behavior
{
uint2 uNormal = uint2(min(Normal.rg,float2(1.0, 1.0))*float2(127.0, 127.0));
return float(uNormal.r | (uNormal.g<<7))/65535.0;
}
float3 R16_N3(float Pack)//unchecked
{
uint iPack = uint(Pack*65535);
float3 N;
N.xy = float2(iPack&0x7F, (iPack>>7)&0x7F)/float2(127,127)*2-1;//maybe optimze with /float2(63.5,63.5)-1;
N.z = sqrt(1-dot(N.xy,N.xy));//in view space I should not need sign
return N;
}
The Normal 77 (N2_R16) enoding is to show how I will proceed for the Nxy encoding/decoding. The two final bits are added with a test and bitshift like uint(N.z<0)<<15.
Now to convert two R16 into a R32_UINT I'm planning to use asuint function this way:
uint ColorOut = (asuint(C3_R16(mycolor.rgb))&0x00EFFFFF)>>7;
//uint NormalOut = (asuint(C2_R16(mynormal.rg))&0x00EFFFFF)>>7;//this may be optimized to avoid latter <<16
uint MyFinalR32_UINT = ColorOut;//| NormalOut<<16; currently only one R16 is added for the color
In this code I'm storing only one R16 at the moment to check how it works.
For unpaking I'm doing this:
uint Data = txDiffuseInt.Load(uint3(Input.Tex.x*960, Input.Tex.y*540,0));
float3 C = R16_C3(float(Data&0x0000FFFF));
According to IEEE rules the *0x00EFFFFF mask considers that the 9 msb are the sign and 8 bit exponent and the lower 23 bit the mantissa. As the value reulting from C3_R16 must be in the range [0..1] I should not need the sign and exponent. The >>7 is to pick the 16 MSB bit of the mantissa (again if I'm correct these are the most significant bits). This is were things go wrong I think. My colors are mostly blue with some green on unpacking. Some objects should be full red.
Is my description of float32 well-used?
C3_R16
in your attempted 77+2 conversion. Wouldn't you write a newN3_R16
function to do that? \$\endgroup\$