WebGL中的模板缓冲区 [英] Stencil buffer in WebGL

查看:403
本文介绍了WebGL中的模板缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何为我最简单的程序使用模板缓冲? 我已经阅读了许多不同的主题,但是没有找到详细的指南. 我想在创建的四面体的每一侧切出孔.

How I can use to stencil buffer for my easiest program? I have read many different themes about it, but I not found a detailed guide about it. I want to cut out for hole each side in a created tetrahedron.

请逐步向我说明使用模板缓冲区吗?

Please explain to me step by step use stencil buffer?

我的程序链接

推荐答案

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

To use the stencil buffer you have to first request it when you create the webgl context

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

然后打开模板测试

  gl.enable(gl.STENCIL_TEST);

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

Set up the test so it always passes and set the reference value to 1

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

并设置操作,以便在模板和深度测试均通过时将模板设置为参考值

And set the operation so we'll set the stencil to the reference value when both the stencil and depth tests pass

  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
  );

然后绘制第一个内部三角形

We then draw the first inner triangle

... lots of setup for a single triangle ...

gl.drawArrays(...) or gl.drawElements(...)

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

Then we change the test so it only passes if the stencil is zero

  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的位置.

and now we can draw something else (the larger triangle) and it will only draw where there is 0 in the stencil buffer which is everywhere except where the first triangle was drawn.

示例:

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>

这篇关于WebGL中的模板缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆