代码之家  ›  专栏  ›  技术社区  ›  Winter

如何用LibGDX生成一个透明的PNG图像?

  •  2
  • Winter  · 技术社区  · 6 年前

    有一个我的LibGDX游戏的实体,我想渲染成一个PNG。所以我做了一个小工具,是一个LibGDX应用程序来显示这个实体,它在F5上截图。这个应用程序的目标只是生成PNG。

    camera.update();
    
    Gdx.gl.glClearColor(0, 0, 0, 0);
    Gdx.gl.glClear(GL_COLOR_BUFFER_BIT);
    
    batch.setProjectionMatrix(camera.combined);
    batch.begin();
    
    animation.update(Gdx.graphics.getDeltaTime() * 1000);
    animation.draw(batch);
    
    batch.end();
    
    if(exporting)
        // export...
    

    从那开始 wiki page 我发现了如何制作一个屏幕截图,通过移除for循环,我可以得到一个屏幕截图,它不会用黑色像素替换透明像素。

    byte[] pixels = ScreenUtils.getFrameBufferPixels(0, 0, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);
    
    Pixmap pixmap = new Pixmap(Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), Pixmap.Format.RGBA8888);
    BufferUtils.copy(pixels, 0, pixmap.getPixels(), pixels.length);
    PixmapIO.writePNG(Gdx.files.external("mypixmap.png"), pixmap);
    pixmap.dispose();
    

    它可以很好地处理实体的边缘,但不能处理内部的多个部分。

    边缘:(完美)

    Edges

    内部:(不应透明)

    Inside

    所以我开始玩混合来解决这个问题。 与

    batch.enableBlending();
    batch.setBlendFunction(
                exporting ? GL20.GL_ONE : GL20.GL_SRC_ALPHA, // exporting is set to true on the frame where the screenshot is taken
                GL20.GL_ONE_MINUS_SRC_ALPHA);
    

    这稍微改进了一点:

    Inside working

    但是像眼镜这样的图像应该是透明的,它是不透明的:

    Opaque glasses

    而不是:

    Transparent glasses

    你知道我该怎么做吗?我想要的是非常标准的,一个透明的背景,上面有半透明的图像。我希望它的行为就像一个普通的图像软件对层(如GIMP)一样。

    1 回复  |  直到 6 年前
        1
  •  1
  •   mgsx-dev    6 年前

    你的问题是因为书写颜色和alpha都是由同一个函数调制的:SRC_alpha和ONE_MINUS_SRC_alpha。

    您需要使用glBlendFuncSeparate来实现这一点。就你而言:

    batch.begin();
    
    // first disable batch blending changes (see javadoc)
    batch.setBlendFunction(-1, -1);
    
    // then use special blending.
    Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA,GL20.GL_SRC_ALPHA, GL20.GL_DST_ALPHA);
    
    ... your drawings ...
    
    batch.end();
    

    以这种方式,颜色通道仍然像往常一样混合,但是添加了alpha通道(源通道和目标通道)。

    注意,使用libgdx 1.9.7+,不再需要批量混合黑客,可以是:

    batch.begin();
    
    batch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA,GL20.GL_SRC_ALPHA, GL20.GL_DST_ALPHA);
    
    ... your drawings ...
    
    batch.end();