如何将一个float的小数部分保存成RGBA4个8位的byte
shadow map的时候经常看到这两个函数
vec4 packFloatToVec4i(const float value) { const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0); const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0); vec4 res = fract(value * bitSh); res -= res.xxyz * bitMsk; return res; } float unpackFloatFromVec4i(const vec4 value) { const vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); return(dot(value, bitSh)); }
用于将0-1之间的深度值保存到RGBA8纹理里面。
参考http://marcodiiga.github.io/encoding-normalized-floats-to-rgba8-vectors解释下原理:
------------------------------------------------------------------------------------------------------------------------------------------------------
首先上述方法只能编码/解码小数部分,也就是0-1之间的值。
------------------------------------------------------------------------------------------------------------------------------------------------------
IEEE754 floats
也就是说:0.3可以分解成:{2^(-2) + 2^(-5) + 2^(-6)} + {2^(-9) + 2^(-10) + 2^(-13) + 2^(-14)} + {2^(-17) + 2^(-18) + 2^(-21) + 2^(-22)} + {2^(-25)}
也就是说:如果我们能分别拿到上面的四部分,就能重新拼出这个0.3,那么如何得到每一部分的值呢?
{2^(-25)}:这个比较简单,fract(0.3 << 24) >> 24; [fract函数为取小数部分]
{2^(-17) + 2^(-18) + 2^(-21) + 2^(-22)}:(fract(0.3 << 16) - (fract(0.3 << 24) >> 8)) >> 16
我们来分析一下:
- a:=fract(0.3 << 16),先右移16位再取小数部分,这样得到的结果是({2^(-17) + 2^(-18) + 2^(-21) + 2^(-22)} + {2^(-25)})<< 16
- b:= fract(0.3 << 24) >> 8, 结果是{2^(-25)}<<16
- 哈哈,(a - b)>>16 就得到了蓝色部分{2^(-17) + 2^(-18) + 2^(-21) + 2^(-22)}
依次类推:
{2^(-9) + 2^(-10) + 2^(-13) + 2^(-14)} :(fract(0.3 << 8) - (fract(0.3 << 16) >> 8)) >> 8
{2^(-2) + 2^(-5) + 2^(-6)}: (fract(0.3) - (fract(0.3 << 8) >> 8)) >> 0
------------------------------------------------------------------------------------------------------------------------------------------------------
To Sum Up : 上面的两个函数。