yzsolt
yzsolt

Reputation: 23

GL_ARB_vertex_attrib_binding and indexed drawing

I'm experimenting with rendering a Minecraft-like world in OpenGL. The world is split into chunks (each of them containing N^3 blocks) and these chunks get rendered each frame.

Currently I'm using one VAO per chunk. I always thought this is a bit odd, since every chunk uses the same vertex format - why can't I use a single VAO, and then draw each chunk by changing the index and vertex buffer bindings?

Recently I came across the GL_ARB_vertex_attrib_binding extension which is in core 4.3 and seems to address this problem - VAO and VBO bindings can be now separated. But there is no mention about index buffers bindings, which are still part of the VAO state, making the extension useless with indexed rendering. The only thing I can think of is updating the bound index buffer's contents for each chunk and vertex buffer binding change when rendering, but it makes little sense.

My question is, do I understand what the extension does correctly? If I do, is there another method I can use to avoid per-chunk VAOs without merging the per-chunk index buffers into one big IBO (as it would needlessly complicate chunk streaming management)?

Upvotes: 2

Views: 615

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473537

You have... partly misunderstood the purpose of vertex attrib binding.

Yes, it creates separation between the vertex format and the buffer bindings. However, this separation is only at the level of the API. That is, you have functions like glVertexAttribFormat that set the format, and glBindVertexBuffer that sets the buffers.

But all of these functions still modify VAO state.

However, there is no need to change VAOs just because you're changing the state within VAOs. The reason that vertex attrib binding exists is because changing vertex format state is expensive. Whereas changing buffer binding state is not (or at least, it's not as expensive). So it's cheaper to call glBindVertexBuffer than it is to call glVertexAttribFormat.

That's why the feature exists: so that you're not making an expensive call just to perform a cheap operation.

So what you want to do is fine; you can just bind the VAO, then make the glBindVertexBuffer and glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) calls as you see fit. Yes, these will modify the state in the VAO, but so what? So long as you don't touch the vertex format in the VAO, you're fine.

That being said, if your goal is performance, you probably shouldn't be changing buffer binding state per chunk anyway. Put all of your chunks (or at least, large groups of them) into different regions of the same buffer. All of the indices for the groups of chunks should likewise live in a single buffer. The indices should be relative to the start of that chunk's data, so you ought to be able to use 16-bit GLshort indices.

When it comes time to render a particular chunk, use BaseVertex-based rendering to select which individual chunk you want to render with. The base_vertex is used to provide an offset to the index. This offset should be based on the maximum size of the chunk.

This way, to render with a group of chunks, you minimize the number of buffer binding operations you do. And therefore minimize the number of state changes between draw calls.

Upvotes: 4

Related Questions