【问题标题】:Masking with glBlendFunc, without frame buffers使用 glBlendFunc 进行屏蔽,没有帧缓冲区
【发布时间】:2014-03-19 19:43:18
【问题描述】:

我希望这可以在不使用帧缓冲区或着色器的情况下实现,只需直接使用 glBlendFunc 或 glBlendFuncSeparate。

我正在使用标准混合模式正常渲染场景:

glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

在那个场景的顶部,我想绘制一个被其他纹理掩盖的纹理。这些是在任意位置绘制的(不一定是矩形,不一定是相同的大小/位置)。

顺序是;渲染蒙版纹理,然后渲染蒙版纹理。

蒙版的纹理是带有 alpha 的常规图像。

遮罩纹理可以是黑色 RGBA(0, 0, 0, 255),也可以是透明 RGBA(0, 0, 0, 0)

我希望任何黑色不接触的东西都看不见。基本上,最终的结果应该是:

RGBA(masked.r, masked.g, masked.b, masked.a * mask.a)

以下是订购图片,以解释我的意思。我真的在寻找一种解决方案,以避免不得不使用不同的着色器或将东西粘贴到帧缓冲区上。如果绝对不可能,请告诉我。

【问题讨论】:

  • 您考虑过使用模板缓冲区吗?
  • 如果我必须先绘制蒙版纹理,这可能吗?我以为我必须创建模板,为其绘制蒙版,然后将蒙版纹理绘制到屏幕上,然后关闭模板?
  • 使用模板缓冲区,你应该可以写掩码只绘制到模板缓冲区,清除模板缓冲区,绘制你想要修改像素的正方形,然后设置模板函数仅在模板缓冲区具有您在绘制方形区域时设置的值的位置绘制。然后,取消屏蔽颜色/深度缓冲区,屏蔽写入模板缓冲区,绘制纹理,然后禁用模板测试。听起来比实际复杂,而且比混合模式掩蔽要简单。
  • 有道理,我已经阅读了一些内容,我认为这正是我所追求的。我已经尝试过了,但它并没有达到我想要的效果。你知道一个像样的教程或指南吗?我尝试按照我在此处找到的示例进行操作; research.ncl.ac.uk/game/mastersdegree/graphicsforgames/…
  • 这是一个近乎完美的例子(据我所知)你想要做什么:en.wikibooks.org/wiki/OpenGL_Programming/Stencil_buffer#Sample 是的,它使用圆形而不是纹理,但所有代码都只相关到模板上。

标签: opengl-es opengl-es-2.0


【解决方案1】:

我会解释为什么这是不可能的。混合蒙版需要三遍,因为它包含三个部分:目标、源和蒙版。无论您做什么,都必须将源和掩码混合到帧缓冲区中,然后渲染到目标。

然而,模板缓冲区是内置在默认窗口帧缓冲区中的,只要您告诉 OpenGL 提供它(就像您提供深度缓冲区一样),并且看起来完全符合您的要求。作为 GLUT 调用,在双缓冲窗口中初始化窗口中的模板缓冲区以及启用 alpha 的颜色和深度缓冲区看起来像这样:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL);

模板缓冲区能够完全满足您的需求 - 您可以在其中绘制一个形状,并有选择地告诉它丢弃或保留该形状内的像素。这是一个如何使用它的示例,从 OpenGL 红皮书修改:

GLdouble dRadius = 0.1; // Initial radius of spiral
GLdouble dAngle;        // Looping variable

// Use 0 for clear stencil, enable stencil test
glClearStencil(0);
glEnable(GL_STENCIL_TEST);

// Clear stencil buffer
glClear(GL_STENCIL_BUFFER_BIT);

// All drawing commands fail the stencil test, and are not
// drawn, but increment the value in the stencil buffer.
// glStencilFunc takes three arguments: the stencil function, the reference value, and the mask value. Whenever the stencil function is tested (for example GL_LESS), both the reference and the stencil value being tested from the buffer is bitwise ANDed with the mask: GL_LESS returns true if (ref & mask) < (stencil & mask).
glStencilFunc(GL_NEVER, 0x0, 0x0);
// glStencilOp takes three arguments: the stencil operation to call when the stencil test fails, the stencil operation to call when the stencil test passes but the depth test fails, and the stenciloperation to call when the stencil test passes AND the depth test passes (or depth test is disabled or no depth buffer is allocated).
glStencilOp(GL_INCR, GL_INCR, GL_INCR);

// Spiral pattern will create stencil pattern
// Draw the spiral pattern with white lines. We
// make the lines  white to demonstrate that the
// stencil function prevents them from being drawn
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINE_STRIP);
    for(dAngle = 0; dAngle < 400.0; dAngle += 0.1)
        {
        glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle));
        dRadius *= 1.002;
        }
glEnd();

// Now, allow drawing, except where the stencil pattern is 0x1
// and do not make any further changes to the stencil buffer
glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

// Now draw red square
glColor3f(0.0f, 1.0f, 0.0f);
glRectf(0, 0, 200, 200);

此绘图代码的输出是一个红色正方形,上面有一个螺旋线,从 (1, 1) 开始。螺旋由丢弃的像素组成,因此将与清除的颜色缓冲区具有相同的颜色。如果您要将此代码用于您的目的,您将在您希望纹理成为螺旋代码的位置绘制正方形,然后使用 GL_EQUAL 作为模板函数,在绘制红色正方形的位置绘制蒙版纹理。有关模板缓冲区的更多信息,请参阅here

【讨论】:

    猜你喜欢
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多