# Thread: GLSL: packing a normal in a single float

1. ## Re: GLSL: packing a normal in a single float

Thank you this works great for 3 components!

Can it work for 4?

Seemed to zero out the last component for me not sure if this is due to something with how floats work? Here is my code:

Code :
```	float TestPackUnsignedNormalizedFloat4ToFloat(float* aValues)
{
assert(	aValues[0] <= 1.0f &amp;&amp; aValues[1] <= 1.0f &amp;&amp; aValues[2] <= 1.0f &amp;&amp; aValues[3] <= 1.0f &amp;&amp;
aValues[0] >= 0.0f &amp;&amp; aValues[1] >= 0.0f &amp;&amp; aValues[2] >= 0.0f &amp;&amp; aValues[3] >= 0.0f);

unsigned long packedColor = (UNFloatConvertChar(aValues[0]) << 24) | (UNFloatConvertChar(aValues[1]) << 16) | (UNFloatConvertChar(aValues[2]) << 8) | UNFloatConvertChar(aValues[3]);

float packedFloat = (float) ( ((double)packedColor) / ((double) (0xFFFFFFFF)) );

return packedFloat;
}

//Helper method to emulate GLSL
float frac(float value)
{
return (float)fmod(value, 1.0f);
}

//UnPack 3 values from 1 float
CVec4 UnPackUnsignedFloat(float src)
{
return CVec4(		frac(src),
frac(src * 256.0f),
frac(src * 65536.0f),
frac(src * 16777216.0f) );
}```

2. ## Re: GLSL: packing a normal in a single float

What would you multiply by in the unpacking code if you just had 2 components?

NM Figured it out I think:
Code :
```	float TestPackUnsignedNormalizedFloat2ToFloat(float* aValues)
{
assert(	aValues[0] <= 1.0f &amp;&amp; aValues[1] <= 1.0f &amp;&amp;
aValues[0] >= 0.0f &amp;&amp; aValues[1] >= 0.0f );

unsigned long packedColor = (UNFloatConvertShort(aValues[0]) << 16) | UNFloatConvertShort(aValues[1]);

float packedFloat = (float) ( ((double)packedColor) / ((double) (0xFFFFFFFF)) );

return packedFloat;
}

//Helper method to emulate GLSL
float frac(float value)
{
return (float)fmod(value, 1.0f);
}

//UnPack 3 values from 1 float
CVec2 UnPackUnsignedFloat2(float src)
{
return CVec2( frac(src),
frac(src * 65536.0f) );
}```

3. ## Re: GLSL: packing a normal in a single float

Well since this code snipit helped me out so much. I thought I would post another related bit.

http://www.caffeinatedgames.com/prof...uch-memory-and

I decided I wanted to pack normals into my GBUFFER as well. It is a 16F buffer and I want to pack the x and y into a single 16 bit float but this time on the GPU so no |. I asked out on twitter and @paveltumik was kind of enough to reply with what should have been obvious looking at all these posts but I think at that point my eyes had glazed over . Basically I just store one number in the fractional part and one number in the non fractional part. I get two bits of precision which seem to be just fine for my normals.

It assumes:

1) You are compressing numbers between -1 and 1.
2) You only care about two digits of precision which is good since I am packing into a 16bit float format
3) I deal with the 1.0 case by using a range 0.0 - 0.8f.

Code :
```//Thanks @paveltumik for the original code in comments

//pack:	f1=(f1+1)*0.5; f2=(f2+1)*0.5; res=floor(f1*1000)+f2;
inline float PackFloat16bit2(float2 src)
{
return floorf((src.x+1)*0.5f * 100.0f)+((src.y+1)*0.4f);
}

//unpack:	f2=frac(res);	f1=(res-f2)/1000;	f1=(f1-0.5)*2;f2=(f2-0.5)*2;
inline float2 UnPackFloat16bit2(float src)
{
float2 o;
float fFrac = frac(src);
o.y = (fFrac-0.4f)*2.5f;
o.x = ((src-fFrac)/100.0f-0.5f)*2;
return o;
}```

Also some of the numbers I didn't combined just to make it more readable. Hope this helps someone else.

Cheers,
Greg

4. ## Re: GLSL: packing a normal in a single float

Just thought I would like to point out that if you are only targeting Geforce 5+ cards, you can probably use the Nvidia OpenGL Cg extensions:

pack_2half()
Converts the components of a into a pair of 16-bit floating point values. The two converted components are then packed into a single 32-bit result. This operation can be reversed using the unpack_2half() function.

(to use this, you will probably have to have something at the top of your shader file saying "enable Cg extensions")

If you are targeting Shader Model 4 and above cards, you can probably just use bit masks directly.

5. ## Re: GLSL: packing a normal in a single float

Why are you "packing" floats in a 16-bit float format? Why not just use an 8-bit format and skip the packing? Are you actually getting any more accuracy this way?

6. ## Re: GLSL: packing a normal in a single float

The reason for packing is usually not for accuracy, it is typically that you have more data variables than output/input channels.

Eg. Your render target might be RGBA16F (4 components) but you want to store 6 pieces of output data.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•