【问题标题】:Stencil buffer in WebGLWebGL 中的模板缓冲区
【发布时间】:2020-04-19 17:28:47
【问题描述】:

如何为最简单的程序使用模板缓冲区? 我已经阅读了许多关于它的不同主题,但我没有找到关于它的详细指南。 我想在创建的四面体的每一侧都挖出一个洞。

请向我一步一步解释如何使用模板缓冲区?

Link for my program

【问题讨论】:

    标签: javascript canvas webgl stencil-buffer


    【解决方案1】:

    要使用模板缓冲区,您必须在创建 webgl 上下文时首先请求它

    const gl = someCanvasElement.getContext('webgl', {stencil: true});
    

    然后你打开模板测试

      gl.enable(gl.STENCIL_TEST);
    

    设置测试使其始终通过并将参考值设置为 1

      gl.stencilFunc(
         gl.ALWAYS,    // the test
         1,            // reference value
         0xFF,         // mask
      );
    

    并设置操作,以便当模板和深度测试都通过时,我们将模板设置为参考值

      gl.stencilOp(
         gl.KEEP,     // what to do if the stencil test fails
         gl.KEEP,     // what to do if the depth test fails
         gl.REPLACE,  // what to do if both tests pass
      );
    

    然后我们绘制第一个内三角形

    ... lots of setup for a single triangle ...
    
    gl.drawArrays(...) or gl.drawElements(...)
    

    然后我们更改测试,使其仅在模板为零时通过

      gl.stencilFunc(
         gl.EQUAL,     // the test
         0,            // reference value
         0xFF,         // mask
      );
      gl.stencilOp(
         gl.KEEP,     // what to do if the stencil test fails
         gl.KEEP,     // what to do if the depth test fails
         gl.KEEP,     // what to do if both tests pass
      );
    
    

    现在我们可以绘制其他东西(更大的三角形),它只会在模板缓冲区中的 0 处绘制,除了第一个三角形被绘制的位置之外,它无处不在。

    例子:

    const m4 = twgl.m4;
    const gl = document.querySelector('canvas').getContext('webgl', {stencil: true});
    
    const vs = `
    attribute vec4 position;
    uniform mat4 matrix;
    void main() {
      gl_Position = matrix * position;
    }
    `;
    
    const fs = `
    precision mediump float;
    uniform vec4 color;
    void main() {
      gl_FragColor = color;
    }
    `;
    
    const program = twgl.createProgram(gl, [vs, fs]);
    const posLoc = gl.getAttribLocation(program, 'position');
    const matLoc = gl.getUniformLocation(program, 'matrix');
    const colorLoc = gl.getUniformLocation(program, 'color');
    
    const buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
       0, -1,
       1,  1,
      -1,  1,
    ]), gl.STATIC_DRAW);
    
    gl.enableVertexAttribArray(posLoc);
    gl.vertexAttribPointer(
        posLoc,    // attribute location
        2,         // 2 value per vertex
        gl.FLOAT,  // 32bit floating point values
        false,     // don't normalize
        0,         // stride (0 = base on type and size)
        0,         // offset into buffer
    );
    
    // clear the stencil to 0 (the default)
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
    
    gl.useProgram(program);
    
    // turn on the stencil
    gl.enable(gl.STENCIL_TEST);
    
    // Set the stencil test so it always passes
    // and the reference to 1
    gl.stencilFunc(
       gl.ALWAYS,    // the test
       1,            // reference value
       0xFF,         // mask
    );
    // Set it so we replace with the reference value (1)
    gl.stencilOp(
       gl.KEEP,     // what to do if the stencil test fails
       gl.KEEP,     // what to do if the depth test fails
       gl.REPLACE,  // what to do if both tests pass
    );
    
    // draw a white small triangle
    gl.uniform4fv(colorLoc, [1, 1, 1, 1]); // white
    gl.uniformMatrix4fv(matLoc, false, m4.scaling([0.2, 0.2, 1]));
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    
    
    // Set the test that the stencil must = 0
    gl.stencilFunc(
       gl.EQUAL,     // the test
       0,            // reference value
       0xFF,         // mask
    );
    // don't change the stencil buffer on draw
    gl.stencilOp(
       gl.KEEP,     // what to do if the stencil test fails
       gl.KEEP,     // what to do if the depth test fails
       gl.KEEP,  // what to do if both tests pass
    );
    
    // draw a large green triangle
    gl.uniform4fv(colorLoc, [0, 1, 0, 1]); // green
    gl.uniformMatrix4fv(matLoc, false, m4.scaling([0.9, -0.9, 1]));
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    canvas { border: 1px solid black; }
    <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
    <canvas></canvas>

    【讨论】:

    • 非常感谢!这是非常有价值的信息。感谢您的 cmets,我了解了如何使用模板缓冲区。
    猜你喜欢
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多