Infinite Horizontal Scrolling Using FBOs

Hey all! I am trying to get a functionality where I can draw paths on a constantly scrolling background. Currently, I am drawing to an FBO, then drawing the FBO at a constantly moving “offset” according to the velocity of the object I am moving.

In the left case, all is as it should be—the drawing object is moving in the direction and the drawn path is constantly scrolling to the left to simulate motion (the drawing object stays in place).

On the right side is the problem. Because I’m drawing to an FBO, at a certain point I reach a horizontal limit, and my FBO becomes no longer visible. At this point I don’t really need the path drawn that’s offscreen to the left because this application will only be going to the right.

Does anyone know a simple solution to this? I’ve tried various things, like just making a huge FBO (runs into performance issues, of course) and even hot-swapping two different FBOs, but the problem with that is that the boundaries don’t transition properly when you are drawing in between the FBOs. I also tried just forgetting about the FBOs and storing the path history in a vector, but this runs into performance issues after a while too due to the drawing resolution.

What would be really nice is if there were a way to just constantly shift my FBO pixels to the left in a sort of queue fashion, loading new space to the right and deleting it to the left, but I haven’t been able to find a way to do this.

Any ideas or helpful knowledge is very much appreciated!

-Michael

Hey Michael,

I’m not really sure if I understood your render setup correctly. In my understanding FBOs are just texture buffers (simply spoken an image or a texture, that is used to render into). The “image” or “texture” of this FBO is than mapped onto a fullscreen quad (two triangles that fill the whole screen) to show it on the screen. Therefore I didn’t quite get the notion of the FBO “becoming no longer visible”?

Couldn’t you move the camera and the fullscreen quad? I’ve tried to build a quick setup in blender to show what I mean: https://streamable.com/nq4rt4
Then make sure to delete points of the path when they get out of sight.

You could probably also just move the path in the other direction to the left and keep the camera static :thinking:

1 Like

Hey Guido, thanks so much for your reply! This sounds promising and I’ll give it a shot.

To clarify, right now those points of the path are being drawn to the background in each frame—they look like one big shape but really there is a sort of “brush head” that is drawing them multiple times a second, so I can’t modify the position of those points once I’ve drawn them—I tried this using a std::vector and using translate + offset, but the number of points I was drawing causes too much performance lag.

So the “solution” I’ve been using is to instead modify the position of the buffer to move the points that I’ve drawn to the buffer, as in fbo.draw(-offset,0); , which I will admit seemed wrong/hacky to me ( I posted this in the beginners section for a reason :wink:). The problem is that once fbo.getWidth()-offset is smaller than ofGetWidth(), the fbo is no longer visible on the screen.

I will try the camera method and report back!

1 Like

This should not be too difficult with a custom shader and FBO ping-pong. Goes something like this:

// .h
ofShader shader;
ofFbo fbo[2];
int iFBO = 0;

// .cpp
#define SWAP(x) (x + 1) % 2

// .cpp setup
ofEnableAlphaBlending();

for (size_t i = 0; i < 2; i++) {
	fbo[i].allocate(WIDTH, HEIGHT, GL_RGBA);
}
shader.load(SHADER_PATH);

// .cpp draw
iFBO = SWAP(iFBO); // this swaps the active buffer index

fbo[iFBO].begin();
ofClear(0, 0);
shader.begin();
shader.setUniformTexture("tex", fbo[iFBO].getTexture(), 0);
fbo[SWAP(iFBO)].draw(WIDTH, HEIGHT);
shader.end();

// draw new content to fbo here

fbo[iFBO].end();

fbo[iFBO].draw(WIDTH, HEIGHT)

And then in your shader you sample the texture by adding a small horizontal shift/bias to the texture coordinate. You can take a very simple texture shader program and in the fragment shader simply add 1.0 (or 1.0/WIDTH for normalized coordinates) to the x component of the incoming texcoord. I wrote all this really fast and might have missed a thing in the code but hopefully it makes some sense. You will find more on FBO ping-ponging online–it’s a pretty common approach for this sort of thing. Good luck!

3 Likes

Thanks so much for your input guys! I ended up using the camera technique and went back to the std::vector storage & drawing method—it’s slow, but I found ways to optimize it a bit by deleting shapes that had disappeared off screen.

In the future, I will probably try your method of “FBO ping-pong”, Ishoek, since that sounds like the most proper solution. I appreciate the examples and knowledge—I learned a lot!

2 Likes