2

I'm messing with a simple concept of creating 2D walls with C++/OpenGL. Each wall is described by 4 vertices and either extends horizontally or vertically, and also has a color. Walls interlink if they collide. Perimeters formed by walls are filled by simple rectangles.

original

My idea would be to store many walls' vertex data in a single VBO. Or multiple for each attribute then place in a VAO? Interleave in one VBO and access via VAO? Regardless, many walls in one object. If whatever I'm storing in runs out of space, make another VBO (or whatever I'm using) to store another group of walls. I also wanted to have walls that meet, such as at a right angle, share vertices to save space.

However, the walls are mutable, so vertices can be added, moved, or removed at any time. This would require keeping track of the free blocks in the VBO and then allocating wall data to them as needed. It would also mean that if I have multiple VBOs, 2 walls that share vertices must be in the same VBO, possibly introducing all sorts of headaches. But at the same time, I don't want to make a VBO for every single wall, which is nothing but a very simple 4 vertex thing at most.

Example of some alterations occurring to the original image: altered

How is this situation typically handled? Does it require rolling my own memory allocation scheme to work with the VBOs, or is there a suitably fast solution that doesn't require so much work?

user173342
  • 1,820
  • 1
  • 19
  • 45
  • Are you running into performance issues with the basic "reupload the entire scene if anything changes" approach? – genpfault Dec 03 '12 at 18:20
  • I'd like to pursue further optimization in the future, so I'd like to know my options and build with them in mind. – user173342 Dec 03 '12 at 18:21
  • You could use a geometry shader to generate the wall vertices on the fly. Adjacent input will enable you to draw the extra rect and other special cases. The buffer would then just contain the wall parameters, resulting in reduced buffer size and complexity. Even if you have small buffers as a result of rather expensive management, what about the actual wall objects in the logic part of the code? If they would be one and the same struct as used in the GL buffers, this could cut down some overhead, because direct manipulation in mapped buffer ranges would be possible then. – Sam Dec 09 '12 at 23:52

3 Answers3

3

Why do you think that a VBO could possibly run out of space? I mean, for most GPUs the maximum size of a VBO is of the order of 16-32-64Mb, that's a lot! (check also here)

If you can fit all your datas in a single VBO the problem is much simpler. I'd just re-buffer all your datas when they need to be changed (and that, I believe, wouldn't happen often, unless you want to add/remove a wall every frame).

If this is not accetable in your case, I suggest you to check out some popular implementation from open source codes, here for example there is osg's GLBufferObject.

Take a look at the GLBufferObject::compileBuffer() function; in your case each osg::BufferEntry can be a group of connected walls. To render the scene you will have to query this class to get the offsets of each data.

Hope this helps.

Community
  • 1
  • 1
sbabbi
  • 11,070
  • 2
  • 29
  • 57
2

I'd say, whenever your data changes (including on the initial creation) allocate a new buffer for all the vertices (reusing the VBO name, but orphaning the old and allocating new storage) and copy vertices from your own data structures to the VBO.

chill
  • 16,470
  • 2
  • 40
  • 44
  • Ya, I've read about orphaning (http://www.opengl.org/wiki/Buffer_Object_Streaming), and it certainly seems the way to go. However, my problem is with tracking unused portions after vertices are deleted, allocating new VBOs when I run out of space, and dealing with connected walls that may end up in different VBOs. I was wondering if there was any prerolled (or maybe simply easier) solution for what would seem to be a common issue. – user173342 Dec 01 '12 at 18:13
2

Approach significantly depends on your requirements.

  • What is the performance of you target platform (PC, phone)?
  • How large is your buffer going to be (~1Mb, ~10mb, ~100Mb)?
  • How frequently you are going to update your data (every frame or occasionally)?

I don't recommend you implementing your memory manager, unless it is really necessary. I.e. your buffer is larger than several megabytes and you have frequent updates. For small buffers you can hold and process all your data on CPU using suitable data structures and just construct the buffer before rendering and stream all the data to GPU. I.e. create buffer with GL_STREAM_DRAW and update it fully every frame.

If that is not the case, then implement a kind of memory manager. To avoid moving data around use degenerate triangles (i.e. when you remove a wall, move wall vertices such they compose a triangle that will be culled by rasterizer). Keep a list of chunks of free vertices (those that compose a degenrate triangles) and use them to construct new walls. Adding a wall should not be a problem. You can use whatever buffers you want, but it is hardly necessary (recently I've implemented an application that used ~300Mb VBO, it worked an all modern hardware seamlessly).

DikobrAz
  • 3,557
  • 4
  • 35
  • 53