GL_TRIANGLE_STRIP With Predefined Strip Length

In a voxel world (where the environment is composed of blocks) each block face is composed of two triangles. This means that 6 vertices are required to create each block face, and two vertices in triangle A share the exact same data (position, normal, texture ID, etc) as two of the vertices in triangle B.

I attempted to remove this redundant data by changing from GL_TRIANGLES to GL_TRIANGLE_STRIP and providing 4 vertices per block face, but I found I had to insert two degenerate vertices between each block face, meaning I’m back at 6 vertices per block face.

Is it possible to tell OpenGL that each strip in a GL_TRIANGLE_STRIP is composed of exactly 4 vertices, meaning that degenerate vertices are not needed?

// Old, draws 1000 block faces
Gl.BindVertexArray(VAO);
Gl.DrawArrays(PrimitiveType.Triangles, 0, 6000);

// New, draws 1000 block faces
Gl.BindVertexArray(VAO);
Gl.TriangleStripLength(4);
Gl.DrawArrays(PrimitiveType.TriangleStrip, 0, 4000);

You can use primitive restarting to render multiple strips/loops/polygons with a single draw call. See glEnable for GL_PRIMITIVE_RESTART or GL_PRIMITIVE_RESTART_FIXED_INDEX.

However, you’re better off using GL_TRIANGLES. Only the vertex index needs to be duplicated. You only need one copy of the data for each vertex and the vertex shader will only be executed once for each vertex (assuming that the triangles in each pair are consecutive in the index array).

1 Like

Thank you, I will look into primitive restarting.

I’m hesitant to use an index buffer as my vertices are the same size as an integer in the index buffer (4 bytes), meaning for a block face I’ll have 4 vertices + 6 indices = 40 bytes total, up from 24.

I’ve looked into geometry shaders, however they seem to have issues with rewriting the produced geometry back to memory, before passing them to the fragment shader.

Mesh shaders look perfect for this task as I can send one vertex to the mesh shader and produce two triangles from it. Unfortunately they are only available on newer NVIDIA cards and some AMD cards but I’d love to see the performance difference.

I doubt this.

You’ve said that your vertices contain position, normal, texture id, etc, so they’re going to be nearer 32 bytes than 4.

1 Like

Is it possible to associate an index buffer object with multiple VBOs? If so, I could create an index buffer with the data:

0, 1, 2, 3, 0xFFFF, 4, 5, 6, 7, 0xFFFF, 8, 9, 10, 11, 0xFFFF, etc...

and then re-use it in multiple draw calls? For example if I had three VBOs with lengths 1000, 2000 and 3000:

// Bind the index buffer, which will be used to render each VBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboHandle);

glBindVertexArray(vao0);
// Divide by 4 to get face count, multiply by 5 to get the amount of indices
glDrawElements(GL_TRIANGLE_STRIP, 1000 / 4 * 5, GL_UNSIGNED_INT, NULL);

glBindVertexArray(vao1);
glDrawElements(GL_TRIANGLE_STRIP, 2000 / 4 * 5, GL_UNSIGNED_INT, NULL);

glBindVertexArray(vao2);
glDrawElements(GL_TRIANGLE_STRIP, 3000 / 4 * 5, GL_UNSIGNED_INT, NULL);

It’s true :slight_smile: I’m rendering chunks of 32x32x32 voxels, where each vertex is composed of:

  • 6 bits for X position
  • 6 bits for Y position
  • 6 bits for Z position
  • 6 bits for texture ID
  • 5 bits for brightness
  • 3 bits for normal (a value of 0 represents Y-, 1 represents Y+, 2 represents X-, and so on)

You can use the same index buffer for multiple draw calls. If you’re using VAOs, you can bind the same index buffer in multiple VAOs.

If you’re using a single index buffer, it doesn’t really matter if it’s 20% larger (i.e. GL_TRIANGLES with 6 indices per triangle versus GL_TRIANGLE_STRIP with 5). If there’s any overhead for using primitive restarting, using it with such small primitives will exacerbate it.

1 Like

Fair enough.

But 32x32x32 is 32768, which fits very nicely in GL_UNSIGNED_SHORT indices, so you don’t need 4 bytes per index; 2 is sufficient.

1 Like

Perfect, thank you!

That’s a great point I didn’t consider, thank you.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.