LibGDX iOS 上的 FrameBuffer 怪癖

LibGDX FrameBuffer quirk on iOS

我为文字游戏创建了动态纹理,并将其保存在 FrameBuffer 中。然后,我使用由该 FrameBuffer 支持的 TextureRegions 绘制到屏幕上。此代码在 Android 上运行良好,但我在 iOS.

上遇到问题

您可以在下方看到左下角绘制了 FrameBuffer 内容的屏幕截图 - 一切正常。

但是,如果我 return 到 iOS 主屏幕,我会处理 FrameBuffer,然后根据需要重新创建并重绘所有内容到 FrameBuffer。然后 FrameBuffer 的内容看起来是屏幕的部分翻转镜像。

我尝试在每一帧上处理并重新创建 FrameBuffer 以查看会发生什么。同样,除非我 return 到 iOS 主屏幕,否则这非常有效,之后 FrameBuffer 的内容不正确。

然后我尝试减小 FrameBuffer 的大小并跨多个 FrameBuffer 绘图。如果我这样做它再次工作正常,除非我 return 到 iOS 主屏幕。但是,在这种情况下,只有创建的第一个 FrameBuffer 损坏,所有后续缓冲区都很好。

然后我尝试总是首先创建一个 1x1px FrameBuffer,我从不在其中绘制任何东西,这解决了我的问题....但为什么呢!?从 iOS 主屏幕 returning 后创建的第一个 FrameBuffer 似乎没有按预期工作,但之后的每个 FrameBuffer 都很好。看起来它总是试图在我创建的第一个 FrameBuffer 上绘制屏幕。

以下FrameBuffer的创建和绘制代码:

private static FrameBuffer getFrameBuffer(boolean newRequired) {
    if (newRequired || frameBuffers.size == 0) {
        FrameBuffer frameBuffer;

        try {
            frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, getFrameBufferSize(), getFrameBufferSize(), false);
        } catch (Exception e) {
            frameBuffer = new FrameBuffer(Format.RGBA4444, getFrameBufferSize(), getFrameBufferSize(), false);
        }

        frameBuffer.begin();
        Gdx.gl20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        frameBuffer.end();

        frameBuffers.add(frameBuffer);

        // Set up the camera correctly for the frame buffer
        OrthographicCamera camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
        camera.position.set(frameBuffer.getWidth() * 0.5f, frameBuffer.getHeight() * 0.5f, 0);
        camera.update();
        spriteBatch.setProjectionMatrix(camera.combined);
    }

    return frameBuffers.get(frameBuffers.size - 1);
}

private static TextureRegion getTextureUsingGpu(String letter, Bubble.BubbleType bubbleType) {
    if (!enabled)
        return null;

    TextureRegion tx = getBlockImage(letter, bubbleType);

    int width = (int) (tx.getRegionWidth() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
    int height = (int) (tx.getRegionHeight() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());

    if (nextTextureX + width + PADDING > getFrameBufferSize()) {
        nextTextureX = PADDING;
        nextTextureY = nextRowY + PADDING;
        if (nextTextureY + height + PADDING > getFrameBufferSize()) {
            getFrameBuffer(true);
            nextRowY = PADDING;
            nextTextureY = PADDING;
        }
    }

    FrameBuffer fb = getFrameBuffer(false);

    fb.begin();
    spriteBatch.begin();

    tx.flip(false, !tx.isFlipY());

    spriteBatch.disableBlending();
    spriteBatch.draw(tx, nextTextureX, nextTextureY, width, height);
    spriteBatch.enableBlending();

    // Drawing Code Removed

    spriteBatch.end();
    fb.end();

    TextureRegion textureRegion = new TextureRegion(fb.getColorBufferTexture(), nextTextureX, nextTextureY, width, height);
    textureRegion.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
    cacheTexture(letter, textureRegion);

    nextTextureX += width;
    nextRowY = Math.max(nextRowY, nextTextureY + height);

    return textureRegion;
}

如果您从 resizeresume 方法调用 getFrameBuffergetTextureUsingGpu,那就是问题所在。在 iOS 上,resizeresume 不一定在 OpenGL 准备好恢复之前被调用,所以在那里做任何与 OpenGL 直接相关的事情都是不安全的,比如创建 ShaderPrograms,加载纹理,或创建帧缓冲区。我在我的游戏中通过使用 resume 设置一个成员布尔值来修复此问题,并使用它将新帧缓冲区的创建推迟到 render 方法。