Opengl es 如何在float和vec4、vec3、vec2之间转换?

Opengl es 如何在float和vec4、vec3、vec2之间转换?,opengl-es,webgl,glsles,Opengl Es,Webgl,Glsles,这个问题与这里的问题非常相关() 已经有一些文章或问题与这个问题相关,但我想知道大多数文章都没有确定哪种类型的浮动价值。 只要我能想出,下面有一些浮值包装/拆包公式 无符号规范化浮点 有符号规范化浮点 有符号范围浮点(我可以找到范围限制的浮点值) 无符号范围浮点 无符号浮点 签名浮动 然而,实际上这只是两种情况。其他包装/拆包可通过这2种方法进行处理 无符号范围浮点(我可以通过简单的位移位进行打包/解包) 签名浮动 我还想将带符号的浮点值打包并解包到vec3或vec2中 在我的例子中,浮

这个问题与这里的问题非常相关()

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

  • 无符号规范化浮点
  • 有符号规范化浮点
  • 有符号范围浮点(我可以找到范围限制的浮点值)
  • 无符号范围浮点
  • 无符号浮点
  • 签名浮动
然而,实际上这只是两种情况。其他包装/拆包可通过这2种方法进行处理

  • 无符号范围浮点(我可以通过简单的位移位进行打包/解包)
  • 签名浮动
我还想将带符号的浮点值打包并解包到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(zeroTo16Bit, 256.0), zeroTo16Bit / 256.0);
}
把它放回去,你做的正好相反。组装零件,将其拆分为一个zeroToOne值,然后按范围展开

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(zeroTo24Bit, 256.0), mod(zeroTo24Bit / 256.0, 256.0), zeroTo24Bit / 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一起写了一个小例子:

它将浮点存储为RGB或从像素加载浮点。还有一个测试表明函数是精确的逆函数(我见过的许多其他函数在某些范围内有错误,因为精度不高)

整个示例假设您希望将值保存在缓冲区中,并在下一次绘制时将其读回。由于只有256种颜色,它限制您获得16777216个不同的值。大多数时候,我不需要更大的规模。我还把它改成了在间隔时间内使用float

float color2float(在vec3 c中){
c*=255。;
c=地板(c);//如果没有此值,可以在某些时间间隔内移动
返回c.r*256.*256.+c.g*256.+c.b-8388608。;
}
//中的值存储为最小/最大值
vec3浮点2颜色(在浮点值中){
val+=8388608;//这使值有符号
如果(val<0.){
返回向量3(0);
}
如果(val>16777216.){
返回向量3(1);
}
vec3 c=vec3(0.);
c、 b=模数(val,256.);
val=地板(val/256.);
c、 g=模数(val,256.);
val=地板(val/256.);
c、 r=模(val,256.);
返回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;
}
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
vec4
解码为[
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 );
}
注意,由于标准32位[IEEE 754][2]数字只有24位有效数字,因此完全可以将数字编码为3个字节


对浮点数的有效数字和指数进行编码 将浮点数的有效位及其指数编码为
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;
}
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
vec4
解码为浮点数的有效位及其指数:

float 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) );
}

另见以下问题的答案:


我测试了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;
}
例如:

  • 如果使用最小值=0和最大值=1打包0.25,则会得到(1.0、1.0、0.247059)
  • 如果你解开这个向量,你会得到0.24999970197678

我是个白痴,所以,请确认:您提供了一个
GLfloat
作为属性,并且希望它是由两个或三个其他浮点值组成的包,然后需要解包?因此,您的值在
glVertexAttributePointer
中没有标准化,这不是说您创建了一个未标准化的浮点数(尾数/指数)?如果是这样的话,CPU区域中的原始向量是否存在已知的范围限制?如果存在范围限制,我可以通过除以范围进行规格化,并且我可以使用相同的打包/解包方式对规格化浮点值进行打包。但是,在我的情况下,实际上没有限制。。。所以它需要尾数/指数来实现它。
%
在WebGL 1中是有效的运算符吗?我想它应该只适用于WebGL 2(GLSL ES 3.00)。我想如果我用mod重写%的话,这段代码会工作得很好。但是,这是我能找到的变量范围。mod vs%只是一个大脑屁。谢谢你指出这一点。在ES 3.0中,有用于打包/解包的内置功能以及保证的浮动目标(较少需要打包)。至于不知道范围,你会如何建议将32位浮点打包成16位vec2而不丢失一些东西呢。。。func