OpenGL ES:模板缓冲区和剔除

OpenGL ES: Stencilbuffers and culling

我是 OpenGL 的新手,我正在尝试一些实验,尤其是模板缓冲区。 在我的代码中,我使用 glStencilFuncSeparate 分别将前模板缓冲区和后模板缓冲区分别设置为 0x5 和 0xC(GL_ALWAYS 作为函数的参数)。 glStencilOpSeparate 为 dppass 的前后状态设置为 GL_REPLACE。我还确保在设置两个模板缓冲区时禁用深度和剔除。

接下来我尝试渲染一个启用了深度、前端剔除和模板测试的立方体。我现在使用 glStencilFuncSeparate() 通过与 0x12 进行比较来仅绘制背面模板设置区域。由于正面被剔除,我希望只显示值为 0x12 的后模板缓冲区覆盖的区域。

但令我沮丧的是,它显示黑屏。当它给出的比较值为 0x5(front stencil init val),剔除面为前面时,我能够看到立方体的部分。

所以这似乎表明,当剔除设置为 GL_FRONT 时,将立方体的背面与正面模板进行比较。所有其他参数,如 StencilClear(值 0x1)看起来都正确,但我无法理解这种行为。

设置模板

glStencilMaskSeparate(GL_FRONT_AND_BACK, 0xff)
glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0x5, 0xff)
glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0xc, 0xff)
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_REPLACE)
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
glDepthMask(GL_FALSE)
glDrawArrays(GL_TRIANGLES, 0, 6)

启用剔除

glCullFace(GL_FRONT)
glEnable(GL_CULL_FACE)

画一个立方体

glStencilOpSeparate(GL_FRONT,GL_KEEP,GL_KEEP,GL_REPLACE)
glStencilOpSeparate(GL_BACK,GL_KEEP,GL_KEEP,GL_REPLACE)
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
glDepthMask(GL_FALSE)
glDrawArrays(GL_TRIANGLES, 0, 36)

OpenGL 版本:OpenGL ES 3.1 Mesa 19.0.8,Mesa DRI Intel Haswell Desktop

有人能帮我理解为什么前面和后面的模板缓冲区似乎与剔除模式互换了吗?

听起来您认为有两种不同的模板缓冲区,一种用于正面,一种用于背面。这是不正确的;每个像素只有一个模板缓冲区和一个模板值。

glSeparate...() 函数只是为您提供了为正面和背面三角形指定单独的模板 test/update 规则的方法,但它们将写入帧缓冲区中的相同存储位置。

假设您有一个正面最靠近相机的立方体,那么 "surviving" 第一次通过后的模板值将始终是正面参考值。

更新: 请注意,您可以 "mix" 同一模板缓冲区中的前后模板值,方法是使用 glStencilMaskSeparate() 控制可以写入哪些位, 和 glStencilFuncSeparate() 来控制在模板测试时使用哪些位。