【问题标题】:How to get a bit from a float using GLSL on WebGL如何在 WebGL 上使用 GLSL 从浮点数中获取一些信息
【发布时间】:2020-03-31 21:29:39
【问题描述】:

在一个带有threeJs 的网络应用程序上,我有一个float32array,我将它作为我的几何图形的一个名为“state”的bufferAttribute 传递给我的顶点着色器。 如何获得顶点着色器中每个浮点数的第 n 位? 我需要类似的东西:

  vertexShader: `
  attribute float state;
  varying float active;

  void main() {
      active = getnthbit(state, 4); // get the fourth bit of the float value of state
     ...
 }`,...

我在这里查看了汤米的答案:https://stackoverflow.com/a/41946046/3548345 使用这个公式

float bit = step(0.5, mod(float(value) / 8.0, 1.0));

获得第三位,但它不起作用,我不明白。

【问题讨论】:

    标签: glsl webgl


    【解决方案1】:

    在 WebGL2 中,您可以传递整数数据并在着色器中进行整数数学运算(有符号和无符号)。

    在 WebGL1 中,你确实得到了浮点数,甚至标记为 int 的东西实际上可能不是 int。因此 AFAIK 你真的只能使用 mod 方法获得前 23 位

    您可以将getNthBit(float v, int bit) 实现为

    float getNthBit(float v, int bit) {
      return mod(floor((v + 0.5) / pow(2.0, float(bit))), 2.0);
    }
    

    或类似的东西。

    const gl = document.querySelector('canvas').getContext('webgl');
    const vs = `
    void main() {
      gl_PointSize = 150.0;
      gl_Position = vec4(0, 0, 0, 1);
    }
    `;
    const fs = `
    precision highp float;
    uniform float offset;
    
    float getNthBit(float v, int bit) {
      return mod(floor((v + 0.5) / pow(2.0, float(bit))), 2.0);
    }
    
    void main() {
      float v = gl_FragCoord.x + offset;
      int bit = int(gl_FragCoord.y);
      float nthBit = getNthBit(v, bit);
      
      gl_FragColor = vec4(0, nthBit > 0.0 ? 1.0 : 0.0, 0, 1);
    }
    `;
    
    const prg = twgl.createProgram(gl, [vs, fs]);
    const offLoc = gl.getUniformLocation(prg, 'offset');
    
    gl.useProgram(prg);
    
    let offset = 0;
    function render(time) {
      offset += 150;
      gl.uniform1f(offLoc, offset);
      gl.drawArrays(gl.POINTS, 0, 1);  // draw 1 point
      requestAnimationFrame(render);
    }
    
    requestAnimationFrame(render);
    <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
    <canvas 
        width="150"
        height="32"
        style="
          width: 450px;
          height: 192px;
          image-rendering: pixelated;
          border: 1px solid black;
        "></canvas>

    请注意,如果您只想提取每一位,就好像它是二进制数据一样,那么您可以将其声明为 UNSIGNED_SHORT 的 vec2,因此即使您将 float32s 放入缓冲区,您也会将它们读取为 UNSIGNED_SHORT

    然后使用类似的东西

    float getNthBit(vec2 v, int bit) {
      float t = bit < 16 ? v[0] : v[1];
      int b = bit < 16 ? bit : bit - 16;
      return mod(floor((t + 0.5) / pow(2.0, float(b))), 2.0);
    }
    

    例子

    const gl = document.querySelector('canvas').getContext('webgl');
    const vs = `
    attribute vec2 v;
    varying vec2 v_v;
    void main() {
      gl_PointSize = 150.0;
      gl_Position = vec4(0, 0, 0, 1);
      v_v = v;
    }
    `;
    const fs = `
    precision highp float;
    varying vec2 v_v;
    
    float getNthBit(vec2 v, int bit) {
      float t = bit < 16 ? v[0] : v[1];
      int b = bit < 16 ? bit : bit - 16;
      return mod(floor((t + 0.5) / pow(2.0, float(b))), 2.0);
    }
    
    void main() {
      int bit = 31 - int(gl_FragCoord.x / 4.0);
      float nthBit = getNthBit(v_v, bit);  
      gl_FragColor = vec4(0, nthBit > 0.0 ? 1.0 : 0.0, 0, 1);
    }
    `;
    
    const prg = twgl.createProgram(gl, [vs, fs]);
    const vLoc = gl.getAttribLocation(prg, 'v');
    
    const buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf, gl.STATIC_DRAW);
    gl.enableVertexAttribArray(vLoc);
    gl.vertexAttribPointer(vLoc, 2, gl.UNSIGNED_SHORT, false, 0, 0);
    
    gl.useProgram(prg);
    
    const data = new Float32Array(1);
    const bits = new Uint32Array(data.buffer);
    const inputElem = document.querySelector('input');
    const codeElem = document.querySelector('pre');
    
    function render() {
      data[0] = inputElem.value;
      codeElem.textContent = bits[0].toString(2).padStart(32, '0');
      gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
      gl.drawArrays(gl.POINTS, 0, 1);  // draw 1 point
    }
    render();
    inputElem.addEventListener('input', render);
    <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
    <canvas 
        width="128"
        height="4"
        style="
          width: 256px;
          height: 8px;
          image-rendering: pixelated;
          border: 1px solid black;
          display: block;
        "></canvas>
    <pre></pre>
    <input type="number" value="13445">

    【讨论】:

    • 这适用于我测试的整数,但缓冲区包含浮点数,如 1.6675451725465323e-43,它不适用于此
    • 如果您从浮点数中获取位,那么您可以将它们作为无符号短的 vec2 传递,在这种情况下,您将获得 2 个范围内的浮点数。见答案。
    猜你喜欢
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    相关资源
    最近更新 更多