用texture给GUP传参数,好多GPU不支持浮点数纹理,所以要自己实现浮点数的编码解码。
我们研究32位编码,和24位编码。
ieee754标准可以从网上搜索学习。
对于32位浮点数,1位表示正负,0位正,1为负;8位表示指数;23位表示小数。
详细内容参见:https://www.cnblogs.com/HDK2016/p/10506083.html
用js简单实现:
var floatBuffer = new Float32Array(1); var uintBuffer = new Uint8Array(floatBuffer.buffer); decode(0.15625); decode(123.456); decode(-123.456); decode(3154.138916015625); decode(768); function decode(value){ floatBuffer.set([value]); console.log(uintBuffer); var r = uintBuffer[0]; var g = uintBuffer[1]; var b = uintBuffer[2]; var a = uintBuffer[3]; var bits = []; for(var i = 0; i < 4; i++) { var v = uintBuffer[3 - i]; var n = 128; for(var j = 0; j < 8; j++) { bits.push(Math.floor(v / n)); v = v % n; n = n / 2; } } var sign = bits[0]; var e = 0; for(var i = 1; i < 9; i++) { e = e * 2 + bits[i]; } console.log(bits); console.log(sign); console.log(e); e = e - 127 console.log(e); var f = 1; var m = 0.5; for(var i = 9; i < 32; i++) { var bs = bits[i]; f += bs * m; m *= 0.5; } console.log(f); var r = f * Math.pow(2, e) * (sign ? (-1): 1); console.log(r); console.log("--------------------"); console.log(value +" 解码后 " + r); console.log("--------------------"); }
GPU中解码,可以从gpu.js中提取,,如下。
// Here be dragons! // DO NOT OPTIMIZE THIS CODE // YOU WILL BREAK SOMETHING ON SOMEBODY\'S MACHINE // LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME const vec2 MAGIC_VEC = vec2(1.0, -256.0); const vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0); const vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536 float decode32(vec4 texel) { texel *= 255.0; vec2 gte128; gte128.x = texel.b >= 128.0 ? 1.0 : 0.0; gte128.y = texel.a >= 128.0 ? 1.0 : 0.0; float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC); float res = exp2(_round(exponent)); texel.b = texel.b - 128.0 * gte128.x; res = dot(texel, SCALE_FACTOR) * exp2(_round(exponent-23.0)) + res; res *= gte128.y * -2.0 + 1.0; return res; }
对于24位。我们取1位作为符号位,7位作为指数位,16位作为小数位。(指数位不应该是7,可以计算一下,用多少合适,这里为了简单,取7)。
代码如下:
[0.15625, 123.456, -123.456, 3154.138916015625, 768, -768,2633.142857142857, 1.0, -1.0].forEach((value) => { var a = encode(value); console.log(value, a, decode(a)); }); function encode(value) { var sign = value > 0 ? 0 : 1; value = Math.abs(value); var exponent = Math.floor(Math.log2(value)); var mantissa = value * Math.pow(2, -exponent) - 1.0; exponent = (exponent + 63) % 128; var r = exponent + 128 * sign; mantissa *= 256; var g = Math.floor(mantissa); mantissa = mantissa % 1; mantissa *= 256; var b = Math.floor(mantissa); return [r, g, b]; } function decode(arr){ var r = arr[0]; var g = arr[1]; var b = arr[2]; var sign = r >= 128 ? 1 : 0; var exponent = (r - sign * 128) - 63; var mantissa = ((256 + g) * 256 + b) * Math.pow(2, -16); var f = mantissa * Math.pow(2, exponent) * (1 - sign * 2); return f; }
平时用不到,编程语言都实现了。遇到问题的时候,知识储备就发挥作用了,这种编码解码比单纯乘个系数做个平移,再取余,要好得多。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。