Pack four bytes in a float

YellPika picture YellPika · Jan 27, 2011 · Viewed 9.9k times · Source

I'm writing a shader (HLSL), and I need to pack a color value into the R32 format. I've found various pieces of code for packing a float into the R8G8B8A8 format, but none of them seem to work in reverse. I'm targeting SM3.0, so (afaik) bit operations are not an option.

To sum it up, I need to be able to do this:

float4 color = ...; // Where color ranges from 0 -> 1
float packedValue = pack(color);

Anyone know how to do this?

UPDATE
I've gotten some headway... perhaps this will help to clarify the question.
My temporary solution is as such:

const int PRECISION = 64;

float4 unpack(float value)
{   
    float4 color;

    color.a = value % PRECISION;
    value = floor(value / PRECISION);

    color.b = value % PRECISION;
    value = floor(value / PRECISION);

    color.g = value % PRECISION;
    value = floor(value / PRECISION);

    color.r = value;

    return color / (PRECISION - 1);
}

float pack(float4 color)
{   
    int4 iVal = floor(color * (PRECISION - 1));

    float output = 0;

    output += iVal.r * PRECISION * PRECISION * PRECISION;
    output += iVal.g * PRECISION * PRECISION;
    output += iVal.b * PRECISION;
    output += iVal.a;

    return output;
}

I'm basically... pretending I'm using integer types :s
Through guess and check, 64 was the highest number I could use while still maintaining a [0...1] range. Unfortunately, that also means I'm losing some precision - 6 bits instead of 8.

Answer

Olhovsky picture Olhovsky · Jan 29, 2011

Have a look at: http://diaryofagraphicsprogrammer.blogspot.com/2009/10/bitmasks-packing-data-into-fp-render.html

The short answer is that it's not possible to do a lossless packing of 4 floats into 1 float.

Even if you do find a way to pack 4 floats, storing their exponent and significand, the packing and unpacking process may be prohibitively expensive.