MSD
MSD

Reputation: 137

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

Upvotes: 1

Views: 971

Answers (2)

Here's a simple solution I derived from hamham previous answer:


private val colorWhite = Color.WHITE

fun renderToFrameBuffer() {
    fbo!!.begin()
    ScreenUtils.clear(Color.CLEAR)
    
    fboBatch.begin()
    fboBatch.projectionMatrix = camera.combined
    

    fboBatch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA); //pre-multiplied alpha ShaderProgram
    super.draw(fboBatch, parentAlpha)
    fboBatch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); //default blend mode
    

    fboBatch.color = colorWhite
    
    fboBatch.end()
    fboGroup!!.end(screenXInPixels, screenYInPixels, screenWidthInPixels, screenHeightInPixels)
}

PS. Vel_daN: Love What You DO 💚.

Upvotes: 0

hamham
hamham

Reputation: 571

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();
}

Upvotes: 1

Related Questions