'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.
- render the root Sprite into an FBO, (the background and all the entities)
- render a "swirl"-effect to the same FBO
- render a bloom-effect to the same FBO
- render a horizontal blur to the same FBO
- render a vertical blur to the same FBO
- 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 1:[1]
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. ....
Solution 2:[2]
OpenGL ES does not support reading and writing to the same texture simultaneously, which is what you're doing in the first example. You need two FBO's that you can ping pong between.
Texture fbo1, fbo2;
...
bloom.setTexture(fbo1);
bloom.setTarget(fbo2);
blurH.setTexture(fbo2);
blurH.setTarget(fbo1);
...
Solution 3:[3]
I had a very similar issue and I'm so glad I found this topic, it was a pain and I was trying to debug my glsl code for so long...
I was doing cellular automata calculations using a recursive shader with a single buffer, which suffers from the same problem. The artefacts I had with libgdx were:
- Diagonal artefact line from bottom left to top right
- Horizontal/vertical artefact lines every 256px
I fixed it by swapping the buffers each frame
private void swapBuffers() {
FrameBuffer tmp = buffer1;
buffer1 = buffer2;
buffer2 = tmp;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Cristina |
| Solution 2 | Tenfour04 |
| Solution 3 | Tann |
