4
\$\begingroup\$

I am just getting my head wrapped around modern OpenGL. Let's say that I would like to draw 10 objects, how would I structure that? Would I call glDrawElements(...) in a for loop 10 times?

void render() {
  shader.bind(); // calls glUseProgram
  bindVAO();     // calls glBindVertexArray

  for(int i = 0; i < 10; i++) {
    glDrawElements(....)
  }

  unbindVAO;
  shader.unbind();
}
\$\endgroup\$
  • \$\begingroup\$ I apologize, but I don't see a specific question here. "How do I use OpenGL" isn't very specific. Which piece are you stumped by? \$\endgroup\$ – Sean Middleditch Jul 13 '15 at 8:42
  • \$\begingroup\$ Check out this (slides) presentation. It should give you an idea of how to set up your draw loops in modern OpenGL. \$\endgroup\$ – Soapy Jul 13 '15 at 10:46
  • 1
    \$\begingroup\$ @Soapy thank you very much, that was a very detailed talk and more than solved the issues that I was having but prevented me from going down some crazy rabbit holes as well. Thanks again! \$\endgroup\$ – sean Jul 13 '15 at 15:28
6
\$\begingroup\$

Maybe.

Broadly, there are two ways to categorize geometry (triangles you will render):

  • either the geometry is static, and all sits in the same fixed place in the world, or the geometry is dynamic and either moves around in the world or otherwise animates
  • the geometry is defined according to a specific vertex format (this geometry has a position, normal, and four texture coordinates, that geometry has a position, color, and one texture coordinate).

In practice you'll end up with a mixed bag of all kinds of geometry, and it will fall along various points in the spectrum defined by those categories. Where it falls determines how you can most-efficiently render it -- although keep in mind that the most objectively efficient approach is not always the overall best idea.

Geometry that differs in vertex format generally needs to be contained within its own buffer, and you'll generally need at least one buffer for each kind of vertex format, so you'll generally need at least one set of binding setup and glDrawElements calls for each of those buffers.

Geometry that is totally static, or which all can share the same bind setup for shaders, uniforms (world transform et cetera), can all be lumped into one large buffer and rendered in a single draw call, even if that buffer contains what you'd logically consider many objects. For example, in an RTS game that has a bunch of rocks and other ground clutter which is purely decorative and static, you could put all the rocks in one buffer and render them with one call.

Geometry that is dynamic, and must be updated or animated or otherwise use different bind setup for uniforms, generally will need one draw call for every set of distinct bind setup; note that multiple objects make still share a draw call here, in some cases. You may or may not be able to get away with storing all these objects in one buffer, as well.

You're always going to have to make a choice between various methods depending on the needs of your game. For example, in my aforementioned "rocks" example, it may still be worth breaking the rocks into multiple buffers if your map is large enough so you don't bother rendering objects that aren't even remotely visible.

When you are just learning, it is better to start off simpler. A default of "one buffer and one draw call" per object is not the most efficient but it should be efficient enough for quite a while for early forays into the world of OpenGL; once you are more comfortable you can start to explore ways in which you can divorce buffers and draw calls from that 1:1 relationship with logical objects.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.