14
\$\begingroup\$

I'm just getting started with OpenGL, and I'm attempting to use it to create a 2D game. In this game, I have a hexagonal grid made up of a very large variety of differently-colored hexagons. As a newbie OpenGL programmer, I see two ways of drawing this grid:

  1. Using a vertex buffer with the data for a single hexagon, then using a uniform offset value and iterating on the CPU to draw the same program many times until I have a grid.
  2. Creating a singular very large pre-calculated vertex buffer that draws all the hexagons in a single call.

What's the most efficient method? Is there a better way of doing this?

\$\endgroup\$
  • \$\begingroup\$ Your pre-calculated vertex buffer only needs to extend past the screen by one hexagon, you can then fake it by scrolling smoothly until you go a full hexagon and then "warping" back, as for the colors in that scenario, you can keep a 2D texture on the GPU, read it in the vertex shader, and flat interpolate it into the fragment shader. \$\endgroup\$ – MickLH Sep 4 '13 at 23:10
  • \$\begingroup\$ Passes usually refer to a situation where one render operation relies on the results of a prior operation. What you are asking about in this question is actually related to reducing the number of draw calls within a single pass. I know it sounds pedantic, but it is very important to understand the difference otherwise multi-pass algorithms will not make a lot of sense ;) \$\endgroup\$ – Andon M. Coleman Sep 5 '13 at 0:22
  • \$\begingroup\$ @AndonM.Coleman Hmm, thanks, I'm clearly not familiar with graphics terminology. So, in this case, how would I describe it? Multiple shader/program calls? \$\endgroup\$ – Alexis King Sep 5 '13 at 0:32
  • \$\begingroup\$ You can immediately tell that this is a single-pass algorithm because there is no order dependency; you can draw these hexagons in any order and still get the same result. You might take multiple draw calls to supply OpenGL with the data required to render them, but OpenGL is effectively free to draw them all in parallel since there are no dependencies. If it were multi-pass, then hexagon B might require the result of hexagon A before it could be drawn, or you might need to draw the same hexagon multiple times and combine the result. \$\endgroup\$ – Andon M. Coleman Sep 5 '13 at 0:35
9
\$\begingroup\$

There are indeed a few ways to make such a grid.

The most efficient way would be instancing. This way you make your hexagon only once in a VBO, and render this a hundred, a thousand or a million times. You can do it manually using shaders with uniforms as you said in point 1, but there also is a built-in OpenGL functionality for it. For that, take a look at glDrawElementsInstanced.

Note that instancing is only faster than other methods if you draw more than a certain amount of instanced objects. For example drawing 300 can be faster using 1 big VBO, but drawing 2 million can be faster if you use instanced rendering.

If you use instanced rendering you can send per-object data using Attribute Divisors. In your case you would want to send the position and the color.

A good tutorial on instanced rendering: click

Really the best way is to try both methods, and check the amount of milliseconds it takes to draw 1 frame. This way you also learn both ways, which is always good.

Also note that instanced rendering is a modern OpenGL functionality, and that you will have to use shaders to use it. But it's always best to learn it the correct way from the beginning.

\$\endgroup\$
  • 2
    \$\begingroup\$ Instancing is not necessarily the most efficient; in many implementations I've seen profiles of, the instancing support was tacked on for conformance but slower than individually drawing many objects (indeed, it was likely just a poorly implemented loop in the driver doing that very thing). It's an option, and a good one, but one should be careful to profile and test on target OS/hardware before making any assumptions about "most efficient." \$\endgroup\$ – Sean Middleditch Sep 5 '13 at 0:25
  • \$\begingroup\$ Agreed. I have seen different performances on Windows / Linux and Ati / nVidia for example. Thanks for the addition. \$\endgroup\$ – Basaa Sep 5 '13 at 7:09
  • 1
    \$\begingroup\$ In fact. If you draw multiple combined meshes within a single vbo (that share the same space). No way instancing could be faster. The problem with instancing is: vertices are not parallel calculated cross instance. It only eliminates the gpu/cpu/gpu sync/drawcall. So it's faster to draw one vertex buffer containing 1000 spheres than drawing 1000 spheres with hardware instancing. (no frustum culling/object distance detail optimization involved) \$\endgroup\$ – Jeroen van Langen Mar 8 '17 at 14:06
3
\$\begingroup\$

Method 1 is simpler to code and will be fine as long as you don't have too many hexagons in view at once. You might want to stick with this since you're new to OpenGL, to avoid putting too much complexity on your plate at once.

If there are a large number of hexagons (like several hundred or over a thousand) in view at once, a lower-overhead method would be necessary to avoid the CPU overhead of doing so many individual draws. Method 2 would work for this, or even better, use instancing. I'd expect instancing to be faster than method 2, or certainly no worse, since you only have to update a buffer of per-instance data rather than a (much larger) buffer of vertex data for all the instances.

\$\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.