21

I basically want to play around with blending modes in LibGDX but don't know how to do it. I found this image on internet. I want to do the same thing on LibGDX. Can someone teach me how.

enter image description here

I've been playing around using Scene2D. Here's my non-working snippet.

private class MyGroup extends Group {

    Image red, blue;

    public MyGroup() {
        Texture texture = new Texture(Gdx.files.internal("images/red.png"));
        texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
        red = new Image(texture);

        texture = new Texture(Gdx.files.internal("images/blue.png"));
        texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
        blue = new Image(texture);

        red.setX(-25);
        blue.setX(25);
    }
    @Override
    public void draw(Batch batch, float parentAlpha) {
        batch.end();
        batch.begin();
        batch.enableBlending();

        red.draw(batch, parentAlpha);

        Gdx.gl.glEnable(Gdx.gl20.GL_BLEND);
        Gdx.gl.glBlendFuncSeparate(
                Gdx.gl20.GL_DST_COLOR, 
                Gdx.gl20.GL_SRC_COLOR,
                Gdx.gl20.GL_ONE,
                Gdx.gl20.GL_ONE);

        blue.draw(batch, parentAlpha);
    }
}
Ezekiel Baniaga
  • 853
  • 1
  • 12
  • 26
  • 1
    You should call `enableBlending()` after `end()` and before `begin()`, otherwise you're flushing the batch twice for no reason. (There is a cost to a flush, e.g. recomputing matrices.) Or, you could just call `enableBlending()` and skip the other two calls, since that causes a flush anyway. – EntangledLoops Feb 28 '20 at 01:04

2 Answers2

21

I realize this is not a new question, but I thought I would share some information for anyone else who makes it to this question/answer without knowing much about rendering in OpenGL (Knowing these terms helps a lot so you aren't just guessing mix-and-matching) Note that this site is how I learned most of this myself, so more complete information can be found there.

Destination Color: the color in the buffer, which will (eventually) be drawn unless it is modified or overwritten with new values.

Source Color: the color coming in from additional rendering commands, which may or may not interact with the destination color (depending on our settings)

The default blending equation: Final Color = (SourceColor*SourceBlendingFactor)+(DestinationColor*DestinationBlendingFactor) (This default equation can be changed, but I recommend reading my source link at the top for more information on that)

The two BlendingFactors are what we can mess with. We can set them to:

GL_ZERO: RGB(0,0,0) A(0)
GL_ONE: RGB(1,1,1) A(1)
GL_SRC_COLOR: RGB(sourceR, sourceG, sourceB) A(sourceA)
GL_ONE_MINUS_SRC_COLOR: RGB(1-sourceR, 1-sourceG, 1-sourceB) A(1-sourceA)
GL_DST_COLOR: RGB(destinationR, destinationG, destinationB) A(destinationA)
GL_ONE_MINUS_DST_COLOR: RGB(1-destinationR, 1-destinationG, 1-destinationB) A(1-destinationA)
GL_SRC_ALPHA: RGB(sourceA, sourceA, sourceA) A(sourceA)
GL_ONE_MINUS_SRC_ALPHA: RGB(1-sourceA, 1-sourceA, 1-sourceA) A(1-sourceA)
GL_DST_ALPHA: RGB(destinationA, destinationA, destinationA) A(destinationA)
GL_ONE_MINUS_DST_ALPHA: RGB(1-destinationA, 1-destinationA, 1-destinationA) A(1-destinationA)
GL_SRC_ALPHA_SATURATE: RGB(min(sourceA, 1-destinationA), min(sourceA, 1-destinationA), min(sourceA, 1-destinationA)) A(1)

The following also uses some predefined constant color, by default it is black
GL_CONSTANT_COLOR: RGB(constantR, constantG, constantB) A(constantA)
GL_ONE_MINUS_CONSTANT_COLOR: RGB(1-constantR, 1-constantG, 1-constantB) A(1-constantA)
GL_CONSTANT_ALPHA: RGB(constantA, constantA, constantA) A(constantA)
GL_ONE_MINUS_CONSTANT_ALPHA: RGB(1-constantA, 1-constantA, 1-constantA) A(1-constantA)

So all of these are just predefined float values that are being multiplied with either our source or destination, and then added to the other.

The easiest to observe from the image is GL_ZERO and GL_ONE. We end up with whichever image has the ONE.


Understanding GL_ZERO with GL_DST_COLOR

When GL_ZERO is on the destination, we are ignoring any color information currently in the buffer (because multiplying everything by zero). However, With GL_DST_COLOR also on the source image, we end up multiplying the r, g, b, a values of the source and destination.

This looks good in the image because of the nature of the example images. One acts as a solid color image, while the other grayscale image looks and acts almost like a beam of light to "reveal" the color out from our GL_ZERO setting.

Hopefully, this helps explain the images we can see above and helps everyone understand how those images are actually being blended together.

jevon
  • 3,197
  • 3
  • 32
  • 40
DoubleDouble
  • 1,493
  • 10
  • 25
5

Ok, to partly answer my question, here's the trick I used. Please let me know if I'm doing anything wrong. Note: This doesn't work on other function.Like when I combine GL_DST_COLOR and GL_ZERO, it doesn't output what I want. But others will. So just play around with it. I'm still watching for other answers here.

Here's the code:

private class MyGroup extends Group {

    Texture dst, src;

    public MyGroup() {
        dst = new Texture(Gdx.files.internal("images/dst.png"));
        dst.setFilter(TextureFilter.Linear, TextureFilter.Linear);

        src = new Texture(Gdx.files.internal("images/src.png"));
        src.setFilter(TextureFilter.Linear, TextureFilter.Linear);
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        // We need to cast to use blending function
        SpriteBatch sb = (SpriteBatch)batch;

        // draw our destination image
        sb.draw(dst, 0, 0);
        sb.end();

        // remember SpriteBatch's current functions
        int srcFunc = sb.getBlendSrcFunc();
        int dstFunc = sb.getBlendDstFunc();

        // Let's enable blending
        sb.enableBlending();
        sb.begin();

        // blend them
        b.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_SRC_ALPHA);
        sb.draw(src, 0, 0);

        // Reset
        sb.end();
        sb.begin();
        sb.setBlendFunction(srcFunc, dstFunc);

    }
}
Ezekiel Baniaga
  • 853
  • 1
  • 12
  • 26