我很难理解为什么在下面的代码中,模板测试在我直接渲染到屏幕时按预期工作,而在我尝试使用帧缓冲区时却没有。使用这些帧缓冲区对纹理进行多 channel 后处理没有问题,所以我怀疑我的深度和模板缓冲区有问题。
首先我初始化上下文:
gl = canvas.getContext("webgl",{stencil:true});
然后
function initFBO()
{
for (var i = 0; i < shaderPrograms.length; i++)
{
var texture = createTexture(imgWidth,imgHeight);
textures.push(texture);
var fbo = gl.createFramebuffer();
framebuffers.push(fbo);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
var renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, imgWidth, imgHeight);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
}
}
function drawScene()
{
gl.enable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
if(!useFBO)
{
computeProgFBO(9,null,imgHeight,imgHeight,textureId,null,null,false);
computeProgFBO(8,null,imgHeight,imgHeight,textureId,null,null,false);
}else{
computeProgFBO(9,framebuffers[0],imgHeight,imgHeight,textureId,null,null,false);
computeProgFBO(8,null,imgHeight,imgHeight,textures[0],null,null,false);
}
// Restore the original matrix
mvPopMatrix();
gl.disable(gl.STENCIL_TEST);
gl.disable(gl.DEPTH_TEST);
}
function computeProgFBO(progId,fboId,w,h,textureId0,textureId1,textureId2,flip)
{
currentProgram=shaderPrograms[progId];
gl.useProgram(currentProgram);
if(progId==9)
{
transform(w,h,0.0);
gl.stencilMask(1);
gl.stencilFunc(gl.ALWAYS,1,0);
gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
gl.colorMask(true, true, true, true);
gl.depthMask(false);
setMatrixUniformsView();
}else{
gl.colorMask(true, true, true, true);
gl.depthMask(true);
gl.stencilFunc(gl.EQUAL,0,1);
gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
setMatrixUniforms();
}
setMyUniforms(progId,flip);
setMyTexture(textureId0, textureId1,textureId2);
gl.activeTexture(gl.TEXTURE1);
gl.bindFramebuffer(gl.FRAMEBUFFER, fboId);
//the below is commented out for now as i'm only testing the stencil buffer for now
// gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures[progId], 0);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D , null);
}
我认为展示不同的制服和纹理函数没有任何意义,但请不要让我知道其他情况。顺便说一句,progId 9 绘制了一个小的绿色方 block ,而 progId 8 在它上面绘制了一个更大的红色方 block 。所以,当我直接渲染到屏幕上时,我希望看到一个被一些红色边缘包围的绿色方 block ,正如它目前所显示的那样。
*****除了第一个答案,我还修改了以下内容 *****
if(!useFBO)
{
computeProgFBO(9,null,imgHeight,imgHeight,textureId,null,null,false,null);
computeProgFBO(8,null,imgHeight,imgHeight,textureId,null,null,false,null);
computeProgFBO(6,null,imgHeight,imgHeight,textureId,null,null,false,null);
}else{
computeProgFBO(9,framebuffers[0],imgHeight,imgHeight,textureId,null,null,false,null);
computeProgFBO(8,framebuffers[1],imgHeight,imgHeight,textures[0],null,null,false,renderbuffers[0]);
computeProgFBO(6,null,imgHeight,imgHeight,textures[1],null,null,false,null);
}
并且我已经将函数参数更改为
computeProgFBO(progId,fboId,w,h,textureId0,textureId1,textureId2,flip,render)
在下面的评论之后
//the below is commented out for now as i'm only testing the stencil buffer for now
// gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures[progId], 0);
我已经添加了
if(render!=null)
{
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, render);
}
结果稍微好一些,但还不完全符合我的预期,即:我得到了大红色方 block ,而不是里面有小绿色方 block ,我得到了一个白色方 block 。我觉得这是微不足道的事情,但现在还不能真正解决。直接渲染到屏幕上仍然可以正常工作。
***** 我添加了其他人的评论******
我想我理解这个问题并找到了解决方法 [不是很优雅]。基本上,第一遍使用模板写入帧缓冲区[0]的纹理[0],第二遍使用帧缓冲区[0]的渲染缓冲区[0]而不是纹理[0]写入帧缓冲区[1]的纹理[1] ].因此,我最终得到了一个被红色包围的白色 [而不是绿色] 小方 block 。因为,我不能 blit,我意识到我可以按照下面的方式在第一遍中绘制两次:
....
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
if(progId==9)
{
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffers[1]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
}
这有效但看起来很丑!还有其他办法吗?
在将最终纹理渲染到屏幕时,似乎我不需要做太多事情,即:我只将颜色缓冲区(而不是模板和深度缓冲区)和所有最终纹理发送到屏幕按预期显示。
此外,请注意我的片段着色器仅执行以下操作
shader9: gl_FragColor = vec4(0.0,1.0,0.0,1.0);
shader8: gl_FragColor = vec4(1.0,vec2(0.0),1.0);
shader6: gl_FragColor = texture2D(u_Texture0,vTextureCoord);
最佳答案
您不能在 webgl 中复制缓冲区的内容,但您可以通过调用 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer); 在多个 FBOS 之间共享深度模板缓冲区;
在同一个渲染缓冲区上。
如果要在启用模板测试的情况下渲染到默认帧缓冲区,则必须首先渲染到具有所需模板渲染缓冲区附件的 FBO。然后使用该 FBO 的颜色纹理绘制到默认帧缓冲区。
关于opengl - 如何将模板从帧缓冲区传递到另一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32119140/