javascript - WebGL:在带有深度模板纹理附件的帧缓冲区上未清除颜色

标签 javascript webgl framebuffer

我尝试在启用模板的情况下绘制对象,一切正常。下面是我预期的工作结果的动画帧图片(从左到右)。 expected result

当我使用帧缓冲区时出现问题。据我了解,WebGL 1.0 不支持将模板与深度分开,既不支持渲染缓冲区也不支持纹理。可以通过 WEBGL_depth_texture 扩展将模板和深度附加在一起来完成。我正在使用该扩展并使用帧缓冲区,绘制对象,但结果颜色似乎不清晰。下面是结果的动画帧图片。

enter image description here

谁能解释一下这是怎么回事?

请浏览下面的完整代码。

(function() {
var gl;
var dtExt;

var gProgram;
var gRectShader;

var gVertexAttribLocation;
var gColorAttribLocation;

var gRectVertexAttribLocation;
var gRectTexcoordAttribLocation;

var gModelViewMatrixUniform;

var gTriangleVertexBuffer;
var gTriangleColorBuffer;
var gQuadVertexBuffer;
var gQuadColorBuffer;
var gQuadTexcoordBuffer;

var gFramebuffer;

var gColorTexture;
var gDepthStencilTexture;

var rotationMatrix = mat4.create();

function initGL() {
	var glcanvas = document.getElementById("glcanvas");
	gl = glcanvas.getContext("webgl", {stencil:true});
	dtExt = gl.getExtension('WEBGL_depth_texture') || gl.getExtension('WEBKIT_WEBGL_depth_texture') || gl.getExtension('MOZ_WEBGL_depth_texture');
}

function initFramebuffers() {
	gFramebuffer = gl.createFramebuffer();

	gl.bindFramebuffer(gl.FRAMEBUFFER, gFramebuffer);

	gl.bindTexture(gl.TEXTURE_2D, gColorTexture);
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, gColorTexture, 0);

	gl.bindTexture(gl.TEXTURE_2D, gDepthStencilTexture);
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, gDepthStencilTexture, 0);

	gl.bindTexture(gl.TEXTURE_2D, null);
	gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}

function createTexture() {
	var texture = gl.createTexture();

	gl.bindTexture(gl.TEXTURE_2D, texture);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	gl.bindTexture(gl.TEXTURE_2D, null);

	return texture;
}

function initTextures() {
	gColorTexture = createTexture();
	gl.bindTexture(gl.TEXTURE_2D, gColorTexture);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

	gDepthStencilTexture = createTexture();
	gl.bindTexture(gl.TEXTURE_2D, gDepthStencilTexture);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_STENCIL, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.DEPTH_STENCIL, dtExt.UNSIGNED_INT_24_8_WEBGL, null);
	
	gl.bindTexture(gl.TEXTURE_2D, null);
}

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;",

		"uniform mat4 u_modelViewMatrix;",

		"varying vec4 v_color;",

		"void main(void) {",
			"v_color = a_color;",
			"gl_Position = u_modelViewMatrix * 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);

	var gVertexShader = createAndCompileShader(gl.VERTEX_SHADER, [
		"attribute vec3 a_vertex;",
		"attribute vec2 a_texcoord;",

		"varying vec2 v_texcoord;",

		"void main(void) {",
			"v_texcoord = a_texcoord;",
			"gl_Position = vec4(a_vertex, 1.0);",
		"}"
	].join("\n"));

	var gFragmentShader = createAndCompileShader(gl.FRAGMENT_SHADER, [
		"precision mediump float;",

	    "uniform sampler2D u_sampler0;",

		"varying vec2 v_texcoord;",
		"void main(void) {",
			"gl_FragColor = texture2D(u_sampler0, v_texcoord);",
		"}"
	].join("\n"));

	gRectShader = createAndLinkProgram(gVertexShader, gFragmentShader);
}

function initAttribAndUniformLocations() {
	gVertexAttribLocation = gl.getAttribLocation(gProgram, "a_vertex");
	gColorAttribLocation = gl.getAttribLocation(gProgram, "a_color");
	gModelViewMatrixUniform = gl.getUniformLocation(gProgram, 'u_modelViewMatrix');

	gRectVertexAttribLocation = gl.getAttribLocation(gRectShader, "a_vertex");
	gRectTexcoordAttribLocation = gl.getAttribLocation(gRectShader, "a_texcoord");
}

function initBuffers() {
	gTriangleVertexBuffer = gl.createBuffer();
	gTriangleColorBuffer = gl.createBuffer();
	gQuadVertexBuffer = gl.createBuffer();
	gQuadColorBuffer = gl.createBuffer();
	gQuadTexcoordBuffer = 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
	]);
	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);

	gl.bindBuffer(gl.ARRAY_BUFFER, gQuadTexcoordBuffer);
	var texcoords = new Float32Array([
	     0.0, 1.0,
	     0.0, 0.0,
	     1.0, 1.0,
	     1.0, 0.0
	]);
	gl.bufferData(gl.ARRAY_BUFFER, texcoords, 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 drawRectQuads() {
	gl.bindBuffer(gl.ARRAY_BUFFER, gQuadVertexBuffer);
	gl.vertexAttribPointer(gRectVertexAttribLocation, 3, gl.FLOAT, false, 0, 0);

	gl.bindBuffer(gl.ARRAY_BUFFER, gQuadTexcoordBuffer);
	gl.vertexAttribPointer(gRectTexcoordAttribLocation, 2, 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() {
	var mvMatrix = mat4.create();

	gl.clearColor(0.5, 0.5, 0.5, 1.0);

	gl.bindFramebuffer(gl.FRAMEBUFFER, gFramebuffer);
	gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

	gl.enable(gl.STENCIL_TEST);
	gl.enable(gl.DEPTH_TEST);
	gl.enable(gl.CULL_FACE);

	gl.clear(gl.STENCIL_BUFFER_BIT);

	gl.useProgram(gProgram);

	gl.enableVertexAttribArray(gVertexAttribLocation);
	gl.enableVertexAttribArray(gColorAttribLocation);

	gl.disable(gl.DEPTH_TEST);
	gl.colorMask(false, false, false, false);

	gl.stencilFunc(gl.ALWAYS, 0, 0xff);
	gl.stencilMask(0xff);
	gl.stencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.INCR);
	gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.DECR);

	mat4.identity(mvMatrix);
	mat4.scale(mvMatrix, mvMatrix, [0.5, 0.5, 0.5]);
	mat4.multiply(mvMatrix, mvMatrix, rotationMatrix);

	gl.uniformMatrix4fv(gModelViewMatrixUniform, false, mvMatrix);

	gl.cullFace(gl.FRONT);
	drawTriagles();

	gl.cullFace(gl.BACK);
	drawTriagles();

	gl.stencilMask(0x00);
	gl.stencilFunc(gl.NOTEQUAL, 0, 0xff);

	gl.enable(gl.DEPTH_TEST);
	gl.colorMask(true, true, true, true);

	mat4.identity(mvMatrix);
	mat4.scale(mvMatrix, mvMatrix, [0.75, 0.75, 0.75]);

	gl.uniformMatrix4fv(gModelViewMatrixUniform, false, mvMatrix);

	drawQuads();

	gl.disableVertexAttribArray(gVertexAttribLocation);
	gl.disableVertexAttribArray(gColorAttribLocation);

	gl.flush();

	gl.disable(gl.STENCIL_TEST);

	gl.bindFramebuffer(gl.FRAMEBUFFER, null);
	gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

	gl.enable(gl.DEPTH_TEST);

	gl.bindTexture(gl.TEXTURE_2D, gColorTexture);

	gl.useProgram(gRectShader);

	gl.enableVertexAttribArray(gRectVertexAttribLocation);
	gl.enableVertexAttribArray(gRectTexcoordAttribLocation);

	drawRectQuads();

	gl.disableVertexAttribArray(gRectVertexAttribLocation);
	gl.disableVertexAttribArray(gRectTexcoordAttribLocation);

	gl.flush();
}

function step(timestamp) {
	renderScene();

	mat4.rotate(rotationMatrix, rotationMatrix, Math.PI / 360, [0, 0, 1])

    window.requestAnimationFrame(step);
}

initGL();
initShaderPrograms();
initAttribAndUniformLocations();
initTextures();
initFramebuffers();
initBuffers();
window.requestAnimationFrame(step);

}());
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.4.0/gl-matrix-min.js"></script>

<canvas id="glcanvas" width="480" height="360">
		WebGL not supported!
</canvas>

最佳答案

在清除模板缓冲区之前需要设置模板掩码

gl.stencilMask(0xff);

此外,您不需要 WEBGL_depth_texture 来为帧缓冲区制作深度+模板附件。您可以使用 DEPTH_STENCIL 渲染缓冲区

const rb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb);

还有 multiline template literals可能会为您节省很多时间。

此外,gl.flush 在代码中没有任何意义。

关于javascript - WebGL:在带有深度模板纹理附件的帧缓冲区上未清除颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46827829/

相关文章:

javascript - 关于 DOM manip 和 GreaseMonkey 的一点帮助

javascript - 如何使用 anchor 标签中的图像作为输入?

javascript - 无法插入将 $scope 变量传递到 Angular 过滤器时出现的错误

opengl - 如何将纹理附加到帧缓冲区?

objective-c - Paint 应用程序,使用帧缓冲区在 OpenGL ES 中渲染纹理

javascript - LocalStorage 只能在 1 页中工作?

javascript - Ashima Perlin 噪声着色器不适用于最新版本的 Three.JS

webgl - 使用矩阵转换 Three.js 场景图

javascript - 在 Three.js 中访问立方体一个面上的所有顶点

linux - 树莓派 : Does the framebuffer image viewer (FBI) display gifs?