Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 2 of 2 FirstFirst 12
Results 11 to 16 of 16

Thread: GLSL: packing a normal in a single float

  1. #11

    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) );
    	}
    Indie Game Developer
    http://www.caffeinatedgames.com

  2. #12

    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) );
    	}
    Indie Game Developer
    http://www.caffeinatedgames.com

  3. #13

    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.

    Here is the link to my original post in case I add any updates:
    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
    Indie Game Developer
    http://www.caffeinatedgames.com

  4. #14
    Senior Member OpenGL Pro sqrt[-1]'s Avatar
    Join Date
    Jun 2002
    Location
    Australia
    Posts
    1,000

    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. #15
    Junior Member Regular Contributor
    Join Date
    Mar 2009
    Location
    California
    Posts
    192

    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. #16
    Senior Member OpenGL Pro sqrt[-1]'s Avatar
    Join Date
    Jun 2002
    Location
    Australia
    Posts
    1,000

    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
  •