【问题标题】:OpenGL Alpha MaskOpenGL Alpha 蒙版
【发布时间】:2014-09-11 13:37:26
【问题描述】:

我正在尝试将 alhpa 掩码与 glAlphaBlend 和他的所有参数一起使用。我在 stackoverflow 上找到了很多类似的答案,但我什么都没意识到。

我有三个图像,一个背景 (1)、一个蒙版 (2) 和文本 (3)。

我想要的是绘制背景,将我的蒙版减去文本以最终获得图像(A)。

Draw background

glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glBegin(GL_QUADS);
glColor4ub(0,0,0,255);
glVertex2d(mxIncrust0 - bgwidth, myIncrust0);
glVertex2d(mxIncrust0, myIncrust0);
glVertex2d(mxIncrust0, myIncrust0 + textheight);
glVertex2d(mxIncrust0 - bgwidth, myIncrust0 + textheight);
glEnd();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ZERO, GL_ONE);

Draw Text

但一切正常!

实现它的真正方法是什么?

我的问题不同,因为它不是基于 OpenGL ES,而是仅基于 Open GL。

【问题讨论】:

  • But Anything is working ! 这到底意味着什么?你有什么结果? SO 上没有媒介。
  • 我明白,我想说我尝试了堆栈上的每个答案,但一切都在做正确的事情!
  • 然后告诉我们你有什么。另请注意,没有“画面具”之类的东西。唯一吸引人的是Draw* 调用。你不需要画面具。掩码将在输出合并阶段与您的文本纹理相结合(GL 俚语中的“每个样本操作”)。在您向我们展示绘图代码和生成的屏幕截图之前,我只能建议您看一下 opengl 文档:Rendering Pipeline Overview
  • 如果我不粘贴这段代码,那只是因为它没有帮助。
  • 你想要的输出可以很容易地在着色器中完成。您将首先渲染背景。然后启用混合并附加蒙版纹理和文本纹理,并将文本纹理的 alpha 乘以蒙版值。

标签: opengl mask alpha freetype


【解决方案1】:

实现这一点的“真正方法”是使用 shader programsmodern OpenGL 。为什么要使用已弃用的 API?我们在 2014 年使用 OpenGL 4.5 作为最新版本。你甚至不能声称你关心向后兼容性,因为即使是一些非常老的卡(嗯,5 岁)今天至少支持完全可编程的 GL 3.2。而且你知道,即使使用 GL 2.0,你仍然可以使用着色器,但使用已弃用的如果您打算在不久的将来为自己的生活编写 OpenGL 代码,API 将无处可去。

现在,使用着色器,遮罩是最简单的任务之一。 您通常会将 2 个纹理传递到片段着色器中。1 - 漫反射纹理(覆盖表面的实际纹理) 2 - 蒙版纹理(可能是单通道灰度纹理)

片段着色器如下所示:

#version 150
uniform sampler2D maskTex;
uniform sampler2D colorTex;

out vec4 colorOut;
in smooth vec2 texCoords;
void main(){ 

     vec4 color = texture(colorTex,texCoords);
     vec4 mask  = texture(maskTex,texCoords);

     colorOut =vec4(color.rgb,color.a * mask.r);//alpha value can be in any channel ,depends on texture format.
}

尽可能简单。希望对您有所帮助。

P.S 确保你也对 alpha 纹理进行 mipmap,以防漫反射纹理被 mipmap。 另请注意,我的示例并不是为了解决您的特定任务,而是向您展示如何在可编程 OpenGL 中完成基本遮罩。从这里很容易弄清楚该怎么做;)

附录:

下面的 cmets 中有人想知道为什么要使用额外的纹理来保存 alpha 掩码数据。这是我的答案:

在许多复杂的应用程序中,用户使用称为 alpha 贴图的附加纹理来屏蔽主纹理的像素,同时在此过程中还要考虑该纹理的 alpha,并且没有理由将 alpha 通道“合并”到一个纹理贴图中因为它需要一个额外的步骤并且浪费运行时间而没有真正的目的。在一些复杂的渲染场景中,这些 alpha 贴图只能在请求的不同渲染过程中生成,然后被提取到片段着色器中以供最终使用。因此,在这种情况下,应用程序在运行之前甚至没有这些数据。此外,许多不同颜色的纹理可能需要相同的 alpha 蒙版。那么将它合并到所有这些中是否有意义?当然不是。与在 CPU 上合并透明度数据以避免额外的纹理采样相比,上述做法是众所周知的并且非常有效。

【讨论】:

  • 非常感谢您的完整回复,我找到了使用着色器的类似示例。这似乎是可以理解的,但我的第一个问题是文本不是纹理,我用基本的 gl_quad 生成我的蒙版! PS:它并没有解决我正在寻找的方式,但它似乎首先是性能更高,其次是你说的未来更好。我会在接下来的几天里尝试一下......
  • @PurpleIce 首先,即使您不同意 SO 上的某个人,我建议您保持友善。在此示例中,我展示了 ALPHA MAP 的用法,它为已经存在的 alpha 通道提供了额外的 alpha 信息在 colorTex 中。您的评论的问题是您没有看到这种用例的全貌。请参阅上面的附录。
【解决方案2】:

我终于找到了 glClipPlane 的解决方案,我没有找到任何带有着色器的解决方案,因为它不是纹理。

那么它是如何工作的呢? 1)我画我的背景(四边形,线条......) 2)我定义并激活了一个低于任何值的限制是在左边绘制,一个高于任何值的限制是在右边绘制 3)我画出我需要的一切(四边形,线条,我的文字......) 4) 我禁用了剪辑。

// Draw the background
double* leftMask = new double[4];
leftMask[0] = 1;
leftMask[3] = -mClipXL; // Be careful to use -Limit for the left limit
glClipPlane(GL_CLIP_PLANE0, leftMask);
delete[] leftMask;
glEnable(GL_CLIP_PLANE0);

double* rightMask = new double[4];
rightMask[0] = -1;  // Be careful to use -1 for the right limit
rightMask[3] = mClipXR;
glClipPlane(GL_CLIP_PLANE1, rightMask);
delete[] rightMask;
glEnable(GL_CLIP_PLANE1);

// draw the text

// disable the clip to draw anything else.
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);

效果很好!!!

【讨论】:

    【解决方案3】:

    您也可以为此使用模板缓冲区。首先,您将启用模板测试:

    glEnable(GL_STENCIL_TEST);
    

    然后您首先仅在模板缓冲区中绘制遮罩四边形:

    //begin mask
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glStencilFunc(GL_NEVER, 0, 0);
    glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
    glClear(GL_STENCIL_BUFFER_BIT);
    //draw your mask, a quad in your case
    

    然后你绘制蒙版部分:

        ////masked fill part
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glStencilFunc(GL_NOTEQUAL, 0, 1);
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        // draw the masked element, the text in your case
    

    再次禁用模板测试

    glDisable(GL_STENCIL_TEST);
    

    根据您的需要,您可以更改 glStencilFunc() 和 glStencilOp() 参数以实现所需的剪辑效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-07
      • 2014-10-27
      相关资源
      最近更新 更多