【问题标题】:Unexpected texture blending result with mask带有蒙版的意外纹理混合结果
【发布时间】:2014-08-28 17:57:39
【问题描述】:

我正在尝试使用 GLES20 在 GLSurfaceView 中实现混合效果。

视图具有颜色(红色)背景,在其上混合了蒙版纹理和具有 Alpha 通道的图像纹理。

这是一个示例蒙版和图像:

,

预期结果:

这是一个类似的问题,到目前为止它指导了我:OpenGL - mask with multiple textures

很遗憾,我无法获得类似的结果。以下是我的 onDraw() 方法的相关部分:

// Bind default FBO and use shader program
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(program);

// Set the vertex attributes
glVertexAttribPointer(texCoordHandle, 2, GL_FLOAT, false, 0, mTexVertices);
glEnableVertexAttribArray(texCoordHandle);
glVertexAttribPointer(posCoordHandle, 2, GL_FLOAT, false, 0, mPosVertices);
glEnableVertexAttribArray(posCoordHandle);

// Clear the buffer color - draw red color background
glClear(GL_COLOR_BUFFER_BIT);

// Apply transformation - irrelevant
glUniformMatrix4fv(mvpMatrixHandle, 1, false, matrix, 0);

// Bind the mask texture for drawing
glUniform1i(contentTextureHandle, 0);

glBindTexture(GL_TEXTURE_2D, textures[MASK_TEX]);

// Write alpha value 1.0 to white regions and 0.0 to black - don't change the RGB values
glBlendFuncSeparate(
   GL_ZERO,      // remove the source rgb colors
   GL_ONE,       // keep the destination rgb colors
   GL_SRC_COLOR, // !! put high alpha (1.0) where image is white
   GL_ZERO);     // remove destination alpha

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// Bind the content image
glBindTexture(GL_TEXTURE_2D, textures[CONTENT_TEX]);

// Change the blend function to write the regions with low alpha
glBlendFuncSeparate(
   GL_ONE_MINUS_DST_ALPHA, // black regions (alpha 0): keep src rgb, white regions: remove src rgb
   GL_DST_ALPHA,           // black regions: remove dst rgb, white regions: keep dst rgb
   GL_ONE_MINUS_DST_ALPHA, // black regions: keep src alpha, white regions: remove src alpha
   GL_DST_ALPHA);          // black regions: remove dst rgb, white regions: keep dst alpha

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

但是,结合这些混合函数的结果只会产生红色背景。

我已经尝试了两天的各种功能,但我认为上面的一个应该是对的。此外,在调试时,我尝试了glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);,但两个图像都显示在彼此之上(即纹理或 GL 设置没有问题):

我对上述混合函数的选择是基于funcSeparate后面的公式为:

 Orgb = srgb  *Srgb + drgb * Drgb 
 Oa = sa * Sa + da * Da

O:输出,s - 源,d - 目的地,其余参数来自 glBlendFuncSeparate​(Srgb, Drgb, Sa, Da)


任何想法为什么纹理没有按预期混合或如何达到预期的结果?



已解决

我听从 Reto Koradi 的建议,将混合合并到我的片段着色器中:

  "precision mediump float;\n" +
  "uniform sampler2D tex_sampler;\n" +
  "uniform sampler2D mask_sampler;\n" +
  "varying vec2 v_texcoord;\n" +
  "void main() {\n" +
  "  vec4 mask = texture2D(mask_sampler, v_texcoord);\n" +
  "  vec4 text = texture2D(tex_sampler, v_texcoord);\n" +
  "  gl_FragColor = vec4(text.r * (1.0 - mask.r), text.g * (1.0 - mask.r), text.b * (1.0 - mask.r), text.a * (1.0 - mask.r));\n" +
  "}\n";

请注意,我正在使用具有混合功能 .glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) 的预乘位图。

我打算通过切换到具有相反颜色的蒙版来减少 (1.0 - mask.r) 部分(即在白色区域而不是黑色区域显示纹理)。

正确连接两个纹理(glActiveTexture 和 glUniform1i)有点棘手,但是网上有很多资源可以做到这一点。

【问题讨论】:

    标签: android opengl-es-2.0 mask blending


    【解决方案1】:

    您的解决方案似乎是基于对 GL_SRC_COLOR 作为混合函数的一部分如何影响 alpha 分量的误解。 GL_SRC_COLOR 使用源颜色的(R, G, B) 作为源的RGB 部分的乘数,源颜色的A 作为源的A 的乘数。所以对于源部分,它本质上只是每个分量的平方。

    所以当你使用这个混合功能时:

    glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ZERO);
    

    应用于 alpha 分量的GL_SRC_COLOR 使用源颜色的 alpha 值作为乘数。这个混合方程等价于:

    glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ZERO);
    

    看起来你的蒙版纹理的 alpha 是一个常量 1.0,这意味着当你使用这个混合函数渲染你的蒙版纹理时,alpha 值都设置为 1.0。然后,当您渲染您的 android 纹理时,它不会显示,因为混合方程设置为保留目标 alpha 为 1.0 的所有像素的现有内容。

    您需要解决这个问题,确保您的蒙版纹理渲染的 alpha 输出代表您要应用的蒙版值。您可以通过更改纹理本身以在 alpha 组件中包含掩码值来做到这一点。但是由于 ES 2.0 都是基于着色器的,您也可以在片段着色器中轻松处理这个问题。假设您目前在片段着色器中有这样的东西:

    vec4 texVal = texture2D(...);
    gl_FragColor = texVal;
    

    由于您的蒙版纹理是黑白的,您可以使用任何颜色值作为输出 alpha。您没有使用此渲染阶段的颜色输出,因此这些组件可以是任何东西。如果我们将它们留在0.0,它可能看起来像这样:

    vec4 texVal = texture2D(...);
    gl_FragColor = vec4(0.0, 0.0, 0.0, texVal.r);
    

    你最终所做的结果与我最近对一个相关问题的回答相似:LibGDX texture blending with OpenGL blending function。主要区别在于我建议在渲染蒙版时使用颜色蒙版来抑制颜色输出,而您使用的是单独的混合功能。

    【讨论】:

    • 谢谢,我会考虑你的建议。但是我认为前两个功能不一样(请参阅我发布的另一个问题的链接)。据我了解, funcSeparate(0, 1, GL_SRC_COLOR, 0) 将 alpha 1 用于白色区域,将 alpha 0 用于黑色区域,而 (0, 1, GL_SRC_ALPHA, 0) 将 alpha 1 用于整个图像.即 - 第一个函数是正确的。
    • 不是根据红皮书。在glprogramming.com/red/chapter06.html 查看表 6.1。对于表中的GL_SRC_COLORGL_SRC_ALPHA 条目,在这两种情况下,alpha 的因子都是As。官方的 OpenGL 规范也说了同样的话。查看 OpenGL 3.3 Core Profile 规范第 205 页上的示例表 4.2。在“Alpha 混合因子”列中,GL_SRC_COLORGL_SRC_ALPHA 具有相同的值。
    • 非常感谢,我能够通过设置片段着色器实现我的目标,这需要一些时间才能让两个纹理一起播放。 OpenGL 红皮书是一个很好的参考!我买了两本关于 OpenGL 的书,它们对我没有帮助,但只有一半的指导性......
    猜你喜欢
    • 1970-01-01
    • 2011-07-03
    • 2016-02-27
    • 2012-09-04
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    相关资源
    最近更新 更多