你如何打包一个32位int在glsl / webgl中的4位,8位整数?
我正在寻找并行化一些复杂的math,webgl看起来是完美的方式来做到这一点。 问题是,你只能从纹理读取8位整数。 理想情况下,我想从纹理中获取32位数字。 我想到了使用4个颜色通道来获得每像素32位,而不是4个8位。
我的问题是,glsl没有“%”运算符或任何按位运算符!
TLDR:如何使用glsl中的运算符将32位数字转换为4 8位数字。
关于该技术的一些额外信息(使用按位运算符):
如何在两个32位整数中存储64位整数并再次转换回来
你可以通过乘以/除以2的幂来移位。
正如在评论中指出的,我最初发布的方法是有效但不正确的, 这里是ArasPranckevičius的方法 ,请注意,post中的源代码本身包含一个拼写错误,是HLSL,这是一个GLSL端口,
const vec4 bitEnc = vec4(1.,255.,65025.,16581375.); const vec4 bitDec = 1./bitEnc; vec4 EncodeFloatRGBA (float v) { vec4 enc = bitEnc * v; enc = fract(enc); enc -= enc.yzww * vec2(1./255., 0.).xxxy; return enc; } float DecodeFloatRGBA (vec4 v) { return dot(v, bitDec); }
一般来说,如果要打印浮点数的有效数字(以字节为单位),则必须连续提取有效数字的8位数据包并将其存储在一个字节中。
在预定义的范围内编码一个浮点数
为了将浮点值打包到4 * 8位缓冲区中,必须首先指定源值的范围。
如果您已经定义了值范围[ minVal
, maxVal
],则必须将其映射到范围[ minVal
]:
float mapVal = clamp((value-minVal)/(maxVal-minVal), 0.0, 1.0);
函数Encode
将浮点值在[ vec4
]范围内打包到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
提取范围[ vec4
]中的浮点值:
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字节对数字进行编码已经足够了。
另请参阅以下问题的答案:
- 如何在float和vec4,vec3,vec2之间进行转换?
- OpenGL ES将深度数据写入颜色
- 在H264中以RGB颜色编码浮点灰度,并重新读取深度值
- 将颜色转换为世界空间坐标(GLSL ES) :