In version 4.3+ the vao layout can be set independently from the VBO buffer which allows you to rebind the vbo without having to call vertexAttribPointer every time:
//in init
glBindVertexArray(vao);
glVertexAttribFormat(posAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, pos));
// set the details of a single attribute
glVertexAttribBinding(posAttrLoc, 0);
// which buffer binding point it is attached to
glEnableVertexAttribArray(posAttrLoc);
glVertexAttribFormat(normalAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, normal));
glVertexAttribBinding(normalAttrLoc, 0);
glEnableVertexAttribArray(normalAttrLoc);
glVertexAttribFormat(texAttrLoc, 2, GL_FLOAT, false, offsetof(Texture, tex));
glVertexAttribBinding(texAttrLoc, 1);
glEnableVertexAttribArray(texAttrLoc);
Note that there is no mention of any VBO during init, just the binding points. That binding point is then used during draw to specify which vbo to pull the vertex data from:
//draw
glBindVertexArray(vao);
foreach(mesh in meshes){
glBindVertexBuffer(0, mesh.vbo, mesh.vboOffset, sizeof(Vertex));
glBindVertexBuffer(1, mesh.texVbo, mesh.texVboOffset, sizeof(Texture));
// bind the buffer to the binding point
glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
//draw
}
In pre 4.3 you would create a VAO per mesh and per mesh call glVertexAttribPointer for each attribute:
glBindVertexArray(mesh.vao);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
glVertexAttribPointer (posAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, pos));
glEnableVertexAttribArray(posAttrLoc);
//...
Then during draw bind the per mesh vao before drawing it:
foreach(mesh in meshes){
glBindVertexArray(mesh.vao);
glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
}