如何正确使用LIBGDXFrameBuffer

How to use LIBGDX FrameBuffer correctly

这是我的第一个问题。我试图查看源代码 (link) 搜索 Whosebug 并阅读一些一般性解释。但是我不知道如何正确设置(或理解)它。

我不了解投影矩阵或大部分 GL 术语。 我不知道当你设置相机时会发生什么(camera.setToOrtho())当你应该更新相机时 或者何时设置批次的投影矩阵。到目前为止,我对它的唯一使用仅限于下面所示的 draw() 方法中使用的代码。

我有一个带有图层的基于图块的游戏。我想使用 FrameBuffer 将水层绘制到 TextureRegion。所以我以后可以尝试用着色器来操纵它。我认为这将是做到这一点的方法。

(我没有使用任何 "Scene2d" 或 "Tiled" classes)

Example of what the layer looks like

我如何绘制图层:

public void draw(OrthographicCamera camera) {

        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA,GL20.GL_ONE_MINUS_SRC_ALPHA); // [1]
        BATCH.setProjectionMatrix(camera.combined);
        BATCH.begin();

        for (int i = 0; i < NUM_LAYERS; i++) {
            if (RENDER[i]) {
                if (SORT[i]) Collections.sort(LAYERS.get(i));
                for (DrwDat dat: LAYERS.get(i)) {                           // [2]
                    dat.draw(BATCH);
                }
            }
        }
        BATCH.end();
    }

1。不知道这是做什么的,但我似乎不需要它。 [2]. DrwDat 只是一个保存可绘制对象的 class。在这种情况下,这些是瓷砖。

好的。所以在绘制循环中,我放置了一个在绘制水层时调用的方法。目前 我想绘制应该在屏幕上显示的每个图块,而不是将它们绘制到缓冲区。然后:将缓冲区绘制到屏幕上。

问题:我可以在下面的 "renderFBO()" 方法中输入什么来使其工作?为什么?基本上让屏幕准确显示不使用 FrameBuffer

时会显示的内容

(当前代码纯粹是绝望,因为我尝试使用 youtube 看不懂就当作模板教程。)

private void renderFBO(OrthographicCamera camera, int layer) {
        BATCH.end();
        frameBuffer.begin();
        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);


        BATCH.begin();

        camera.setToOrtho(false);
        camera.position.set(FocusPoint.position.x,FocusPoint.position.y,0);  // [3]
        camera.update();
        BATCH.setProjectionMatrix(camera.combined);

        for (DrwDat dat: LAYERS.get(layer)) {
            dat.draw(BATCH);
        }

        frameBuffer.end();                                                             // [4]
        BATCH.end();
        camera.setToOrtho(false);

        //BATCH.setProjectionMatrix(camera.combined);
        BATCH.begin();
        BATCH.draw(bufferTexture.getTexture(),0,0,Settings.SCREEN_W,Settings.SCREEN_H);
        BATCH.end();

        camera.position.set(FocusPoint.position.x,FocusPoint.position.y,0);
        camera.update();
        BATCH.setProjectionMatrix(camera.combined);

        BATCH.begin();

}

[3]。 FocusPoint 只是相机跟随的一个点(例如:鼠标点击位置)

[4]。出于某种原因,framebuffer.end() 在 batch.end() 下方不会呈现任何内容。

下面是我如何初始化 FrameBuffer:

private FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888,Settings.SCREEN_W,Settings.SCREEN_H,false);
private TextureRegion bufferTexture = new TextureRegion(frameBuffer.getColorBufferTexture());

如果这太笼统了,我很抱歉。但任何帮助表示赞赏。我可以阅读的任何提示也会 很有帮助。

关于您的第 1 点:您不需要该行,因为 SpriteBatch 会自行管理混合并将覆盖您在调用 batch.begin().

之前设置的任何混合状态

关于您的第 4 点:像这样打乱它们,您根本就没有吸引 FBO。可能是您的 FBO 设置有问题或您绘制它的方式有问题,所以它无法正常工作,但像正常一样直接在屏幕上绘制会使它看起来像是在工作。

就像在您的示例中一样,这将假设它正在中断 batch.begin()batch.end() 之间完成的现有绘图。所以它会在你的 begin()end() 调用之间被调用,如下所示:

    public void draw(OrthographicCamera camera) {
        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        BATCH.setProjectionMatrix(camera.combined);
        BATCH.begin();

        renderFbo();

        BATCH.end();
    }

无需摆弄相机来绘制帧缓冲区内容以覆盖整个屏幕。您可以使用单位投影矩阵和 OpenGL 将默认投影定义为 2 个单位宽和高,以 (0, 0) 为中心的知识。

您不需要结束和开始批处理。在切换渲染表面之前刷新它会更简单一些。

private final Matrix4 originalMatrixTemp = Matrix4();
private static final Matrix4 IDENTITY = Matrix4();

public void renderFbo() {

    // Finish drawing anything queued before we switch the frame buffer.
    batch.flush(); 

    // Store the current Batch state for things we're going to temporarily change.
    originalMatrixTemp.set(BATCH.getProjectionMatrix());
    ShaderProgram originalShader = BATCH.getShaderProgram();
    int originalBlendSrcFunc = BATCH.getBlendSrcFunc();
    int originalBlendDstFunc = BATCH.getBlendDstFunc();

    // No need to set up camera projection again. 
    // It was already set before calling this method.

    // This ensures alpha is preserved in case you have overlapping translucent sprites.
    BATCH.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE);

    // Draw to FBO
    frameBuffer.begin();
    Gdx.gl.glClearColor(0, 0, 0, 0);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    for (DrwDat dat: LAYERS.get(layer)) {
        dat.draw(BATCH);
    }
    BATCH.flush();
    frameBuffer.end();

    /* When you have a custom shader for rendering FBO contents, here's where 
       you would prepare it.
    BATCH.setShader(waterFboShader);
    waterFboShader.setUniformf("u_someUniformAttribute", someUniformAttribute);
    etc.
    */

    // Ensure we're drawing the frame buffer texture without modifying its color.
    BATCH.setColor(Color.WHITE);

    // Dimensions to the corners of the screen when using an identity matrix for 
    // projection. Negative height to flip vertically. (OpenGL image space and world 
    // space have opposite Y directions for some reason.)
    BATCH.setProjectionMatrix(IDENTITY);

    BATCH.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2);
    BATCH.flush();

    // Restore state from before this method was called.
    BATCH.setShader(originalShader);
    BATCH.setProjectionMatrix(originalMatrixTemp);
    BATCH.setBlendFunction(originalBlendSrcFunc, originalBlendDstFunc);
}

存储原始矩阵时,您必须将其值复制到您自己的临时实例中,因为 SpriteBatch 会向您传递其自己的最终实例,其值在您应用单位矩阵时将被覆盖。