PDA

View Full Version : Encoding multiple floats into one



nickels
08-09-2010, 07:09 AM
I am displaying quake3 levels using lightmaps. I am using deferred shading, so I end up needing to render the rgb componets of the lightmap into the g-buffer. I am using a high precision G buffer (16 or 32 bit), and since the lightmap is 8 bytes per component, it is a waste to use 3 slots of the g-buffer for the lightmap. At most I should need 24 bytes, which is 2.5 of the 16 bit or .75 or the 32 bit.

So the question:
What is a good method to encode several floats into 1? It's sort of the space filling curve question...

Its pretty clear how to do this for integers by using shifts, etc.. but I need it to work in shaders....

Any thoughts or references? Thanks!

nickels
08-09-2010, 07:43 AM
#include <iostream>
#include <cmath>

int main(int argc, char *argv[]) {


for (int i = 0; i < 255; ++i) {

for (int j = 0; j < 255; ++j) {

for (int k = 0; k < 255; ++k) {

float x = i/255.0f;
float y = j/255.0f;
float z = k/255.0f;

float enc = x + 255.0f*y + 65025.0*z;

// std::cout << "Encoding " << x << ", " << y << ", " << z << std::endl;

// std::cout << " result:" << enc << std::endl;

float ipart;

float xd = 255.0f*modff(enc, &amp;ipart);

float yd = 255.0f*modff(enc/255.0f, &amp;ipart);

float zd = 255.0f*modff(enc/65025.0f, &amp;ipart);

// printf("Decode:%10.6f, %10.6f, %10.6f\n", xd, yd, zd);
// std::cout << "Decode:" << xd << ", " << yd << std::endl;

float xerr = std::abs(xd-i);
float yerr = std::abs(yd-j);
float zerr = std::abs(zd-k);
float err = std::max(xerr, std::max(yerr, zerr));

printf("\terr:%10.5f\n", err);


}
}
}

return 0;
}



Maybe something like this? It seems to preserve the precision reasonably well. Will have to see if there is a modf in GLSL...
Found the needed link at:
encode rgba to float (http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/)
Basically the reverse procedure...
Why 65025???

Thus seems to give a maximum error of about 0.9 (scale of 0-255), which is probably fine... On the cpu, anyway...

Just found this as well, oops:
gl solution (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&amp;Number=268030)

kRogue
08-09-2010, 11:03 AM
Several bits:

1) If you are using GL3 hardware you can have multiple render targets, each target with a different format. For simplicity you can make another render target and store the lightmap data as GL_RGB8 (8-bit fixed point clamped), no conversion needed, though AFAIK, the hardware might implement GL_RGB8 as GL_RGBA8, so you "waste" one bytes per pixel.

2) If you are already using "too many render targets" then consider GL_EXT_texture_integer (http://www.opengl.org/registry/specs/EXT/texture_integer.txt). GeForce 8/9/2xx/3xx can render up to 8 textures at the same time.

Even under Mac OS-X (with a GeForce 8/9/2xx/3xx) both of these are possible [as Mac OS-X exports both GL_EXT_texture_integer and GL_ARB_framebuffer_object]

On the other hand if you are using GeForce6/7 neither of these is possible and they have a render target limit of 4 buffers, significant performance clip at 3 (I think) and all buffer targets must be the same format.

nickels
08-09-2010, 03:03 PM
Several bits:

1) If you are using GL3 hardware you can have multiple render targets, each target with a different format.


Thanks, I wasn't aware of that!



2) If you are already using "too many render targets" then consider GL_EXT_texture_integer (http://www.opengl.org/registry/specs/EXT/texture_integer.txt). GeForce 8/9/2xx/3xx can render up to 8 textures at the same time.

I will keep this in mind. My card (gtx 260) is pretty advanced, but I sort of want to 'play in bounds' as I learn this stuff.
I'm not near the limit yet, but I can see how you could get there pretty quick. Especially using more bytes than the precision of your data.
Thanks!

Alfonse Reinheart
08-12-2010, 04:51 PM
If you are using GL3 hardware you can have multiple render targets, each target with a different format.

Actually, this is not restricted to GL 3.x hardware. Any card that supports ARB_framebuffer_objects (as opposed to EXT_framebuffer_objects) can handle targets with different formats. According to the OpenGL extension viewer database, this includes most GL 2.x hardware (even down to the Radeon 9550).


GeForce 8/9/2xx/3xx can render up to 8 textures at the same time.

So can any DX10-class hardware.

nickels
08-13-2010, 07:43 AM
So can any DX10-class hardware.

That's really good to know. With that I am ok to assume up to 8 textures, which should be way more than I ever need (oops having a 64k moment there... :) )! Thanks. Of course, I will probably still do the compression just to not use any uneeded bits and to reduce bandwidth.... But as things progress I can definitely see needing more buffers.