How general should vertex array objects be?

I'd like to plan ahead and avoid a major revision down the road. I'm having a hard time wrapping my head around a few (possibly conflicting) pieces of wisdom scattered around the internet.

This is what I could gather from a half a year of slowly reading specs and docs, building and abstracting away a somewhat structured piece of a game engine.

  • The more state changes the slower the execution (self evident)
  • VAO holds state for draw calls (for a simple bind -> draw)
  • VBOs are bound to a VAO using the attribute location from a shader program (glGetAttribLocation -> glVertexAttribPointer)
  • These arrays are enabled by location using glEnableVertexAttribArray

So for a single VAO, how many or what kinds of objects should it take care of? Should a single VBO contain many objects' e.g. normals and the program use offsets when drawing, or is having separate VBOs for each a viable option?

Also, since we enable the attribute array by location inside the shader program, are the VAO and the shader in some way connected?

Any pointers would be greatly appreciated!


1 Answer 1


In 4.3 onward (or with the ARB-vertex-attrib-binding extension) VAOs can change which buffers are used for pulling vertices from without needing to call glVertexAttribPointer.

This changes the render meshes loop to:


foreach(mesh: meshes){
    //bind mesh' uniform information:

    // bind vbos:
    glBindVertexBuffer(0, mesh.vbo, 0, sizeof(vertex));

    glDrawArrays(GL_TRIANGLES, 0, mesh.numVertices);
    // or for indexed:
    // glBindElementBuffer(mesh.ebo);
    // glDrawElements(GL_TRIANGLES, mesh.numIndices, GL_UNSIGNED_INT, 0);

This means that for each vertex layout there is one VAO to create during init. Usually 4 or so layouts are enough for a game using skeletal animation and shadow mapping. If you have more then adjust your asset pipeline to reduce them.

Pre 4.3 (and without the extension) you can use a vao per set of vbo buffers that get used and use the baseVertex to select a vertex offset.

Behind the scenes some hardware does software vertex pulling, so if the vertex layout changes the driver will need to patch the program. It's much better to keep to a limited set of vertex layouts.

It is better to have interleaved attributes. This improves cache performance.

  • \$\begingroup\$ So by interleaved you mean having vertices, texture coords and normals in the same buffer as [v1,t1,n1,v2,t2,n2...]? The cache performance improvement seems like a reasonable thing to expect! Is your indexed version replacing the glDrawArrays or both gl calls? Do you have any knowledge as to why the arrays are enabled using the attribute locations in the shader? \$\endgroup\$
    – Felix
    Mar 27, 2018 at 22:36
  • \$\begingroup\$ indexed is without glDrawArrays but with the bind call. \$\endgroup\$ Mar 27, 2018 at 22:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .