libGDX 帧缓冲区 Alpha 问题

libGDX Framebuffer Alpha Issues

我在使用 libGDX FrameBuffer 和 Alpha 时遇到问题。下面是预期结果和实际结果的两个图像。有人可以告诉我我做错了什么以及我该如何纠正它。这是代码:

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

预期结果

实际结果

我在 FrameBuffer 中遇到了几乎相同的半透明颜色问题,您可以在我的 badlogic 论坛主题 here.

上找到问题和解决方案

基本上,您需要在预乘 alpha 状态下绘制 FrameBuffer。您可以通过创建自定义片段着色器来完成此操作(我的完整代码在主题中)。然后将混合模式设置为匹配 (GL_ONE, GL_ONE_MINUS_SRC_ALPHA).

然后使用相同的混合函数但使用默认着色器绘制精灵。你应该得到这样的结果;

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