【问题标题】:Get accurate integer modulo in WebGL shader在 WebGL 着色器中获取准确的整数模数
【发布时间】:2016-02-27 18:41:32
【问题描述】:

我想在 WebGL 片段着色器中获得 xy 的精确模数。 xy 是整数。

绘制mod(x,y),我们得到以下信息:

用于生成红黑矩形的实际代码为:

gl_FragColor = vec4(mod(
  float(int(v_texCoord[0]*15.))/15.,
  float(int(v_texCoord[1]*15.))/15.
), 0, 0, 1);

其中 v_texCoord 是一个 vec2,范围从左上角的 0,0 到右下角的 1,1。 float 和 int 的精度都设置为 mediump。

阅读图表,我们看到虽然mod(6,6) 是正确的0,但mod(7,7) 实际上是7我该如何解决这个问题?

我尝试实现自己的 mod() 函数。但是,它有相同的错误,并产生相同的图表。

int func_mod(int x, int y) {
    return int(float(x)-float(y)*floor(float(x)/float(y)));
}

在 Javascript 中,我可以调试它,该功能完美运行。然后我尝试了一种迭代方法,因为我担心自己会发疯,而且我也不相信浮点除法。

int iter_mod(int x, int y) {
    x = int(abs(float(x))); y = int(abs(float(y)));
    for(int i=0; i>-1; i++) {
        if(x < y) break;
        x = x - y;
    }
    return x;
}

这行得通,但我无法绘制它,因为当我尝试时,它会使 linux 崩溃,并在 ring 0 中出现错误。它适用于我需要它的 spritesheet 计算,但我真的觉得这是一个不正确的解决方案。

(更新:它在我的手机上完美运行。现在不是我的代码出错了,这只是我的问题……)

【问题讨论】:

    标签: webgl shader fragment-shader


    【解决方案1】:

    这是一个 GLSL 函数,它使用应该是整数的 (float) 参数准确计算 MOD:

    /**
     * Returns accurate MOD when arguments are approximate integers.
     */
    float modI(float a,float b) {
        float m=a-floor((a+0.5)/b)*b;
        return floor(m+0.5);
    }
    

    请注意,如果 a0 则返回值将 >=0,这与其他语言的 % 运算符不同。

    【讨论】:

      【解决方案2】:

      你不是在修改 7 到 7,而是在修改 7/15 到 7/15

      试试

      gl_FragColor = vec4(mod(
        floor(v_texCoord[0] * 15.),
        floor(v_texCoord[1] * 15.)
      ) / 15., 0, 0, 1);
      

      你可以看到这里运行的 2 个版本

      function render(num) {
        var gl = document.getElementById("c" + num).getContext("webgl");
        var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
      
        var arrays = {
          position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
        };
        var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
      
        var uniforms = {
          resolution: [gl.canvas.width, gl.canvas.height],
          intMod: num == 1,
        };
      
        gl.useProgram(programInfo.program);
        twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
        twgl.setUniforms(programInfo, uniforms);
        twgl.drawBufferInfo(gl, bufferInfo);
      }
      
      render(0)
      render(1);
      canvas { margin: 1em; height: 100px; width: 150px; }
      div { display: inline-block; }
      pre { text-align: center; }
      <script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
        <script id="vs" type="notjs">
      attribute vec4 position;
      
      void main() {
        gl_Position = position;
      }
        </script>
        <script id="fs" type="notjs">
      precision mediump float;
      
      uniform vec2 resolution;
      uniform bool intMod;
      
      void main() {
        vec2 v_texCoord = gl_FragCoord.xy / resolution.xy;
      
        if (!intMod) {
        
          gl_FragColor = vec4(mod(
            float(int(v_texCoord[0]*15.))/15.,
            float(int(v_texCoord[1]*15.))/15.
          ), 0, 0, 1);
      
        } else {
      
          gl_FragColor = vec4(mod(
            floor(v_texCoord[0]*15.),
            floor(v_texCoord[1]*15.)
          )/15., 0, 0, 1);
          
        }
        
      }
        </script>
      <div><canvas id="c0"></canvas><pre>mod with fractions</pre></div>
      <div><canvas id="c1"></canvas><pre>mod with ints</pre></div>

      您还应该注意 mod by 0 是未定义的,这意味着您将在不同的 GPU 上获得不同的结果

      【讨论】:

        【解决方案3】:

        请注意,从 webGL2 开始,我们现在有了 int 操作,所以这个问题现在可以通过 x % y 轻松解决。

        【讨论】:

        • 我不认为这是正确的。如果我尝试做x % y,我会得到'%' : integer modulus operator supported in GLSL ES 3.00 and above only。据我了解,模数运算符仅在我们在脚本开头指定 #version 130 时才有效,但 AFAIK 尚无浏览器支持此版本的 GLSL ES。
        • 我的错,看起来你可以做 #version 300 es 并且它有效。
        • 当你看到你写错了,逻辑就是删除帖子;-)。
        • 我留下了它以防其他人遇到同样的问题。如果您在线搜索错误消息,人们会说使用#version 130,它在任何浏览器中都不起作用。我希望我的评论可以帮助其他人。
        猜你喜欢
        • 2018-10-27
        • 1970-01-01
        • 1970-01-01
        • 2012-07-23
        • 1970-01-01
        • 2014-03-24
        • 1970-01-01
        • 1970-01-01
        • 2013-02-22
        相关资源
        最近更新 更多