Jump to content
  • Advertisement
Sign in to follow this  
HippyNerd

Packing a float into a texture

This topic is 4891 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I know there are probably a couple of ways to do this. But is there a stardard way people use to pack a floating point into a texture. I would like to extract it as a float in a fragment shader. If its a 32 bit int I can cleanly take 8 bits and store them in the RGBA channel, then in my fragment shader do something like vec4 texVal = glTexture1d(tex,value.u); float number = dot(texVal,vec4(1,256,2^16,2^24) (except I'll also have to account for normalisation of the texture values to [-1,1]..gah) Just wondering if there was a way of doing this with a float, or even if I can use some other channel (such as a depth texture). To store the values. (I know above if I can figure out how to pack an int, I can convert my float to an int in the main application and convert it back in the frag shader...however all these conversions will start slowing things down) Thanks,

Share this post


Link to post
Share on other sites
Advertisement
Well, I know that in D3D you can just make a floating-point texture and then render to that. Can you not do that in OGL?

Share this post


Link to post
Share on other sites
It looks like extensiosn such as ATI_TEXTURE_FLOAT allow 32 bit values to be stored in textures, without being clamped.

Not sure how to access these from the other end via GLSL though. Working on that now...

Share this post


Link to post
Share on other sites
This is the way I do it in my engine. I don't know if there is a better way, but it works very well.

I pack a floating point number into 24 bits (3 channels) of a ARGB texture because I need to keep the alpha for depth testing. If you'd wish to use all 32bits you'd use a similar method, using the extra 8 bits for higher accuracy in the integer or fractional parts, or of course you could just use a 32bit floating point texture. But we are talking about packing here. :)

Here is the packing code:


float3 PackDepth24(float depth)
{
//
// Calculate the integer and fractional parts of the depth
//
float depthInteger = floor(depth);

float depthFraction = frac(depth);

//
// Calculate the upper and lower 8 bits
//
float depthUpper = floor(depthInteger / 256.0f);

float depthLower = depthInteger - (depthUpper * 256.0f);

//
// Pack the values in a float3 which will be converted to 8bit RGB later
//
return float3(depthUpper / 256.0f, depthLower / 256.0f, depthFraction);
}




The above provides 16 bits for the integer part and 8 bits for the fractional part. This obviously allows for a floating point number in the range of 0-65535 with 8 bits of accuracy for the fraction.

Unpacking is performed like so:


float UnpackDepth24(float3 depth)
{
//
// Unpacking multiplier
//
const float3 unpack = {65536.0f, 256.0f, 1.0f};

//
// Unpack the depth
//
return dot(unpack, depth);
}




In my case I didnt need such a large range in the integer part, I only needed from 0-1000. By limiting your range, you can give yourself greater accuracy in the fractional part.

To do this, simply shift upwards like you would for an integer.

The packing code now becomes:


float3 PackDepth24(float depth)
{
//
// Shift the depth up 6 bits (eg. multiply by 64) so that we get 6 more bits of the fraction
//
float shiftedDepth = depth * 64.0f;

//
// Calculate the integer and fractional parts of the depth
//
float depthInteger = floor(shiftedDepth);

float depthFraction = frac(shiftedDepth);

//
// Calculate the upper and lower 8 bits
//
float depthUpper = floor(depthInteger / 256.0f);

float depthLower = depthInteger - (depthUpper * 256.0f);

//
// Pack the values in a float3 which will be converted to 8bit RGB later
//
return float3(depthUpper / 256.0f, depthLower / 256.0f, depthFraction);
}




And the unpacking becomes:


float UnpackDepth24(float3 depth)
{
//
// Unpacking multiplying
//
const float3 unpack = {65536.0f, 256.0f, 1.0f};

//
// Unpack the sample
//
float unpackedShadowSample = dot(unpack, depth);

//
// Unshift the sample by 6 bits and return
//
return unpackedShadowSample / 64.0f;
}




So now you have a floating point number with an integer part that ranges from 0-1024 and 14 bits of accuracy in the fractional part.

There may be another way that preserves the entire sign, mantissa and exponent, but this is the method that best suited me.

Hope that helps.

Share this post


Link to post
Share on other sites
Thanks heaps Buttza, i'm implementing a method simmilar to your idea now. I hadn't really thought about separating out the fractional part like you have. This is cool.

Share this post


Link to post
Share on other sites
superpig, it is. :P The beauty of it is it uses the most bits where they count.

I would still like to see a version which fully preserves a 32, 24 or 16bit floating point number. If its even possible.

I was thinking you may be able to use 'frexp' to get the mantissa and the exponent, then like above, allowing 16bits for the mantissa, 8 bits for the exponent and i guess another 8 bits to store the sign. Though it still isn't a true 32bit float because your wasting 7bits.

Share this post


Link to post
Share on other sites
What's wrong with just using an fp texture? I haven't had any problems accessing those from GLSL.

If you need to render to an fp texture, you might want to try the RenderTexture library, which you can get from gpgpu.org--it makes the whole process pretty easy by encapsulating all the driver-specific stuff like the fp formats.

(Sorry in advance if I misunderstood the question. ;)

Edit: I guess if you're using hardware that doesn't support fp textures you can't do that, but I'm pretty sure any card you can use GLSL with supports them.

Share this post


Link to post
Share on other sites
You can render to floating point textures in OpenGL. Atleast on NVIDIA hardware, since ATI doesn't have any support for FBO (pbuffers does not counts).

GL_ARB_texture_float
GL_EXT_framebuffer_object
http://oss.sgi.com/projects/ogl-sample/registry/

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!