模板缓冲区和掩码如何工作?
How stencil buffer and masking work?
我只想在特定区域绘制对象。请看看这张图片以供参考
2 个三角形(图片 A)仅绘制在四边形(图片 B)内部的区域中,因此结果看起来会被剪裁(图片 C)。
首先我在模板缓冲区中绘制四边形。
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilMask(0xff);
gl.depthMask(false);
gl.colorMask(false, false, false, false);
drawQuads();
据我了解,现在模板缓冲区在四边形区域中的值为 1s。然后画三角形。
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilMask(0x00);
gl.depthMask(true);
gl.colorMask(true, true, true, true);
drawTriagles();
我以为结果会像图(C) 那样,结果不是。我做错了什么?
请在此处找到完整代码https://jsfiddle.net/z11zhf01/1
您的程序绝对正确,但您必须在创建上下文时告诉 getContext
函数创建模板缓冲区:
gl = glcanvas.getContext("webgl", {stencil:true});
见Khronos WebGL Specification - WebGLContextAttributes:
stencil
If the value is true
, the drawing buffer has a stencil buffer of at least 8 bits. If the value is false, no stencil buffer is available.
参见示例:
(function() {
var gl;
var gProgram;
var gVertexAttribLocation;
var gColorAttribLocation;
var gTriangleVertexBuffer;
var gTriangleColorBuffer;
var gQuadVertexBuffer;
var gQuadColorBuffer;
function initGL() {
var glcanvas = document.getElementById("glcanvas");
gl = glcanvas.getContext("webgl", {stencil:true});
}
function createAndCompileShader(type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader));
}
return shader;
}
function createAndLinkProgram(glVertexShader, glFragmentShader) {
var glProgram = gl.createProgram();
gl.attachShader(glProgram, glVertexShader);
gl.attachShader(glProgram, glFragmentShader);
gl.linkProgram(glProgram);
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
throw new Error("Could not initialise shaders");
}
return glProgram;
}
function initShaderPrograms() {
var gVertexShader = createAndCompileShader(gl.VERTEX_SHADER, [
"attribute vec3 a_vertex;",
"attribute vec4 a_color;",
"varying vec4 v_color;",
"void main(void) {",
"v_color = a_color;",
"gl_Position = vec4(a_vertex, 1.0);",
"}"
].join("\n"));
var gFragmentShader = createAndCompileShader(gl.FRAGMENT_SHADER, [
"precision mediump float;",
"varying vec4 v_color;",
"void main(void) {",
"gl_FragColor = v_color;",
"}"
].join("\n"));
gProgram = createAndLinkProgram(gVertexShader, gFragmentShader);
}
function initGLAttribLocations() {
gVertexAttribLocation = gl.getAttribLocation(gProgram, "a_vertex");
gColorAttribLocation = gl.getAttribLocation(gProgram, "a_color");
}
function initBuffers() {
gTriangleVertexBuffer = gl.createBuffer();
gTriangleColorBuffer = gl.createBuffer();
gQuadVertexBuffer = gl.createBuffer();
gQuadColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleVertexBuffer);
var vertices = new Float32Array([
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
0.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, 1.0, 0.0
]);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleColorBuffer);
var colors = new Float32Array([
0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0
]);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadVertexBuffer);
var vertices = new Float32Array([
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
1.0, -1.0, 0.0
]);
for(let i = 0, ii = vertices.length; i < ii; ++i) {
vertices[i] *= 0.75;
}
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadColorBuffer);
var colors = new Float32Array([
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
]);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
}
function drawQuads() {
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadVertexBuffer);
gl.vertexAttribPointer(gVertexAttribLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadColorBuffer);
gl.vertexAttribPointer(gColorAttribLocation, 4, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function drawTriagles() {
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleVertexBuffer);
gl.vertexAttribPointer(gVertexAttribLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleColorBuffer);
gl.vertexAttribPointer(gColorAttribLocation, 4, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function renderScene() {
gl.enable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
// gl.enable(gl.CULL_FACE);
gl.useProgram(gProgram);
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.enableVertexAttribArray(gVertexAttribLocation);
gl.enableVertexAttribArray(gColorAttribLocation);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilMask(0xff);
gl.depthMask(false);
gl.colorMask(false, false, false, false);
drawQuads();
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilMask(0x00);
gl.depthMask(true);
gl.colorMask(true, true, true, true);
drawTriagles();
gl.disableVertexAttribArray(gVertexAttribLocation);
gl.disableVertexAttribArray(gColorAttribLocation);
gl.flush();
}
initGL();
initShaderPrograms();
initGLAttribLocations();
initBuffers();
renderScene();
}());
<main>
<canvas id="glcanvas" width="480" height="360">
WebGL not supported!
</canvas>
</main>
我只想在特定区域绘制对象。请看看这张图片以供参考
2 个三角形(图片 A)仅绘制在四边形(图片 B)内部的区域中,因此结果看起来会被剪裁(图片 C)。
首先我在模板缓冲区中绘制四边形。
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilMask(0xff);
gl.depthMask(false);
gl.colorMask(false, false, false, false);
drawQuads();
据我了解,现在模板缓冲区在四边形区域中的值为 1s。然后画三角形。
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilMask(0x00);
gl.depthMask(true);
gl.colorMask(true, true, true, true);
drawTriagles();
我以为结果会像图(C) 那样,结果不是。我做错了什么?
请在此处找到完整代码https://jsfiddle.net/z11zhf01/1
您的程序绝对正确,但您必须在创建上下文时告诉 getContext
函数创建模板缓冲区:
gl = glcanvas.getContext("webgl", {stencil:true});
见Khronos WebGL Specification - WebGLContextAttributes:
stencil
If the value istrue
, the drawing buffer has a stencil buffer of at least 8 bits. If the value is false, no stencil buffer is available.
参见示例:
(function() {
var gl;
var gProgram;
var gVertexAttribLocation;
var gColorAttribLocation;
var gTriangleVertexBuffer;
var gTriangleColorBuffer;
var gQuadVertexBuffer;
var gQuadColorBuffer;
function initGL() {
var glcanvas = document.getElementById("glcanvas");
gl = glcanvas.getContext("webgl", {stencil:true});
}
function createAndCompileShader(type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader));
}
return shader;
}
function createAndLinkProgram(glVertexShader, glFragmentShader) {
var glProgram = gl.createProgram();
gl.attachShader(glProgram, glVertexShader);
gl.attachShader(glProgram, glFragmentShader);
gl.linkProgram(glProgram);
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
throw new Error("Could not initialise shaders");
}
return glProgram;
}
function initShaderPrograms() {
var gVertexShader = createAndCompileShader(gl.VERTEX_SHADER, [
"attribute vec3 a_vertex;",
"attribute vec4 a_color;",
"varying vec4 v_color;",
"void main(void) {",
"v_color = a_color;",
"gl_Position = vec4(a_vertex, 1.0);",
"}"
].join("\n"));
var gFragmentShader = createAndCompileShader(gl.FRAGMENT_SHADER, [
"precision mediump float;",
"varying vec4 v_color;",
"void main(void) {",
"gl_FragColor = v_color;",
"}"
].join("\n"));
gProgram = createAndLinkProgram(gVertexShader, gFragmentShader);
}
function initGLAttribLocations() {
gVertexAttribLocation = gl.getAttribLocation(gProgram, "a_vertex");
gColorAttribLocation = gl.getAttribLocation(gProgram, "a_color");
}
function initBuffers() {
gTriangleVertexBuffer = gl.createBuffer();
gTriangleColorBuffer = gl.createBuffer();
gQuadVertexBuffer = gl.createBuffer();
gQuadColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleVertexBuffer);
var vertices = new Float32Array([
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
0.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, 1.0, 0.0
]);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleColorBuffer);
var colors = new Float32Array([
0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0
]);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadVertexBuffer);
var vertices = new Float32Array([
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
1.0, -1.0, 0.0
]);
for(let i = 0, ii = vertices.length; i < ii; ++i) {
vertices[i] *= 0.75;
}
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadColorBuffer);
var colors = new Float32Array([
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
]);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
}
function drawQuads() {
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadVertexBuffer);
gl.vertexAttribPointer(gVertexAttribLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, gQuadColorBuffer);
gl.vertexAttribPointer(gColorAttribLocation, 4, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function drawTriagles() {
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleVertexBuffer);
gl.vertexAttribPointer(gVertexAttribLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, gTriangleColorBuffer);
gl.vertexAttribPointer(gColorAttribLocation, 4, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function renderScene() {
gl.enable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
// gl.enable(gl.CULL_FACE);
gl.useProgram(gProgram);
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.enableVertexAttribArray(gVertexAttribLocation);
gl.enableVertexAttribArray(gColorAttribLocation);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilMask(0xff);
gl.depthMask(false);
gl.colorMask(false, false, false, false);
drawQuads();
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilMask(0x00);
gl.depthMask(true);
gl.colorMask(true, true, true, true);
drawTriagles();
gl.disableVertexAttribArray(gVertexAttribLocation);
gl.disableVertexAttribArray(gColorAttribLocation);
gl.flush();
}
initGL();
initShaderPrograms();
initGLAttribLocations();
initBuffers();
renderScene();
}());
<main>
<canvas id="glcanvas" width="480" height="360">
WebGL not supported!
</canvas>
</main>