这个问题与这里的问题非常相关(How do I convert a vec4 rgba value to a float?)。
已经有一些与此问题相关的文章或问题,但我想知道大多数文章都没有确定哪种类型的浮动值。只要我能想到,下面有一些浮动值包装/拆包公式。
然而,实际上这只是两个案例。其他包装/拆包可以通过这两种方法处理。
我想将已签名的浮动值打包并解压缩到vec3或vec2中。
对于我的情况,浮动值不能确保标准化,所以我不能使用简单的位移方式。
如果您知道要存储的最大值范围,比如说+5到-5,那么最简单的方法就是选择一些转换范围为0到1的值。将它扩展为您拥有的位数和然后把它分成几部分。
vec2 packFloatInto8BitVec2(float v, float min, float max) {
float zeroToOne = (v - min) / (max - min);
float zeroTo16Bit = zeroToOne * 256.0 * 255.0;
return vec2(mod(zeroToOne, 256.0), zeroToOne / 256.0);
}
要把它放回去,你会做相反的事情。组装零件,除以返回零到一个值,然后按范围扩展。
float unpack8BitVec2IntoFloat(vec2 v, float min, float max) {
float zeroTo16Bit = v.x + v.y * 256.0;
float zeroToOne = zeroTo16Bit / 256.0 / 255.0;
return zeroToOne * (max - min) + min;
}
对于vec3,只需扩展它
vec3 packFloatInto8BitVec3(float v, float min, float max) {
float zeroToOne = (v - min) / (max - min);
float zeroTo24Bit = zeroToOne * 256.0 * 256.0 * 255.0;
return vec3(mod(zeroToOne, 256.0), mod(zeroToOne / 256.0, 256.0), zeroToOne / 256.0 / 256.0);
}
float unpack8BitVec3IntoFloat(vec3 v, float min, float max) {
float zeroTo24Bit = v.x + v.y * 256.0 + v.z * 256.0 * 256.0;
float zeroToOne = zeroTo24Bit / 256.0 / 256.0 / 256.0;
return zeroToOne * (max - min) + min;
}
几天前我用shadertoy写了一个小例子:https://www.shadertoy.com/view/XdK3Dh
它将float存储为RGB或从像素加载float。还有测试函数是精确的反转(由于精度差,我见过的很多其他函数在某些范围内都有bug)。
整个示例假设您希望将值保存在缓冲区中并在下一次绘制中将其读回。只有256种颜色,它限制您获得16777216个不同的值。大多数时候我不需要更大的规模。我也把它改为在间隔<-8388608; 8388608>中签名浮动。
float color2float(in vec3 c) {
c *= 255.;
c = floor(c); // without this value could be shifted for some intervals
return c.r*256.*256. + c.g*256. + c.b - 8388608.;
}
// values out of <-8388608;8388608> are stored as min/max values
vec3 float2color(in float val) {
val += 8388608.; // this makes values signed
if(val < 0.) {
return vec3(0.);
}
if(val > 16777216.) {
return vec3(1.);
}
vec3 c = vec3(0.);
c.b = mod(val, 256.);
val = floor(val/256.);
c.g = mod(val, 256.);
val = floor(val/256.);
c.r = mod(val, 256.);
return c/255.;
}
还有一件事,溢出的值将四舍五入为最小值/最大值。
为了在vec2
,vec3
或vec4
中打包浮点值,要么限制和明确指定源值的范围,要么也必须以某种方式存储指数。
通常,如果浮点数的有效数字应以字节为单位,则必须从有效数字中提取连续的8位数据包,并且必须将其存储在一个字节中。
必须定义值范围[minVal
,maxVal
],其中包括要编码的所有值,并且值范围必须映射到[0.0,1.0]的范围。
编码[minVal
,maxVal
]到vec2
,vec3
和vec4
范围内的浮点数:
vec2 EncodeRangeV2( in float value, in float minVal, in float maxVal )
{
value = clamp( (value-minVal) / (maxVal-minVal), 0.0, 1.0 );
value *= (256.0*256.0 - 1.0) / (256.0*256.0);
vec3 encode = fract( value * vec3(1.0, 256.0, 256.0*256.0) );
return encode.xy - encode.yz / 256.0 + 1.0/512.0;
}
vec3 EncodeRangeV3( in float value, in float minVal, in float 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 encode.xyz - encode.yzw / 256.0 + 1.0/512.0;
}
vec4 EncodeRangeV4( in float value, in float minVal, in float 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;
}
将qazxsw poi,qazxsw poi和qazxsw poi解码为[vec2
,vec3
]范围内的浮点数:
vec4
注意,由于标准的32位[IEEE 754] [2]数字只有24位有效数字,因此用3个字节编码数字就足够了。
将浮点数及其指数的有效数字编码为minVal
,maxVal
和float DecodeRangeV2( in vec2 pack, in float minVal, in float maxVal )
{
float value = dot( pack, 1.0 / vec2(1.0, 256.0) );
value *= (256.0*256.0) / (256.0*256.0 - 1.0);
return mix( minVal, maxVal, value );
}
float DecodeRangeV3( in vec3 pack, in float minVal, in float maxVal )
{
float value = dot( pack, 1.0 / vec3(1.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 );
}
float DecodeRangeV4( in vec4 pack, in float minVal, in float maxVal )
{
float 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 );
}
:
vec2
将vec3
,vec4
和vec2 EncodeExpV2( in float value )
{
int exponent = int( log2( abs( value ) ) + 1.0 );
value /= exp2( float( exponent ) );
value = (value + 1.0) * 255.0 / (2.0*256.0);
vec2 encode = fract( value * vec2(1.0, 256.0) );
return vec2( encode.x - encode.y / 256.0 + 1.0/512.0, (float(exponent) + 127.5) / 256.0 );
}
vec3 EncodeExpV3( in float value )
{
int exponent = int( log2( abs( value ) ) + 1.0 );
value /= exp2( float( exponent ) );
value = (value + 1.0) * (256.0*256.0 - 1.0) / (2.0*256.0*256.0);
vec3 encode = fract( value * vec3(1.0, 256.0, 256.0*256.0) );
return vec3( encode.xy - encode.yz / 256.0 + 1.0/512.0, (float(exponent) + 127.5) / 256.0 );
}
vec4 EncodeExpV4( 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 );
}
解码为浮点数及其指数的有效数字:
vec2
另请参阅以下问题的答案:
vec3