Float Packing in Shaders; Encoding Multiple Components in One Float
Lets say you are tasked with stuffing a 3 component vector, such as a color, into a single floating point value. Under sane design, this additional complexity would never be justified over simply having a 3 component vector. Unfortunately, whenever the cost to add additional floating point components is high (or impossible), such as with GPU programming, then we can do some tricks :)
A standard 32-bit float can specify up to 7 digits precisely. Maybe we can simply partition some of those digits to be parts of your vector components? For instance, your 7 digit value could encode RGB values in base 10 as RRGGGBB. These sort of hacks can efficiently encode multiple component values with integers using masks and shifts. In fact, this is exactly what Qt does with its internal QRgb
type, which was chosen for benefits with performance and consistent memory layout as apposed to packed structs.
If you are staying in floating point land (like with GLSL), bit hacks are out of the question. Instead, one can use modulo operations and floor divides to provide masking and shifting -like operations. This is commonly done for indexing 2D space with the standard zigzag curve:
The inverse can be calculated as follows:
Extending this to 3D, and going from normalized values to decimal values, results in the following GLSL code:
Check it out in action here.
One concern may be that divides and mods are expensive, but so are memory accesses! In the very least, this technique allows multiple components to be stuffed into a single float.
As a possible optimization, you may be able to make a lookup table to save some operations, which may be really fast if you can keep it small and in a cached texture.