模板缓冲区和掩码如何工作?

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>