WebGL 中的模板缓冲区
Stencil buffer in WebGL
如何为最简单的程序使用模版缓冲区?
我已经阅读了许多关于它的不同主题,但我没有找到关于它的详细指南。
我想在创建的四面体的每一侧切出孔。
请逐步向我解释使用模板缓冲区?
要使用模板缓冲区,您必须在创建 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>
如何为最简单的程序使用模版缓冲区? 我已经阅读了许多关于它的不同主题,但我没有找到关于它的详细指南。 我想在创建的四面体的每一侧切出孔。
请逐步向我解释使用模板缓冲区?
要使用模板缓冲区,您必须在创建 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>