Vertex Arrays in OpenGL - hls333555/OpenGL GitHub Wiki

Vertex arrays are a way to bind vertex buffers with a certain specification for layout. Here's what VAO is explained in Vertex Array Objects:

The Vertex Array Object (a.k.a VAO) is a special type of object that encapsulates all the data that is associated with the vertex processor. Instead of containing the actual data, it holds references to the vertex buffers, the index buffer and the layout specification of the vertex itself. The advantage is that once you set up the VAO for a mesh you can bring in the entire mesh state by simply binding the VAO. After that you can render the mesh object and you don't need to worry about all of its state. The VAO remembers it for you. If your application needs to deal with meshes whose vertex layout slightly differs from one another the VAO takes care of it also. Just make sure to set up the correct layout when you create the VAO and forget about it. From now on it "sticks" to the VAO and becomes active whenever that VAO is used.

For now, what we've done is we bind all the objects(program object, vbo, ibo) we have for one shader, one vertex buffer and one index buffer. If we have multiple objects(multiple vbos etc.), we will have to rebind everything we need for current draw every times(in the game loop):

// Bind shader and set up uniforms
glUseProgram(program);
glUniform4f(location, r, 1.f, 1.f, 1.f);

// Bind vertex buffer and set up the layout
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)0);

// Bind index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

VAOs are actually what contain the state. If you utilize VAOs properly, for example, make a different VAO for each piece of geometry of each draw call, then what you need to do is to bind the VAO, that's it! Because VAO will contain a binding between the vertex buffer(s) and that vertex layout.

Let's utilize VAO to rewrite the above code:

  • Add the following code before glfwCreateWindow() to use the core OpenGL profile:

    // Use OpenGL 3.3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    // Use core OpenGL profile which will not make VAO object 0 an object
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    

    If you press F5, an assert will be triggered like below as long as you wrap all gl functions with GLCALL():

    image

    This is because no VAO objects are found in the core OpenGL profile, which is stated in VertexArrayObject:

    The compatibility OpenGL profile makes VAO object 0 a default object. The core OpenGL profile makes VAO object 0 not an object at all. So if VAO 0 is bound in the core profile, you should not call any function that modifies VAO state. This includes binding the GL_ELEMENT_ARRAY_BUFFER with glBindBuffer.

  • To fix that, simply create a VAO:

    // Vertex array object
    unsigned int vao;
    // Generate vertex array object names
    glGenVertexArrays(1, &vao);
    // Bind a vertex array object
    glBindVertexArray(vao);
    

    When you run the program, everything should work fine now!

  • In fact, the following lines of code in the game loop are no longer needed since a VAO is created and bound and vertex information is linked to this VAO later:

    // Bind vertex buffer and set up the layout
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (const void*)0);
    

    Therefore, the above code can be replaced with the following line:

    // Bind vertex array
    glBindVertexArray(vao);