FrameBuffers and the ping-pong technique

There is a technique known to digital artists, which is known as “ping-pong” where something is rendered to a fbo and a post-processing shader is applied to it, then the result is rendered into another fbo and one more shader is applied to it and then it again is rendered in the first fbo, and so on. It continues until a required number of iterations is done. Therefore it resembles the ping-pong game in some way. Then the result is used somewhere in the actual program.

A neat and clean example of it.

My question is - what is the best approach to do the same in JME?

My guess is:

  1. Create 2 FrameBuffer objects, 2 Filters and 1 ViewPort.
  2. Set 1st FB as the output framebuffer for the VP, and enable the 1st filter on it, render
  3. Set the 2nd FB as the output for the VP,
  4. disable 1st filter and enable 2nd filter
  5. render a full-screen textured quad with the texture from the 1st FB
  6. repeat step 2 but with a textured quad with texture from FB 2 which we got on step 5
  7. repeat the iterations as many times as required…

So am I ok with the general logic? Is it possible to avoid creating quads and just replace the textures directly… Are there any other things I have missed?

What would be the actual use case? It sounds like you want to do multipass rendering in a very complicated way.

@normen said: What would be the actual use case? It sounds like you want to do multipass rendering in a very complicated way.

As a usecase i know this blur filter:

“If you have to apply the filter several times in order to get a more strong blur effect, the only thing you have to do is ping-pong between two framebuffers and apply the shaders to the result of the previous step.”

For making more Blur effact it would be better to ping-pong it several times.

So the use case is to get that final texture, caressed by two shaders in turns, and assign it to a material. Maybe it is possible to do that with multipass but how you do that?

Actually, I think there are use cases for that and the blur filter, as Paul says, is one of them… My use case is a special kind of blurring too. Actually, the OpenFrameworks addon that I have referenced in my original post can be the link to find more use cases by different people.

However, if you advice a better alternative, I am all ears!

But if your use case is just two pass blurring then you can look at the bloom filter to see how it does it’s two pass blurring. It applies a horizontal blur pass and then another vertical blur pass on top of that. Two separate shaders one using the output of the other as you describe.

@pspeed said: But if your use case is just two pass blurring then you can look at the bloom filter to see how it does it's two pass blurring. It applies a horizontal blur pass and then another vertical blur pass on top of that. Two separate shaders one using the output of the other as you describe.

2 passes is only one iteration. Frst pass blurs X, second pass blurs Y. For more blur result it’s needed 4/6/8 passes to get bigger blur effect (for example like in L4D (when a user finishes level)).

You can’t read and write from the same FBO in the same shader. So when you need this kind of thing, you usually have 2 buffers and invert them on each frame. That’s basically pretty classic double buffering.
Usually the use case is temporal reprojection or similar technique. This is roughly using what you rendered on previous frame to save time/fillrate, or avoid temporal flickering on the current frame.

What you describe though sounds like 2 classic passes, I don’t really get the need of the ping pong.
Would you need to read and write from the same buffer during your passes?

There is intended to be more than 2 passes, like Paul says. Yeah, it is like double buffering, I know, I’m just trying to imagine a correct way to do all this in JME.

Not sure what you mean by “the same buffer during my passes”… does writing-reading 2 buffers in turns count as writing-reading into the same one, for each of them?.. my aim is just to receive a texture, which has some (in this case 2) shaders applied to it sequentially, on several iterations. For the best actual example of how I see it, pleae refer to the link from my original post - there is some C++ code that does just that for OpenFrameworks.

@nehon said: What you describe though sounds like 2 classic passes, I don't really get the need of the ping pong. Would you need to read and write from the same buffer during your passes?

The ping-pong is an optimization :slight_smile: It’s simply: read texture A->shader->write texture B, then repeat using texture B as input and so on N-times.

But generating N textures seems like a waste so just exchange them for each repeat. In GL I’d just (sort of) swap color attachement0 with color attachment1 for every repeat. So I guess the question is, how to do the same in JME?

@mifth said: 2 passes is only one iteration. Frst pass blurs X, second pass blurs Y. For more blur result it's needed 4/6/8 passes to get bigger blur effect (for example like in L4D (when a user finishes level)).

Yes, my point is that it goes:
frame → blurs X → target → blurs Y → target
…add as many of those as you want, I guess. But the Y blur pass is done on the results of the x blur pass so I thought it was relevant. Maybe it’s using a different fbo for each? I don’t know as I’ve never looked.

Yeah! So basically I was just like “is my logic on this good, bad or can be improved?”. Where my main question is: do I correctly represent the process in terms of JME classes and abstractions? Can you advice improvements? I never worked with framebuffers before…