检查模板位,然后写入另一位

时间:2015-05-13 07:37:00

标签: opengl bitmask stencil-buffer

我在3D引擎中渲染反射表面。我需要执行两次模板操作。首先,我通过深度测试绘制出反射表面,以找到表面的可见区域。然后我需要将模型绘制到一个G-Buffer中,它也被模板化以找到绘制我的天空盒的区域。

  • 绘制曲面:始终绘制,写入位#1

  • 绘制模型:仅在设置位#1时绘制,写入位#2

我如何使用OpenGL执行此操作?我不确定glStencilFunc ref和掩码值之间的关系,以及glDepthMask值。

1 个答案:

答案 0 :(得分:5)

文档非常具体,但如果您只是想创建然后激活蒙版,那么它并不总是直观或明显该怎么做。我用这些作为一个简单的起点...

创建遮罩

将模板缓冲区清除为零并将1写入您绘制的所有像素。

void createStencilMask()
{
    // Clear the stencil buffer with zeroes.
    // This assumes glClearStencil() is unchanged.
    glClear(GL_STENCIL_BUFFER_BIT);

    // Enable stencil raster ops
    // 1. Enables writing to the stencil buffer (glStencilOp)
    // 2. If stencil test (glStencilFunc) fails, no frags are written
    glEnable(GL_STENCIL_TEST);

    // sfail GL_KEEP - keep original value if stencil test fails
    // dpfail GL_KEEP - also keep if the stencil passes but depth test fails
    // dppass GL_REPLACE - write only if both pass and you'd normally see it
    //                     this writes the value of 'ref' to the buffer
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

    // func GL_ALWAYS - the stencil test always passes
    // ref 1 - replace with ones instead of zeroes
    // mask 1 - only operate on the first bit (don't need any more)
    // Assumes glStencilMask() is unchanged
    glStencilFunc(GL_ALWAYS, 1, 1);
}

调用上面的函数,绘制你的东西。您可以设置glDepthMaskglColorMask,这样实际上不会影响当前颜色/深度和场景,只会影响模板缓冲区。

使用蒙版

绘制

仅绘制上一步中带有1的像素。

void useStencilMask()
{
    // Enable stencil raster ops
    glEnable(GL_STENCIL_TEST);

    // Just using the test, don't need to replace anything.
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    // Only render if the current pixel stencil value is one.
    glStencilFunc(GL_EQUAL, 1, 1);
}

绘制然后在完成后将测试禁用glDisable(GL_STENCIL_TEST)

读取和写入不同的位

现在关注你的问题......

这个位有点棘手,因为两个模板测试中使用ref glStencilFunc()的{​​{1}}值作为替换值。但是,你可以用面具来解决这个问题:

  1. mask中使用glStencilFunc()在测试/阅读时忽略位。
  2. 使用glStencilMask()来阻止某些位被写入。
  3. 在您的情况下,您不需要屏蔽掉第一位,因为它已经设置好了。只需将useStencilMask()更新为glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)glStencilFunc(GL_EQUAL, 3, 1);即可。因为mask1,所以在测试中只使用第一位来表示相等性。但是,写入了整个ref 3(即0b11)。你可以使用glStencilMask(2)0b10)来阻止第一位被写入,但它已经是一位所以无关紧要。

    您还可以使用GL_INCR来设置第二位并删除第一位。或者也许用1清除,然后用GL_ZERO标记你的位。