Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Packing float into vec4 - how does this code work?

Tags:

I am trying to study shadow mapping in WebGL. I see same piece of shader code copied in various libraries and examples that achieve this. However nowhere did I find the explanation of how it works.

The idea is to save a depth value (a single float) into the color buffer (vec4). There is a pack function that saves float to vec4 and unpack function that retrieves the float from vec4.

vec4 pack_depth(const in float depth)
{
    const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
    const vec4 bit_mask  = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
    vec4 res = fract(depth * bit_shift);
    res -= res.xxyz * bit_mask;
    return res;
}

float unpack_depth(const in vec4 rgba_depth)
{
    const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
    float depth = dot(rgba_depth, bit_shift);
    return depth;
}

I would have imagined that packing a float into vec4 should be a trivial problem, just copy it into one of the 4 slots of vec4 and leave others unused. That's why the bit shifting logic in above code is puzzling to me.

Can anyone shed some light?

like image 712
Jayesh Avatar asked Mar 27 '12 02:03

Jayesh


1 Answers

It's not storing a GLSL float in a GLSL vec4. What it's doing is storing a value in a vec4 which, when written to an RGBA8 framebuffer (32-bit value) can be read as a vec4 and then reconstituted into the same float that was given previously.

If you did what you suggest, just writing the floating-point value to the red channel of the framebuffer, you'd only get 8 bits of accuracy. With this method, you get all 32-bits working for you.

like image 83
Nicol Bolas Avatar answered Oct 05 '22 23:10

Nicol Bolas