Search code examples
javaopengllibgdx

Using a single FrameBuffer for multiple Shader effects leads to artifacts


I am using libGDX and have created my own Sprite-class and renderer (which uses libGDX's SpriteBatch under the hood). The renderer is quite "smart", it sorts the sprites by layer/shader/texture/blend, and the sprites can contain children.

Now I am trying to add support for FrameBuffers and I have a little problem.

I am trying to add multiple post-processing effects via shaders, to the "root" sprite in my game.

  1. render the root Sprite into an FBO, (the background and all the entities)
  2. render a "swirl"-effect to the same FBO
  3. render a bloom-effect to the same FBO
  4. render a horizontal blur to the same FBO
  5. render a vertical blur to the same FBO
  6. render the final result of the FBO into the screen via a Sprite

This all is achieved quite simply, each effect has its own Sprite-object. They are layered via setLayer(int), and textures/FBOs/shaders are set via setTexture(Texture) / setTarget(Texture) / setShader(Shader).

I attempted and want to use the SAME Texture as a result and a target. e.g.:

Texture fbo = Video.newTarget();

...

bloom.setTexture(fbo);
bloom.setTarget(fbo);

blurH.setTexture(fbo);
blurH.setTarget(fbo);

....

If I use the same FBO in this way, I can see some strange artifacts in the final image that are hard to describe. I either get some strange lines somewhere in the texture, or simply some weird distortions.

If I create a separate FBO for each effect, everything works just fine.

e.g:

Texture fbo1, fbo2, fbo3, fbo4;

...

bloom.setTexture(fbo1);
bloom.setTarget(fbo2);

blurH.setTexture(fbo2);
blurH.setTarget(fbo3);

...

I'd really like to avoid this if possible, as it leads to messy code, and hurts performance.

I am really not that well-versed in OpenGL/GLSL (I don't even quite understand the rendering pipeline... :), however, does anyone have any ideas what might cause these artifacts from my explanation?

I also thought of having two FBOs and "ping-pong" between them, but for some reason all I see is black.. for now.. :) I'll have to experiment more with that.


Solution

  • Your problem comes from having dependent processing steps in your pipeline.

    render the root Sprite into an FBO, (the background and all the entities)

    render a "swirl"-effect

    Then you are using the same FBO to do:

    render a bloom-effect

    If your GPU driver has not finished processing everything you are overwriting in the bloom effect everything you have done in the swirl effect step.

    The best way to go about it is to break up your pipeline in independent stages, even if that implies using more than one FBO.

    From my point of view if you don't need the original FBO and if all of the effects need as input the same texture size:

    Render the scene in FBO A.
    Render Swirl effect in FBO B.
    Render Bloom in FBO A using the color texture from FBO B.
    Render Vertical Blur in FBO B using the color texture from FBO A.
    ....