crashinvaders / gdx-vfx

libGDX post-processing visual effects
https://crashinvaders.github.io/gdx-vfx
Apache License 2.0
189 stars 25 forks source link

Alternative usage #19

Open kunterbunt2 opened 2 years ago

kunterbunt2 commented 2 years ago

The vfxManager uses a fbo to capture all activities and then adds all the effects. This saves one copy operations. But, currently fbos in libgdx do not support multi sampling. So, I am forced to give up sampling support if I use vfxManager. Can we have an alternative method that just copies the current screen without capturing in a fbo? This way all draw operations can use multi sampling.

metaphore commented 2 years ago

Hi, sorry for the late reply and thanks for the input!

I'm not very familiar with any other sampling methods available for cross-platform libGDX shaders (we stack with GLSL v1.20, if I'm not mistaken). Could you please explain your case in a bit more details? What exactly would you prefer to use to supply the initial image to the effect processing pipeline?

kunterbunt2 commented 2 years ago

Hi, originally I thought, why not read from the current screen? But, I learned that opengl does not support reading from the screen. So, it looks as if we can close this as not possible. But, thanks for looking into it.

Betalord commented 1 year ago

Actually, OpenGL does support reading from screen. In my code, I copy backbuffer contents to a texture and use that for gdx-vfx effects. This is how I copy backbuffer:

public static void copyBackBufferToTexture(Texture tex) {
        tex.bind();
        Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, Format.toGlFormat(tex.getTextureData().getFormat()), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0); // WARNING: getFormat() doesn't always return correct format!
        Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, 0); // unbind
}

You better use RGBA_8888 format, or you could run into troubles (libGDX being buggy). Also, you can simply create a FBO and use its color texture with this method. Here is my little library that does just that and uses Bloom effect (modify it as needed):

package com.betalord.sgx.rendering;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.utils.Disposable;
import com.betalord.sgx.util.SGXFrameBuffer;
import com.crashinvaders.vfx.VfxManager;
import com.crashinvaders.vfx.effects.BloomEffect;

public class PostProcessing implements Disposable {
    private VfxManager vfxManager;
    private boolean enabled = true;
    /** An intermediate FBO we use to copy back buffer contents to it and then pass it to gdx-vfx. */
    private SGXFrameBuffer fbo;
    private int width = 0;
    private int height = 0;

    public void init(int width, int height) {
        this.width = width;
        this.height = height;

        vfxManager = new VfxManager(Pixmap.Format.RGBA8888, width, height);
        BloomEffect bloom = new BloomEffect();
        //bloom.applySettings(new BloomEffect.Settings(10, 0.85f, 1f, 0.85f, 1.1f, 0.85f));
        bloom.applySettings(new BloomEffect.Settings(10, 0.1f, 1f, 0.85f, 1.1f, 1.85f));
        vfxManager.addEffect(bloom);
        fbo = new SGXFrameBuffer(Pixmap.Format.RGBA8888, width, height, false);
    }

    public void process() {
        if (!enabled)
            return;

        RenderUtils.copyBackBufferToTexture(fbo.getColorBufferTexture());
        vfxManager.cleanUpBuffers();
        vfxManager.useAsInput(fbo.getColorBufferTexture());
        vfxManager.applyEffects(); // apply the effects chain to the captured frame
        vfxManager.renderToScreen(); // render result to the screen
    }

    public void resize(int width, int height) {
        if (this.width == width && this.height == height)
            return;
        this.width = width;
        this.height = height;

        vfxManager.resize(width, height);
        // resize FBO:
        if (fbo != null) fbo.dispose();
        fbo = new SGXFrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
    }

    public void enable(boolean enable) {
        this.enabled = enable;
    }

    public void enable() {
        enable(true);
    }

    public void disable() {
        enable(false);
    }

    public boolean isEnabled() {
        return enabled;
    }

    @Override
    public void dispose() {
        if (vfxManager != null)
            vfxManager.dispose();
        if (fbo != null)
            fbo.dispose();
    }
}

Note though, that gdx-vfx is possibly quite slow and could probably be greatly optimized. It uses several shader passes that could be reduced to a single pass, and some redundant (I believe) FBOs. But I haven't looked much into the code, just had a glance at it.

mgsx-dev commented 1 year ago

@Betalord Sorry to be a bit rude but :

OpenGL does support reading from screen

Yes, but that would be very inefficient in this context, it requires copy from GPU memory to CPU memory and send it back to the GPU memory, that's very bad in term of performances.

You better use RGBA_8888 format, or you could run into troubles (libGDX being buggy)

No. Libgdx works well with some other formats.

Also, you can simply create a FBO and use its color texture with this method

Yes, that's the proper way to do it.

that gdx-vfx is possibly quite slow and could probably be greatly optimized. It uses several shader passes that could be reduced to a single pass, and some redundant (I believe) FBOs

No. The lib is good. It's just that post processing effects are greedy.

But I haven't looked much into the code

Yeah, that's probably why you say that :D