libgdxalphaframebuffer

libGDX Framebuffer Alpha Issues


I'm having issues with the libGDX FrameBuffer and Alpha. Below are two images of the expected result and the actual result. Can someone please tell me what I am doing wrong and how can I correct it. Here is the code:

FrameBuffer buffer;
Sprite sprite;

SpriteBatch batch;
Texture texture1;
Texture texture2;
Texture texture3;
Sprite texture2Sprite;

@Override
public void create () {
    batch = new SpriteBatch();

    texture1 = new Texture("1.png");
    texture2 = new Texture("2.png");
    texture3 = new Texture("3.png");

    texture2Sprite = new Sprite(texture2);
    texture2Sprite.setAlpha(0.5f);
    texture2Sprite.setPosition(100, 100);

    buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
    sprite = new Sprite(buffer.getColorBufferTexture());
    sprite.flip(false, true);
}

public void createFBO()
{
    buffer.begin();

    Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.begin();
    batch.draw(texture1, 0f, 0f);

    texture2Sprite.draw(batch);

    batch.end();
    buffer.end();
}

@Override
public void render () {

    createFBO();

    Gdx.gl.glClearColor(0f, 0f, 1f, 1f);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.begin();
    batch.enableBlending();
    batch.draw(texture3, 200, 200);
    sprite.draw(batch);

    batch.end();
}

Expected Result Expected Result

Actual Result Actual Result


Solution

  • I had pretty much the same issue with semi-transparent colours in the FrameBuffer, the problem and solution you can find on my badlogic forum topic here.

    Basically, you need to draw to your FrameBuffer in a pre-multiplied alpha state. You do this by creating a custom fragment shader (my full code is on the topic). Then you set your blending mode to match (GL_ONE, GL_ONE_MINUS_SRC_ALPHA).

    Then draw your sprite using the same blend function but default shader. You should end up with something like this;

    public void createFBO(){
        buffer.begin();
        batch.begin();
    
        Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
        batch.setShader(pmaShaderProgram); //pre-multiplied alpha ShaderProgram
        batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
        batch.draw(texture1, 0f, 0f);
        texture2Sprite.draw(batch);
        batch.setShader(null); //default ShaderProgram
        batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); //default blend mode
    
        batch.end();
        buffer.end();
    }
    
    @Override
    public void render () {
        createFBO();
    
        batch.begin();
        batch.enableBlending();
    
        Gdx.gl.glClearColor(0f, 0f, 1f, 1f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
        batch.draw(texture3, 200, 200);
    
        batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
        sprite.draw(batch);
        batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    
        batch.end();
    }