I've read several links discussing storing 2 or 3 floats in one float. Here's an example:
Storing two float values in a single float variable
and another:
http://uncommoncode.wordpress.com/2012/11/07/float-packing-in-shaders-encoding-multiple-components-in-one-float/
and yet another:
decode rgb value to single float without bit-shift in glsl
I've seen others but all of them use the same principle. If you want to encode x and y, they multiply y by some factor and then add x to it. Well this makes since on paper, but I don't understand how in the world it can work when stored to a floating value. Floating values only have 7 significant digits. If you add a big number and a small number, the small number is just truncated and lost. The precision only shows the value of the big number.
Since everyone seems to prescribe the same method, I tried it myself and it did exactly what I thought it would do. When I decoded the numbers, the number that wasn't multiplied turned out as 0.0. It was completely lost in the encoded float.
Here's an example of some MaxScript I tried to test it:
cp = 256.0 * 256.0
scaleFac = 16777215
for i = 1 to 20 do (
for j = 1 to 20 do (
x = (i as float / 20.01f) as float;
y = (j as float / 20.01f) as float;
xScaled = x * scaleFac;
yScaled = y * scaleFac;
f = (xScaled + yScaled * cp) as float
print ("x[" + xScaled as string + "] y[" + yScaled as string + "]" + " e[" + f as string + "]")
dy = floor(f / cp)
dx = (f - dy * cp)
print ("x[" + dx as string + "] y[" + dy as string + "]" + " e[" + f as string + "]")
)
)
dx is 0.0 everytime. Can anyone shed some light on this? NOTE: It doesn't matter whether I make cp = 128, 256, 512 or whatever. It still gives me the same types of results.
This method works for storing two integers. You're effectively converting your floating point numbers to large integers by multiplying by scaleFac, which is good, but it would be better to make it explicit with int(). Then you need to make sure of two things: cp is greater than the largest number you're working with (scaleFac), and the square of cp is small enough to fit into a floating point number without truncation (about 7 digits for a single precision float).
Here is a working code in C to pack two floats into one float and unpack them.
You should change scaleFactor and cp parameters as according to your possible value ranges (yourBiggestNumber * scaleFactor < cp). It is a precision battle. Try printing a few results to find good values for your case. The example below allows floats in [0 to 1) range.
#include <math.h>
/* yourBiggestNumber * scaleFactor < cp */
double scaleFactor = 65530.0;
double cp = 256.0 * 256.0;
/* packs given two floats into one float */
float pack_float(float x, float y) {
int x1 = (int) (x * scaleFactor);
int y1 = (int) (y * scaleFactor);
float f = (y1 * cp) + x1;
return f;
}
/* unpacks given float to two floats */
int unpack_float(float f, float* x, float* y){
double dy = floor(f / cp);
double dx = f - (dy * cp);
*y = (float) (dy / scaleFactor);
*x = (float) (dx / scaleFactor);
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With