8

我想在特定区域绘制对象。请看一下这张图片以供参考
图片

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

4

1 回答 1

12

您的程序绝对可以正常工作,但是您必须在创建上下文时告诉该getContext函数创建模板缓冲区:

gl = glcanvas.getContext("webgl", {stencil:true});

请参阅Khronos WebGL 规范 - WebGLContextAttributes

stencil
如果值为true,则绘图缓冲区具有至少 8 位的模板缓冲区。如果值为 false,则没有模板缓冲区可用。

请参阅示例:

(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>

于 2017-10-18T09:01:05.667 回答