如何在float和vec4,vec3,vec2之间进行转换?

时间:2016-02-18 16:17:48

标签: opengl-es webgl glsles

此问题与此处的问题(How do I convert a vec4 rgba value to a float?)非常相关。

已经有一些与此问题相关的文章或问题,但我想知道大多数文章都没有确定哪种类型的浮动值。 只要我能想到,下面有一些浮动值包装/拆包公式。

  • unsigned normalized float
  • 签署规范化的浮动
  • 签名的范围浮点数(我可以找到范围限制的浮动值)
  • unsigned ranged float
  • unsigned float
  • signed float

然而,实际上这只是2个案例。其他包装/拆包可以通过这两种方法进行处理。

  • unsigned ranged float(我可以通过简单的位移来打包/解包)
  • signed float

我想将已签名的浮动值打包并解压缩到vec3或vec2中。

对于我的情况,浮动值不能保证标准化,所以我不能使用简单的位移方式。

4 个答案:

答案 0 :(得分:7)

如果您知道要存储的最大值范围,比如说+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;
}

答案 1 :(得分:3)

我几天前用shadertoy写了一个小例子: https://www.shadertoy.com/view/XdK3Dh

它将float存储为RGB或从像素加载浮点数。还有测试函数是精确的反转(由于精度差,我见过的很多其他函数在某些范围内都有bug)。

整个示例假设您要在缓冲区中保存值并在下一次绘制中将其读回。只有256种颜色,它限制您获得16777216个不同的值。大多数时候我不需要更大的规模。我也把它移到了间隔< -8388608; 8388608>中的签名浮点数。

(function (el) {
    var ship = $("<div class='ship' id='saleShip'></div>");

    el.append(ship);

    setTimeout(function () {
      ship.remove();
    }, 5000);

}($('#saleShipHolder')));

还有一件事,溢出的值将四舍五入为最小值/最大值。

答案 2 :(得分:2)

为了在vec3vec4minVal中打包浮点值,必须限制并明确指定源值的范围,或者指数必须以某种方式存储。
一般来说,如果浮点数的有效数字应以字节为单位,则必须从有效数字中提取连续的8位数据包,并且必须将其存储在一个字节中。


在限制和预定义范围内编码浮点数

必须定义值范围[maxValminVal],其中包括要编码的所有值,并且值范围必须映射到[0.0,1.0]的范围。

将[maxValvec2]范围内的浮点数编码为vec3vec4vec2 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; }

vec2

vec3vec4minVal解码为[maxValfloat 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

注意,由于标准的32位IEEE 754号码只有24位有效数字,因此将数字编码为3个字节就足够了。


对有效位数和浮点数的指数

进行编码

将浮点数及其指数的有效数字编码为vec3vec4vec2 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

vec3vec4float DecodeExpV2( in vec2 pack ) { int exponent = int( pack.z * 256.0 - 127.0 ); float value = pack.x * (2.0*256.0) / 255.0 - 1.0; return value * exp2( float(exponent) ); } float DecodeExpV3( in vec3 pack ) { int exponent = int( pack.z * 256.0 - 127.0 ); float value = dot( pack.xy, 1.0 / vec2(1.0, 256.0) ); value = value * (2.0*256.0*256.0) / (256.0*256.0 - 1.0) - 1.0; return value * exp2( float(exponent) ); } float DecodeExpV4( 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) ); } 解码为浮点数及其指数的有效数字:

{{1}}


另见以下问题的答案:

答案 3 :(得分:1)

我测试了gman的解决方案,发现比例因子不正确,并且会产生舍入误差,如果要将结果存储在RGB纹理中,则需要除以255.0。这是我修改后的解决方案:

#define SCALE_FACTOR (256.0 * 256.0 * 256.0 - 1.0)

vec3 packFloatInto8BitVec3(float v, float min, float max) {
   float zeroToOne = (v - min) / (max - min);
   float zeroTo24Bit = zeroToOne * SCALE_FACTOR;
   return floor(
        vec3(
            mod(zeroTo24Bit, 256.0),
            mod(zeroTo24Bit / 256.0, 256.0),
            zeroTo24Bit / 256.0 / 256.0
        )
    ) / 255.0;
}

float unpack8BitVec3IntoFloat(vec3 v, float min, float max) {
   vec3 scaleVector = vec3(1.0, 256.0, 256.0 * 256.0) / SCALE_FACTOR * 255.0;
   float zeroToOne = dot(v, scaleVector);
   return zeroToOne * (max - min) + min;
}

示例:

  • 如果使用min = 0和max = 1打包0.25,您将获得(1.0,1.0,0.247059)
  • 如果解压缩该向量,将得到0.249999970197678