6
\$\begingroup\$

I'm trying to make a 2D Graphic engine for training me. I've actually made it with immediate draw and I've made the renderer outside (so I can switch between OpenGL and DirectX).

How can I manage Vertex Buffer Object and Vertex Array Object? I've made a geometry object, and I don't think VBO and VAO need to be here.

It is the work of my renderer to manage the scene? (Group object in a large VBO, hide object out of screen, Order object by transparency, …)

More explications on my architecture:

  • Spacial : Spacial element containing spacial elements (like a node).
  • Mesh : Object with a geometry and a material
  • Scene : Manage spacial element (like mesh) and lights.
  • Renderer : Draw the given scene (mesh and lights)

Where I should manage buffers (Index buffer, Vertex Object Buffer and Vertex Array Buffer)? In first, I started to put them in the Geometry class, but it seem obvious because a buffer can stock multiple Geometry object.

So, I'm thinking to put buffers in a buffer manager (in the scene object) -> Scene can manage meshes (order + static/dynamic to regroup them in buffers).

What do you think about that?

Thanks!

\$\endgroup\$
3
  • 4
    \$\begingroup\$ It's difficult to understand what you're asking here. Can you edit your question to be more specific? Until then - voting to close. \$\endgroup\$ Commented Apr 17, 2013 at 15:58
  • \$\begingroup\$ I've tried to add more explications, it sound difficult to be more specific :/. \$\endgroup\$
    – Dono
    Commented Apr 17, 2013 at 16:47
  • \$\begingroup\$ It may also be helpful to know what platforms you are targeting (PC/Mobile/PSN). You mention DirectX so I'm assuming a DirectX9 or greater PC in my answer. \$\endgroup\$
    – NtscCobalt
    Commented Apr 17, 2013 at 17:08

2 Answers 2

5
\$\begingroup\$

If this is for desktop OpenGL or OpenGL|ES 3 and you're doing a common 2D sprite-style engine, you won't have a lot of repeat geometry. Everything is quads. You only need a single vertex buffer and index buffer (describing a quad). Use instancing to put all the transformation matrices for your scene objects into a single buffer and then draw that single quad X times (where X is the number of sprites you're drawing) with a single draw call. No need for dynamic buffers, no need to store buffers with "sprites," etc. Even with a fairly complex multi-part sprite animation system, each part is typically just a single quad, all arranged in a tree. You can still render multiple sprites/parts with a single draw call.

Generalizing to 3D (and some more complex 2D needs), each mesh would store the VBO of its attributes and an index buffer. Your renderer would try to group these together to use instancing; that is, if you're drawing 20 copies of the same mesh, only call draw once but use instancing to make that draw call draw all 20 copies. In 2D, there may be some use for this for more complicated objects, like paths or shapes that you need to triangulate, though usually sprites are enough.

For older OpenGL support or OpenGL|Es 2 you can't use instancing. In this case, just keep a single "large enough" VBO for a decent number of sprites. When your scene draws, first insert a transformed quad into the buffer for each object. That is, transform the vertices of a standard (-1,-1),(+1,+1) quad on the CPU to get the world positions of the quad representing that object, then copy those vertices into the VBO (and update the index buffer too, of course). Then draw that single buffer. You may need to split up rendering if your buffer can only hold X objects but you have X+Y objects to draw. E.g., if your buffer can draw 1000 but you have 2456, you'd make three draw calls: one for the first 1000, another for the second 1000, and a third for the remaining 456. In your VBO building loop, just check if the buffer is full after adding each object, and if so, draw and flush the buffer.

Just remember to discard the buffer before reusing it that same frame using glBufferData(vbo_id, 0, NULL, GL_DYNAMIC_DRAW) otherwise you'll stall the pipeline (you can't update a buffer while the GPU is rendering from it). You that call or the newer GL API to discard buffers (I forgot what it was), not glDeleteBuffer, which is something else entirely (recreating a new VBO every time is much slower than discarding a buffers contents).

\$\endgroup\$
2
  • \$\begingroup\$ How do you handle texture switching in your OpenGL|Es 2 example where you add all transformed sprites to one large VBO? Also won't that be inefficient if the sprites are moving as you will have to update the VBO every frame? \$\endgroup\$
    – Nathan
    Commented Jun 17, 2013 at 8:20
  • \$\begingroup\$ You'll have to batch them separetly, or use a texture atlas (preferred). And no, updating a VBO with a few hundred/thousand sprites should not cause any noticeable performance degradation. The GPU/bus can handle a decent amount of streaming uploads as long as you're not being ridiculous about it. As always, test on your target hardware and make sure. \$\endgroup\$ Commented Jun 17, 2013 at 16:13
0
\$\begingroup\$

It depends on how large your buffers are going to be, their usage, and how you work with your shaders.

If you have large static buffers then you should really be grouping them with your mesh and then have your renderable nodes reference their mesh, but since you are talking about 2d I can't imagine this is going to be your style. For 3d meshes that makes a lot of sense though.

For 2d I personally would just create 1 giant dynamic usage buffer that holds enough for say 10k objects, so 10000x2x3 points assuming you are basically working with 2d sprites. Then just you could update sub-sections of that buffer which lines up to an object or the whole thing. This would mean that each renderable scene node would have something like a offset into the buffer.

It may not be efficient for updating and may be difficult due fragmentation and order dependent transparency but it would be pretty efficient for rendering if you could use texture lookups and render it all in a single shader with a single call. If transparency is a big issue you can just be lazy and use multiple layers - thus multiple buffers or calls - like they've done in 2d games for generations.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .