[SOLVED] FilterPostProcessor and multiple ViewPorts

Hello everyone,

I’ve been struggling with a problem recently. I found some discussions in the hub but I couldn’t come to a conclusion on my own.
I wanted to ask before I possibly waste a lot of time in an bad solution, perhaps someone can guide me in the right direction.

My scene is divided in multiple view ports (far away, close and very close) with the last two view ports having the “clear color” flag disabled. Everything is good until I try to apply post processing filters.

Looking into the FilterPostProcessor class, without a deep understanding on how all this works, I can see that the it uses its own FrameBuffer which replaces the one in the ViewPort:

    private void setupViewPortFrameBuffer() {
        if (renderFrameBufferMS != null) {
            viewPort.setOutputFrameBuffer(renderFrameBufferMS);
        } else {
            viewPort.setOutputFrameBuffer(renderFrameBuffer);
        }
    }

I don’t know why this is necessary but I believe this breaks the filters when there are multiple overlapping view ports, because the “background” is thrown away and replaced.

I want to have filters in my scene, some filters could only be applied to the middle view port (e.g. simple drop shadows) and others to the latest (e.g. color overlay).

I wanted to try copying the FilterPostProcessor’s code and modify it to hopefully solve my case, but many of the Filter methods are protected so I’d have to copy that as well and then I’d have to also rewrite any existing filter implementation.
It seems a lot of work and it makes me think I’m missing something, there should be a better way.

Here I made a simple example reproducing what I want to do:

This is the result without the FilterPostProcessor:

This is when I enable it. Notice the first view port (purple background with a cube) is hidden and the front view port doesn’t clear the buffer (I moved the camera to show it) and gets the filter applied.

tl;dr. add filters to multiple view port setup, how can I do it?

Have you tried setting the background color to (0, 0, 0, 0)?

I just tried but nothing changes.

I remember why this occurs now. I believe it’s because blending is turned off on the final render of the FilterPostProcessor, so instead of the alpha allowing the previous viewport to come through, it just overwrites it with the background color. If you’re using custom filters, try setting the main material’s blend mode to alpha on each filter.

Edit: if you’re using jme’s filters, I think you could probably extend the filters you need to use and then change the main material’s blend mode after initialization or in getMaterial.

1 Like

Hi. Thanks for the tip, but I couldn’t make it work with it.
The result was the same, the back scene didn’t show at all and the cube was repeated over and over on each frame (like the 2nd picture). I tried with other blends to validate it was taking effect the colors change but still the same general problem.

However browsing through jMEs code I found the solution! Here’s the how it works:

There is a ComposeFilter already made just for this use case and an example in TestPostFiltersCompositing. :monkey_face:

So the filter composes the result of the last view port with a texture, so I need to make a texture from the back port’s buffer. It’s also important to clear the background color in the front and set a 0 alpha, as you mentioned:

    // clear the background and use a color with 0 alpha
    frontViewPort.setBackgroundColor(new ColorRGBA(0, 0, 0, 0));
    frontViewPort.setClearFlags(true, true, true);

    // change the frame buffer and keep it in a texture
    var backFrameBuffer = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1);
    var backTexture = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8);
    backFrameBuffer.setDepthTarget(FrameBufferTarget.newTarget(Format.Depth));
    backFrameBuffer.addColorTarget(FrameBufferTarget.newTarget(backTexture));
    backViewPort.setOutputFrameBuffer(backFrameBuffer);

    // add another processor to the front
    var frontProcessor = new FilterPostProcessor(assetManager);
    frontProcessor.setFrameBufferFormat(Format.RGBA8);
    // add a filter to it too
    frontProcessor.addFilter(new ColorOverlayFilter(new ColorRGBA(1, 0, 0, 1)));
    // finally add a compose filter to mix it with the back texture
    frontProcessor.addFilter(new ComposeFilter(backTexture));
    frontViewPort.addProcessor(frontProcessor);

I can also apply the filter to the composed image if I play with the order, e.g.:

    frontProcessor.addFilter(new ComposeFilter(backTexture));
    frontProcessor.addFilter(new ColorOverlayFilter(new ColorRGBA(1, 0, 0, 1)));

first makes the composition and then overlays everything with red (this was I wanted to achieve).

Here is the full updated example: v2 · GitHub

Thanks for the help!

4 Likes

Good find! Glad you managed to get it worked out! :smiley:

1 Like