Packing multiple floats into a single float value

I’m trying to pack multiple float values(for normals, colors, etc) into a single float for use with a deferred shader. From what I read, you can use Cg functions in GLSL as long as there isn’t a #version line in the shader. I’m trying to use floatToRawIntBits & intBitsToFloat, because they seem to be exactly what I need. The shader compiles without errors or warnings.

The values I’m getting back aren’t correct. The majority seems to be 0. Let me know if you can spot what I’m doing wrong, or have a better way to do this.

Here is my code.


int ConvertToInt(float f)
{ 
     return int(255.0*f);
}

float PackVec4(vec4 v)
{
     int intVal = (ConvertToInt(v.w) << 24) | (ConvertToInt(v.y) << 16) | (ConvertToInt(v.z) << 8) | ConvertToInt(v.x);
     return intBitsToFloat(intVal);
}

vec4 UnpackVec4(float val)
{
     vec4 result;
     result.x = float((floatToRawIntBits(val) >> 0) & 0xFF) / 255.0;
     result.y = float((floatToRawIntBits(val) >> 8) & 0xFF) / 255.0;
     result.z = float((floatToRawIntBits(val) >> 16) & 0xFF) / 255.0;
     result.w = float((floatToRawIntBits(val) >> 24) & 0xFF) / 255.0;
     return result; 
}

From what I read, you can use Cg functions in GLSL as long as there isn’t a #version line in the shader.

And you’re using an NVIDIA implementation. I would strongly advise against this.

Try:
http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/

inline float4 EncodeFloatRGBA( float v ) {
  float4 enc = float4(1.0, 255.0, 65025.0, 160581375.0) * v;
  enc = frac(enc);
  enc -= enc.yzww * float4(1.0/255.0,1.0/255.0,1.0/255.0,0.0);
  return enc;
}
inline float DecodeFloatRGBA( float4 rgba ) {
  return dot( rgba, float4(1.0, 1/255.0, 1/65025.0, 1/160581375.0) );
}

or
http://diaryofagraphicsprogrammer.blogspot.com/2009/10/bitmasks-packing-data-into-fp-render.html

or
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=265070

Beware, there seem to be a typo in the original post, 160581375.0 should be replaced by 16581375.0

would it be quicker and would you lose any precision if you precalculated the divisions as constants like


const float x = 1.0/255.0;
const float y = 1.0/65025.0;
const float z = 1.0/16581375.0;


vec4 EncodeFloatRGBA( float v ) {
  vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v;
  enc = fract(enc);
  enc -= enc.yzww * vec4(x,x,x,0.0);
  return enc;
}
float DecodeFloatRGBA( vec4 rgba ) {
  return dot( rgba, vec4(1.0, x, y, z) );
}