0
\$\begingroup\$

I'm trying to change my program to use VBOs instead of immediate rendering for performance reason. The rendering consists of thousands of hexagons, all of the same size/shape. Each hexagon has a different color, so I'm trying to figure out how to change the color of the VBO for each rendered hex. Here's the code I'm using right now:

private static final int NUM_VERTICES = 6;
private static final int VERTEX_SIZE = 2;
private static final int COLOR_SIZE = 3;

private int vboVertexHandle;
private int vboColorHandle;

// This is called once on initialization
private void initVbo() {
    DoubleBuffer vertexBuffer = BufferUtils.createDoubleBuffer(VERTEX_SIZE * NUM_VERTICES);
    FloatBuffer colorBuffer = BufferUtils.createFloatBuffer(COLOR_SIZE * NUM_VERTICES);
    for (Point vertex : WorldHandler.TILE_VERTICES) {
        vertexBuffer.put(new double[]{vertex.x(), vertex.y()});
        colorBuffer.put(new float[]{1f, 0f, 0f});
    }
    vertexBuffer.flip();
    colorBuffer.flip();

    vboVertexHandle = GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexHandle);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBuffer, GL15.GL_STATIC_DRAW);
    GL30.glBindVertexArray(0);

    vboColorHandle = GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboColorHandle);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colorBuffer, GL15.GL_STATIC_DRAW);
    GL30.glBindVertexArray(0);
}

// This is called thousands of times per frame
private void drawHex(Color color) {
    // Set up the vertex buffer
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexHandle);
    GL11.glVertexPointer(VERTEX_SIZE, GL11.GL_DOUBLE, 0, 0L);

    // Set up the color buffer
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboColorHandle);
    GL11.glColorPointer(COLOR_SIZE, GL11.GL_FLOAT, 0, 0L);

    GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
    GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);

    GL11.glDrawArrays(GL11.GL_POLYGON, 0, NUM_VERTICES);

    GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
    GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
}

Note that I'm using OpenGL in Java through LWJGL. One solution I found online is to create a color VBO at initialization for each tile, then access each one when rendering that tile. That would probably solve my problem, but it may be more expensive than I'd like considering the lookup time when there are potentially millions of hexes that are off-screen.

Is there anything else I'm doing that is glaringly wrong? Even with those solution I'm only getting ~20 fps which is obviously far lower than I'd like.

\$\endgroup\$
0
\$\begingroup\$

Have you considered creating a single vertex buffer that contains all of your hexagons? (Or if you have too many hexagons for a single buffer, chunking a large number of hexagons into shared buffers)

Generally as a rule, creating vertex buffers with a small number of vertices and making tons of draw calls per frame, are things that you're going to want to avoid from a performance perspective. It's better to batch things together.

A similar example would be a particle system. Ideally you'd probably have a single vertex buffer per particle system (or perhaps multiple particle systems per buffer if the number of particles is small). Creating lots of small buffers and drawing them separately is very inefficient.

As a general rule, GPUs are very good at drawing large numbers of triangles fast, so ideally you want to feed them large batches to work with (within reason, obviously). When you make a draw call, you ideally want to give it something substantial to feed on.

As for colouring, personally my starting point would be just to have per-vertex colours in the same buffer as the vertices, and only have a seperate buffer if I encountered problems with that approach

\$\endgroup\$
  • \$\begingroup\$ Thank you! So would that consist of just adding way more vertices to the buffer? And in that case, how would I go about modifying the buffer if I want to change which tiles are being drawn? \$\endgroup\$ – Lucas Pickering Apr 15 '17 at 3:05
  • \$\begingroup\$ Depends on our use case. If you're changing what's drawn because you're moving through the world, then I'd probably chunk the world and render all visible chunks (even if portions of them are off screen) . Bearing in mind that modern GPUs can take a lot of triangles being thrown at them. If your game is 2D then in all likelyhood you're unlikely to throw enough at it that it's going to slow down If your world is truly dynamic, then I'd probably just use a dynamic vertex buffer, lock it and draw to it every frame. It's still going to be faster than making a draw call for each hexagon. \$\endgroup\$ – Bryan Robertson Apr 15 '17 at 3:13
  • \$\begingroup\$ My knowledge of graphics is a bit out of date, but I think a lot of the rules I've picked up over the years still apply. If you can, try to batch up as much as you can in your draw calls, to improve parallelism. Communicating with the graphics card is (relatively speaking) very slow, but when it actually has a lot of data to chew through, then it can do that very quickly. If you have data that's static for a part of the world, stick it in a static vertex buffer. If it's dynamic, then use a dynamic buffer. \$\endgroup\$ – Bryan Robertson Apr 15 '17 at 3:18

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.