2
\$\begingroup\$

I want to draw a bunch of images in front of a background. Where images overlap, I want those to be blended together (for now, using a mix of 0.5 source * 0.5 destination color every time an image fragment gets drawn on top of another image's fragment). Any background that existed before I drew the images should just be overwritten.

So basically I want:

  • when an image is drawn on top of the background: output color := image color
  • when image A is draw on top of image B: output color := 0.5 * (color A + color B)

What I've tried is the following:

    // clear the alpha channel of the background already in the framebuffer:
    GLES20.glColorMask(false, false, false, true);
    GLES20.glClearColor(0, 0, 0, 0); // clear with alpha == 0
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    GLES20.glColorMask(true, true, true, true);

    // enable blending for drawing the images
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendEquation(GLES20.GL_FUNC_ADD);
    GLES20.glBlendColor(0, 0, 0, 0.5f);

    // The alpha blendFunc is chosen such that the resulting alpha 
    // will be 0.5 in any pixel that had already an image fragment 
    // drawn. In those pixels still holding the background, the
    // alpha should be 0 based on the glClear() above.
    // For those pixels holding the background,
    // GL_ONE_MINUS_DST_ALPHA * srcColor + GL_DST_ALPHA * dstColor
    // should equal srcColor because dstAlpha is 0.
    // For those pixels already holding an image fragment, 
    // GL_ONE_MINUS_DST_ALPHA * srcColor + GL_DST_ALPHA * dstColor
    // should be 0.5 * srcColor + 0.5 * dstColor because dstAlpha
    // will be 0.5
    GLES20.glBlendFuncSeparate(GLES20.GL_ONE_MINUS_DST_ALPHA, GLES20.GL_DST_ALPHA,
            GLES20.GL_CONSTANT_ALPHA, GLES20.GL_ZERO);

    imageShaderProgram.draw(viewProjectionMatrix);

    GLES20.glDisable(GLES20.GL_BLEND);
    [...draw some further foreground...]

However, I can't get this to work. The result is that the background that I've drawn ahead of the blending still appears unaltered, and the foreground that I draw afterwards also appears. There is no trace at all of the content (imageShaderProgram.draw(viewProjectionMatrix)) that I drew while blending was enabled.

If I drop the glEnable(GLES20.GL_BLEND), my images get drawn (but of course not blended).

This all looks just as if the dstAlpha was always 1 rather than 0 or 0.5 like I'm trying to make it. So I suspected my glClear(GL_COLOR_BUFFER_BIT) not working right. But when I change the glColorMask to (true, false, false, true), the background's red color component is cleared, so I don't see why (false, false, false, true) wouldn't set the framebuffer's alpha channel to 0 like I intended.

Any idea what I might be doing wrong?

\$\endgroup\$
  • 2
    \$\begingroup\$ Do you have alpha channel in your frame buffer? \$\endgroup\$ – msell Jan 9 '16 at 12:12
  • \$\begingroup\$ Excellent question. I don't know. I'm just drawing in a render context provided by a GLSurfaceView in Android. Is there a way I can check if my frame buffer has an alpha channel, other than by choosing one through my own code that does? \$\endgroup\$ – Tobias Jan 9 '16 at 12:19
  • 1
    \$\begingroup\$ Thanks to much, that was exactly it! My code is behaving as expected after I added glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 0, 0); \$\endgroup\$ – Tobias Jan 9 '16 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.