如何在JavaScript中打包浮动到4个字节(rgba)?

时间:2017-03-25 20:00:53

标签: javascript opengl floating-point bit-manipulation glsl

试图在JavaScript中将标准化浮点数编码为rgba数组(四个0-255整数值)。具体而言,我正在尝试移植此GLSL代码:

vec4 packFloatToVec4i(const float value) {
  const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
  const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
  vec4 res = fract(value * bitSh);
  res -= res.xxyz * bitMsk;
  return res;
}

应该相当简单,但我仍然很难使用按位操作 据我所知,将vec4 bitSh应用于值相当于在[value << 24, value << 16, value << 8, value]中执行JS 而且我认为我理解比特移位和掩蔽作为一个概念应该做什么,但它对我来说仍然看起来像黑魔法。

预期结果:

packFloatToVec4i(0.4242) = [0,95,151,108]
packFloatToVec4i(0.108108) = [64,246,171,27]

更新 - 我尝试以粗略的形式重现没有位移操作符会产生奇怪的结果:

value = 0.4242
bitSh = [256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0]
bitMsk = [0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0]
res = bitSh.map(function(sh){return (sh*value)%1})
masked = [res[0]*bitMsk[0],res[0]*bitMsk[1],res[1]*bitMsk[2],res[2]*bitMsk[3]]
resres = res.map(function(r,i){return r - masked[i]});
console.log(resres) => [0.0272000003606081, 0.37109375, 0.59375, 0.421875]

顺便说一句,如果我将所有这些乘以255 - gba部分(rgba)似乎匹配预期结果(如果舍入)r - 不是。 :\

你能帮我理解这里发生了什么,并在JS中复制这个吗?

1 个答案:

答案 0 :(得分:0)

我已经建立了一个工作端口:

function packFloatToVec4i(value) {
    value = new Float32Array([value])[0];
    var msk = 1/256;
    var bitSh = [16777216, 65536, 256.0, 1.0];
    var bitMsk = [0.0, msk, msk, msk];
    var shifted = [value*bitSh[0]%1,value*bitSh[1]%1,value*bitSh[2]%1,value*bitSh[3]%1];    
    var masked = [shifted[0]*bitMsk[0],shifted[0]*bitMsk[1],shifted[1]*bitMsk[2],shifted[2]*bitMsk[3]];    
    var res = [Math.round((shifted[0]-masked[0])*255),Math.round((shifted[1]-masked[1])*255),Math.round((shifted[2]-masked[2])*255),Math.round((shifted[3]-masked[3])*255)];
    return res;
};

与我发布的问题的差异是输入值的双重转换。如果没有它,由于GLSL中的浮点值的函数这一事实导致结果失效 此外,为了提高性能,我还展开了我的.map循环。

关于bitshift操作,似乎在内部,在JS中,它们应用的任何值 - 转换为32位整数,这有效地删除了任何小数信息。因此,在这种情况下,位移操作似乎不可能。

纠正我,如果我错了,可以在这里使用位移/屏蔽,但就目前而言,这将有所帮助。