vertex array and buffer objects

Can someone explain in more simple terms what VAO and BO mean. I read documentation but some things are still unclear. For example, VAO can bundle multiple buffer objects, that can be processed by only one vertex and fragment shader, so does it mean that VAO is the best logical representation of one geometric object (e.g. one VAO for terrain and one for plane, in flight simulator game)? Does always to one VAO can be attached only one shader?

Sorry for stupid questions, I still can’t get it.

Don’t think about it that way.

A VBO is data. That’s all it is, just a chunk of data and the buffer object API just gives you ways to allocate that chunk of data and put values into it. It has absolutely no special meaning beyond that.

In old OpenGL you would then make a bunch of calls that define how that data is used. That’s all that a VAO is; it takes that bunch of calls, saves them off, and gives you a way of restoring those saved off calls.

So a VBO is data and a VAO is state. That’s all. Neither define how you ought to design your code around them.

Thank you for you answer, I understood that VBO is just a data, since one can put anything there using glBufferData or glBufferSubData. But how exactly VAO is used? I’m digging through the one of the introductory books and first examples can work without even initialisation of VAO by glGenVertexArrays, that is I erased this line and glBindVertexArray also, and nothing have changed. Could you please give some simple example when it really matters?

VAO just describes how data gets drawn from which buffers, and how frequent they are sent to the shaders. VBO is just data, you cant draw anything with that, you first have to describe to GL how you want to send the data to the shaders, calls like:

glVertexAttribPointer(…)
glEnableVertexAttribArray(…)
glDisableVertexAttribArray(…)
glVertexAttribDivisor(…) // for instanced rendering

are saved in a VAO, once you have stored them in a VAO, you dont have to call them anymore anywhere, just bind VAO to set its state, unbind the VAO (which means bind VAO = 0) to restore defaults

rendering stuff looks then somehow like that:


glUseProgram(program);
glBindVertexArray(VAO);

/* set some uniforms */
mat4 MVP = ...
glUniformMatrix4fv(location, 1, GL_FALSE, value_ptr(MVP));

/* make some draw calls */
glDrawElements(...mesh1);
glDrawElements(...mesh2);
glDrawElements(...mesh3);

glBindVertexArray(0);
glUseProgram(0);

https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object

A VAO is used to store the state relating to vertex attributes. Calls to glVertexAttribPointer(), glEnableVertexAttribArray(), and glVertexAttribDivisor() (amongst others) save their parameters in the currently-bound VAO rather than as part of the context. The current GL_ELEMENT_ARRAY_BUFFER binding is also stored in the currently-bound VAO (other buffer bindings are stored in the context). Rendering obtains vertex attribute values using the state stored in the currently-bound VAO.

See the section entitled “State Tables” in the specification for the precise details of what state is stored in VAOs. In the OpenGL 4.6 specification, the information is in tables 23.3 and 23.4.

VAOs were added in OpenGL 3.0. In earlier versions, the vertex attribute array state was part of the context. In the compatibility profile, a default VAO with a name (ID) of zero exists and is bound by default, so if you only ever use a single VAO, there’s no need to explicitly create and bind a VAO unless you’re using the core profile.