一般来说,如果要将浮点数的有效数字打包成字节,则必须连续提取有效数字的8位数据包并存储在一个字节中。
在预定义的范围内编码一个浮点数
为了将浮点值打包到 4 * 8 位缓冲区中,必须首先指定源值的范围。
如果您定义了值范围 [minVal, maxVal] ,它必须映射到范围 [0.0, 1.0]:
float mapVal = clamp((value-minVal)/(maxVal-minVal), 0.0, 1.0);
函数Encode将[0.0, 1.0]范围内的浮点值打包到vec4中:
vec4 Encode( in float value )
{
value *= (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
vec4 encode = fract( value * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
return vec4( encode.xyz - encode.yzw / 256.0, encode.w ) + 1.0/512.0;
}
函数Decode从vec4中提取[0.0, 1.0]范围内的浮点值:
float Decode( in vec4 pack )
{
float value = dot( pack, 1.0 / vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
return value * (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);
}
以下函数在 [minVal, maxVal] 范围内和范围内打包并提取浮点值:
vec4 EncodeRange( in float value, flaot minVal, maxVal )
{
value = clamp( (value-minVal) / (maxVal-minVal), 0.0, 1.0 );
value *= (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
vec4 encode = fract( value * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
return vec4( encode.xyz - encode.yzw / 256.0, encode.w ) + 1.0/512.0;
}
float DecodeRange( in vec4 pack, flaot minVal, maxVal )
{
value = dot( pack, 1.0 / vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
value *= (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);
return mix( minVal, maxVal, value );
}
用指数编码浮点数
另一种可能性是将有效数字编码为 RGB 值的 3 * 8 位,并将指数编码为 alpha 通道的 8 位:
vec4 EncodeExp( in float value )
{
int exponent = int( log2( abs( value ) ) + 1.0 );
value /= exp2( float( exponent ) );
value = (value + 1.0) * (256.0*256.0*256.0 - 1.0) / (2.0*256.0*256.0*256.0);
vec4 encode = fract( value * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
return vec4( encode.xyz - encode.yzw / 256.0 + 1.0/512.0, (float(exponent) + 127.5) / 256.0 );
}
float DecodeExp( in vec4 pack )
{
int exponent = int( pack.w * 256.0 - 127.0 );
float value = dot( pack.xyz, 1.0 / vec3(1.0, 256.0, 256.0*256.0) );
value = value * (2.0*256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0) - 1.0;
return value * exp2( float(exponent) );
}
注意,由于标准的 32 位 IEEE 754 数字只有 24 位有效数字,因此将数字编码为 3 个字节就足够了。
另见How do I convert between float and vec4,vec3,vec2?