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 s
To use the stencil buffer you have to first request it when you create the webgl context
const gl = someCanvasElement.getContext('webgl', {stencil: true});
Then you turn on the stencil test
gl.enable(gl.STENCIL_TEST);
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
);
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.
Example:
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>