VBO Usage for spherical quadtree-tiled terrain


I have a terrain engine rendering a spherical globe with quad tree tiles. Each quad tile is a mesh of about 1000 vertices. I am currently only using regular indexed vertex arrays with OK performance, but want to use VBO’s instead.

For each quad tile I have a unique vertex array. In addition each tile has texture coordinates and an index array for glDrawElements that can be shared between tiles. (Each tile is the same regular grid, but at different depth in the quad tree).

The question is what’s the best way to put this into VBO’s? Should I use one static VBO per vertex array? These VBO’s would be quite small, and some preliminary tests indicate that this doesn’t do much for performance at all.

Another idea is to make a big VBO of 1-4Mb (as recommended on the OpenGL Wiki) and upload each tile into this VBO with glBufferSubData as they come into view.

I would still need to call glVertexPointer for each tile with the correct offset into the VBO right? Or is there a way to add a fixed offset to the index array before calling glDrawElements?

Would this be a reasonable way of doing things, or should I try something completely different?


I would use one VBO, as there is less state changing. You can use glDrawElementsBaseVertex (when available) to select a base vertex for drawing, no need to adjust pointers.

How often you update the contents? Using API such as glMapBufferRange, glFlushMappedBufferRange and glMemoryBarrier can give better performance than glBufferSubData().

Excellent! glDrawElementsBaseVertex is exactly what I need :slight_smile:

The VBO will probably update fairly often, but not necessarily every frame, depending on the camera movement and speed.

It will be updated when a new tile becomes visible or when a visible tile changes resolution. I think I may be able to cache quite a few tiles in one or more of these large VBOs though, so I imagine that we can get quite static behaviour much of the time. Anyway, large parts of the VBO will remain constant from frame to frame.

If it turns out that parts of the VBO changes every frame, should I still use the GL_STATIC_DRAW buffer hint, or would it be better with DYNAMIC?

Thanks for very useful feedback :slight_smile:

Hm… come to think of it, I probably can’t use glDrawElementsBaseVertex after all, since I want to reuse the same texture coordinate array for each tile. I also have some extra vertex data that will be used for some of the tiles, but not all of them (morph vertices).

Or would it be better to duplicate the texture coordinates to avoid the glVertexPointer calls?

Just a quick update. I implemented it as described in the original post with a single 4Mb VBO for the vertices, glBufferSubData for each new tile, GL_STATIC_DRAW buffers and simple glDrawElements.

The average fps jumped from about 100 to just below 1000 in my benchmarks, so I guess this is one of those cases where VBO’s can make a significant difference :smiley:

Yeah, though keep in mind. Rebinding VBOs is expensive (in my experience at least). This technique excels not just because it is VBO, but because (additionally) there is very little VBO rebinding going on.

If you put each batch in its own VBO, you can actually make things considerably slower than merely using client arrays (VBO being driver-side memory, and client arrays being app-side memory). …unless of course you use NV bindless extensions to get rid of the bind overhead. Then it’s really fast.

Hi eldritch,
I have a similar terrain engine under works, and I’ve been planning to do what you just did with the single big VBO. I just have one thing that I have not been able to figure out yet: how do you change the texture for each tile?

Now I’m drawing each tile individually, setting the correct texture before drawing.