草庐IT

javascript - 在 WebGL 中从 Float32Array 到 Uint16Array 的转换

coder 2024-07-26 原文

我有 Float32Array 纹理,可以通过 WebGL 正确显示。但是,当我尝试将它们转换为 Uint16Array 时,问题出现了。

这是我的转换部分。

var _floatToHalfFloat = function(input, offset) {
    var largestHalf = Math.pow(2, 30-15) * (1 + 1023/1024);
    var m = new ArrayBuffer(4);
    var n = new Float32Array(m);
    var o = new Uint32Array(m);
    var f = 0.0;
    for (var i = input.length - 1 - offset; i >= 0;i--) {
        n[0] = input[i];
        f = o[0];
        // fast conversion of half
        // ref : ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf

        if (isNaN(input[i])) {
            input[i] = 0x7fff;
        } else if(n === Infinity || n > largestHalf) {
            input[i] = 0x7c00;
        } else if(n === -Infinity || n < -largestHalf) {
            input[i] = 0xfc00;
        } else if(n === 0) {
            input[i] = 0;
        } else {
            input[i] = ((f>>16)&0x8000)|((((f&0x7f800000)-0x38000000)>>13)&0x7c00)|((f>>13)&0x03ff);
        }
    }
    return new Uint16Array(input);
};

最佳答案

当原始图像达到黑色时,我们可以在转换后的图像中看到饱和色(全红、全绿和/或全蓝)。我认为该函数在接近 0 时效果不佳。

我已经快速实现了 wikipedia explanation of norm of the float 16 bits.

<html>
<head>
<script>
var _floatToHalfFloat = #### YOUR FUNCTION HERE CUT ####

var _halfFloatToFloat = function(hf) {
  var m = new ArrayBuffer(2);
  var n = new Uint16Array(m);
  n[0] = hf;
  var sign = n[0] & 0x8000;
  var exp = (n[0] >> 10) & 0x1F;
  var mant = n[0]& 0x03FF;
  document.getElementById('sign').innerHTML += sign+" - ";
  document.getElementById('exp').innerHTML += exp+" - ";
  document.getElementById('mant').innerHTML += mant+" - ";
  if (exp == 0x1F) {
    return 1.0 * Math.pow(-1, sign) * Infinity;
  } else if (exp == 0) {
    return Math.pow(-1, sign) *
           Math.pow(2, -14) *
           (mant / Math.pow(2, 10));
  } else {
    return Math.pow(-1, sign) *
           Math.pow(2, exp-15) *
           (1+(mant / Math.pow(2, 10)));
  }
};

document.addEventListener("DOMContentLoaded", function(event) {
  var input = new Float32Array(8);
  input[0] = 2.5;
  input[1] = 0.25;
  input[2] = 0.025;
  input[3] = 0.025;
  input[4] = 0.0025;
  input[5] = 0.00025;
  input[6] = 0.000025;
  input[7] = 0.0;

  var i, s = "Value before = ";
  for (i = 0; i < input.length; i++) 
    s += input[i] + " - ";
  document.getElementById('res1').innerHTML = s;
  var output = _floatToHalfFloat(input, 0);
  s = "Value after = ";
  for (i = 0; i < output.length; i++) 
    s += _halfFloatToFloat(output[i]) + " - ";
  document.getElementById('res2').innerHTML = s;
});
</script>
</head>
<body>
  <span id="res1">result</span></br>
  <span id="res2">result</span></br>
  </br></br></br>
  <span id="sign">signs =</span></br>
  <span id="exp">exponents =</span></br>
  <span id="mant">mantissas =</span></br>
</body>
</html>

测试结果如下图:

Value before = 2.5 - 0.25 - 0.02500000037252903 - 0.02500000037252903 - 0.0024999999441206455 - 0.0002500000118743628 - 0.00002499999936844688 - 0 -
Value after = 2.5 - 0.25 - 0.024993896484375 - 0.024993896484375 - 0.002498626708984375 - 0.0002498626708984375 - Infinity - 2 -



signs =0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 -
exponents =16 - 13 - 9 - 9 - 6 - 3 - 31 - 16 -
mantissas =256 - 0 - 614 - 614 - 286 - 24 - 653 - 0 - 

这表明最后 2 个信息不连贯。 0.000025 转换为无穷大(而不是 0?),0 本身转换为 2。这似乎不正确。当你想编码一个零“维基百科说”你的尾数和你的指数应该是零。在您提供的代码中,尾数为零,但指数为 16,这导致 2 (2^(16-15))。

稍微调整一下您的函数后,似乎所有情况都被视为正常情况。这是由于您的 if 语句中存在错误。所以而不是:

} else if(n === 0) {
    input[i] = 0;
}

你可能想做这样的事情:

} else if(n[0] === 0) {
    input[i] = 0;
}

对于 n 变量的所有使用都是一样的。但是你仍然有下溢问题。所以你可能会发现可以接受:

} else if(Math.abs(n[0]) < 0.0001) {
    input[i] = 0;
}

关于javascript - 在 WebGL 中从 Float32Array 到 Uint16Array 的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30102972/

有关javascript - 在 WebGL 中从 Float32Array 到 Uint16Array 的转换的更多相关文章

  1. ruby - 在 Ruby 中实现 `call_user_func_array` - 2

    我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)

  2. Ruby Koans about_array_assignment - 非平行与平行分配歧视 - 2

    通过ruby​​koans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John

  3. arrays - 这是 Ruby 中 Array.fill 方法的错误吗? - 2

    这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]

  4. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  5. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  6. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  7. Ruby on Rails regexp equals-tilde 与 array include 用于检查选项列表 - 2

    我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试

  8. ruby - 在 Ruby 中,为什么 Array.new(size, object) 创建一个由对同一对象的多个引用组成的数组? - 2

    如thisanswer中所述,Array.new(size,object)创建一个数组,其中size引用相同的object。hash=Hash.newa=Array.new(2,hash)a[0]['cat']='feline'a#=>[{"cat"=>"feline"},{"cat"=>"feline"}]a[1]['cat']='Felix'a#=>[{"cat"=>"Felix"},{"cat"=>"Felix"}]为什么Ruby会这样做,而不是对object进行dup或clone? 最佳答案 因为那是thedocumenta

  9. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

  10. ruby - 为什么Array的pop方法没有感叹号? - 2

    我认为按照惯例,只有带有感叹号的方法才能更改对象。>array=[1,2,3]=>[1,2,3]>array.pop=>3>array=>[1,2]为什么Array的pop方法不调用pop!? 最佳答案 这不太正确。来自TheRubyStyleGuide潜在“危险”方法的名称(即修改自身或参数的方法,exit!(不像exit那样运行终结器)等)如果存在则应以感叹号结尾该危险方法的安全版本。而且pop方法的名称准确地说明了它在做什么,因此无需使用感叹号对其进行签名。 关于ruby-为什么A

随机推荐