<p>VAOs are essentially 'plumbing' objects that help get data from your buffers into your vertex shader ready for drawing. On the GPU this is handled by the vertex fetch stage, so a VAO is basically just a bundle of vertex fetch state corresponding to a particular model.</p>

<p>You can think of it as a bundle of pointers, but with somewhat more complexity than CPU-side pointers. Since OpenGL buffers are just a blob of untyped bytes by default (that's why you get a void* when you map them), the VAO handles type-casting (to vec3 or whatever) when fetching the data. It also deals with the size of the data not necessarily matching the stride between consecutive elements, and makes sure that each data item (position, normal, uv, etc.) is transmitted to the correct 'channel' in the vertex shader input.</p>

<p>You can render without a VAO in legacy OpenGL, but this is generally more of a PITA, since you need to bind each vertex attribute separately each time you draw the object. Encapsulating all these bindings in a VAO lets you set them up once, then you have a 'plug and play' object that simply needs to be bound before a draw call, and all your vertex data will be ready to go.</p>

CC BY-SA 3.0
2017-11-20T07:08:19.690Z
2017-11-20T07:08:19.690Z
russ
<p>Buffer objects contain your vertex data. Vertex array objects tell OpenGL how to <em>interpret</em> that data. Without the VAO, OpenGL just knows that you suck some bytes into some buffers. The VAO says that "in this buffer, at byte offset X, is an array of 4-vector floats, and that data will be fed to attribute index Y."</p>

<p>They're state objects. VAOs are no more "magical" than this C++ data structure:</p>

<pre><code>struct VertexFormat
{
  bool enabled = false;
  int attribute_index;
  VertexFormatType data_type; //Is f32, f64, or int32.
  int num_components = 4;
  bool normalized = false;
  GLenum type;
  int binding;    //The `bindings` index this attribute gets its data from.
  intptr_t offset;
};

struct VertexBufferBinding
{
  BufferObject buffer;
  intptr_t offset;
  intptr_t stride;
  int instancing;
};

struct VertexArrayObject
{
  VertexFormat formats[16];
  VertexBufferBinding bindings[16];
};
</code></pre>

<p>The fields of <code>VertexFormat</code> are specified by the <code>glVertexAttrib*Format</code> or <code>glVertexAttrib*Pointer</code> functions. In the case of the latter, it also specifies the corresponding <code>VertexBufferBinding</code> data.</p>

<p>Note that <code>VertexBufferBinding</code> stores a buffer object. That's where that binding point reads its data.</p>

<p>This structure is not magical; it simply explains how to read vertex data from its associated buffers.</p>

CC BY-SA 3.0
2017-11-20T16:19:54.260Z
2017-11-20T16:19:54.260Z
Nicol Bolas
<p>tl;dr The vao caches the calls to <code>glVertexAttribPointer</code> et. al.</p>

<p>Every call to <code>glVertexAttribPointer</code>, <code>glEnableVertexAttribArray</code> and the binding of <code>gl_Element_Array</code> will store the parameters into the currently bound vao. In the case of <code>glVertexAttribPointer</code> it will also store the current binding to <code>GL_VERTEX_ARRAY</code> in the vao.</p>

<p>This is a major help when drawing a lot of meshes because then the render loop turns from</p>

<pre><code>void drawMesh(Mesh[] meshes){
    foreach(mesh in meshes){        
        glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
        glVertexAttribPointer(posAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, pos));
        glVertexAttribPointer (normalAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, normal));
        //...
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);

        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
    }
}
</code></pre>

<p>into </p>

<pre><code>//done once per mesh on load
void prepareMeshForRender(Mesh mesh){
    glBindVertexArray(mesh.vao);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);

    glVertexAttribPointer (posAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, pos));//will associate mesh.vbo with the posAttrLoc
    glEnableVertexAttribArray(posAttrLoc);

    glVertexAttribPointer (normalAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, normal));
    glEnableVertexAttribArray(normalAttrLoc);

    //...

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo); //this binding is also saved.
    glBindVertexArray(0);
}

void drawMesh(Mesh[] meshes){
    foreach(mesh in meshes){        
        glBindVertexArray(mesh.vao);
        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
    }
}
</code></pre>

<p>This means a lot less calls and the driver can do some optimizations because it knows which vertex formats will be used. (some hardware has to do software vertex pulling so suddenly having a new format will require a patch of the vertex shader).</p>

<p>In version 4.3 (or with extension ARB_separate_attrib_format) there is a new way to bind the vertex attributes where the vao holds the format separately from the buffer binding to help exactly the above mentioned hardware: </p>

<pre><code>//accessible constant declarations
constexpr int vertexBindingPoint = 0;
constexpr int texBindingPoint = 1;// free to choose, must be less than the GL_MAX_VERTEX_ATTRIB_BINDINGS limit

//during initialization
glBindVertexArray(vao);

glVertexAttribFormat(posAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, pos));
// set the details of a single attribute
glVertexAttribBinding(posAttrLoc, vertexBindingPoint);
// which buffer binding point it is attached to
glEnableVertexAttribArray(posAttrLoc);

glVertexAttribFormat(normalAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, normal));
glVertexAttribBinding(normalAttrLoc, vertexBindingPoint);
glEnableVertexAttribArray(normalAttrLoc);

glVertexAttribFormat(texAttrLoc, 2, GL_FLOAT, false, offsetof(Texture, tex));
glVertexAttribBinding(texAttrLoc, texBindingPoint);
glEnableVertexAttribArray(texAttrLoc);

//...
</code></pre>

<p>Then during draw you keep the vao bound and only change the buffer bindings.</p>

<pre><code>void drawMesh(Mesh[] mesh){
    glBindVertexArray(vao);

    foreach(mesh in meshes){
        glBindVertexBuffer(vertexBindingPoint, mesh.vbo, mesh.vboOffset, sizeof(Vertex));
        glBindVertexBuffer(texBindingPoint, mesh.texVbo, mesh.texVboOffset, sizeof(Texture));
        // bind the buffers to the binding point

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);

        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
        //draw
    }
}
</code></pre>

<p>note: code sourced from now defunct docs.SO article on it <a href="https://gist.github.com/ratchetfreak/be5d870396c6e43af3372344001e5339" rel="noreferrer">cached copy available here</a></p>

CC BY-SA 3.0
2017-11-20T10:33:14.170Z
2017-11-20T10:33:14.170Z
ratchet freak
<p>Before I get downvoted. I am not asking how to use them, I know how to use them. I am trying to understand what they are. For example, an array is actually a contiguous section of memory, a linked list is actually just a clever way of using memory addresses, a 3D array is actually just a 1D array being used in a clever fashion...</p>

<p>Under that logic, VBO's are sections of GPU RAM that contain rendering data. They are thus "arrays". But then what is a VAO? My current understanding is that they are magical "boxes" that somehow store machine state information for a set of VBO's, but what are they actually?</p>

<p>Because for example, as far as I know, you MUST bind the VBO's under a VAO to get rendering output, if you just bind the VAO you won't get outpt, so what is their purpouse?</p>

CC BY-SA 3.0
2017-11-20T10:06:30.390Z
_you MUST bind the VBO's under a VAO to get rendering output, if you just bind the VAO you won't get outpt._ That's not true. You can bind dummy VAO without attached VBOs and still dispatch drawcall.
mdkdy
<opengl><vertex-buffer-object><buffers>
What is an OpenGL VAO in a nutshell?
Makogan
# What is an OpenGL VAO in a nutshell?

(Asked by: username_0 on 2017-11-19)

Before I get downvoted. I am not asking how to use them, I know how to use them. I am trying to understand what they are. For example, an array is actually a contiguous section of memory, a linked list is actually just a clever way of using memory addresses, a 3D array is actually just a 1D array being used in a clever fashion...

Under that logic, VBO's are sections of GPU RAM that contain rendering data. They are thus "arrays". But then what is a VAO? My current understanding is that they are magical "boxes" that somehow store machine state information for a set of VBO's, but what are they actually?

Because for example, as far as I know, you MUST bind the VBO's under a VAO to get rendering output, if you just bind the VAO you won't get outpt, so what is their purpouse?

**Tags:** opengl, vertex-buffer-object, buffers

> **Comments:**
> **username_1**: _you MUST bind the VBO's under a VAO to get rendering output, if you just bind the VAO you won't get outpt._ That's not true. You can bind dummy VAO without attached VBOs and still dispatch drawcall.  

---

## 3 answers

### Answer by username_4 on 2017-11-20. Score: 9 | Accepted answer

tl;dr The vao caches the calls to `glVertexAttribPointer` et. al.

Every call to `glVertexAttribPointer`, `glEnableVertexAttribArray` and the binding of `gl_Element_Array` will store the parameters into the currently bound vao. In the case of `glVertexAttribPointer` it will also store the current binding to `GL_VERTEX_ARRAY` in the vao.

This is a major help when drawing a lot of meshes because then the render loop turns from

```
void drawMesh(Mesh[] meshes){
    foreach(mesh in meshes){        
        glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
        glVertexAttribPointer(posAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, pos));
        glVertexAttribPointer (normalAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, normal));
        //...
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);

        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
    }
}

```

into

```
//done once per mesh on load
void prepareMeshForRender(Mesh mesh){
    glBindVertexArray(mesh.vao);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);

    glVertexAttribPointer (posAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, pos));//will associate mesh.vbo with the posAttrLoc
    glEnableVertexAttribArray(posAttrLoc);

    glVertexAttribPointer (normalAttrLoc, 3, GL_FLOAT, false, sizeof(Vertex), mesh.vboOffset + offsetof(Vertex, normal));
    glEnableVertexAttribArray(normalAttrLoc);

    //...

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo); //this binding is also saved.
    glBindVertexArray(0);
}

void drawMesh(Mesh[] meshes){
    foreach(mesh in meshes){        
        glBindVertexArray(mesh.vao);
        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
    }
}

```

This means a lot less calls and the driver can do some optimizations because it knows which vertex formats will be used. (some hardware has to do software vertex pulling so suddenly having a new format will require a patch of the vertex shader).

In version 4.3 (or with extension ARB\_separate\_attrib\_format) there is a new way to bind the vertex attributes where the vao holds the format separately from the buffer binding to help exactly the above mentioned hardware:

```
//accessible constant declarations
constexpr int vertexBindingPoint = 0;
constexpr int texBindingPoint = 1;// free to choose, must be less than the GL_MAX_VERTEX_ATTRIB_BINDINGS limit

//during initialization
glBindVertexArray(vao);

glVertexAttribFormat(posAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, pos));
// set the details of a single attribute
glVertexAttribBinding(posAttrLoc, vertexBindingPoint);
// which buffer binding point it is attached to
glEnableVertexAttribArray(posAttrLoc);

glVertexAttribFormat(normalAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, normal));
glVertexAttribBinding(normalAttrLoc, vertexBindingPoint);
glEnableVertexAttribArray(normalAttrLoc);

glVertexAttribFormat(texAttrLoc, 2, GL_FLOAT, false, offsetof(Texture, tex));
glVertexAttribBinding(texAttrLoc, texBindingPoint);
glEnableVertexAttribArray(texAttrLoc);

//...

```

Then during draw you keep the vao bound and only change the buffer bindings.

```
void drawMesh(Mesh[] mesh){
    glBindVertexArray(vao);

    foreach(mesh in meshes){
        glBindVertexBuffer(vertexBindingPoint, mesh.vbo, mesh.vboOffset, sizeof(Vertex));
        glBindVertexBuffer(texBindingPoint, mesh.texVbo, mesh.texVboOffset, sizeof(Texture));
        // bind the buffers to the binding point

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);

        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
        //draw
    }
}

```

note: code sourced from now defunct docs.SO article on it [cached copy available here](https://gist.github.com/username_4/be5d870396c6e43af3372344001e5339)


---

### Answer by username_2 on 2017-11-20. Score: 5

VAOs are essentially 'plumbing' objects that help get data from your buffers into your vertex shader ready for drawing. On the GPU this is handled by the vertex fetch stage, so a VAO is basically just a bundle of vertex fetch state corresponding to a particular model.

You can think of it as a bundle of pointers, but with somewhat more complexity than CPU-side pointers. Since OpenGL buffers are just a blob of untyped bytes by default (that's why you get a void\* when you map them), the VAO handles type-casting (to vec3 or whatever) when fetching the data. It also deals with the size of the data not necessarily matching the stride between consecutive elements, and makes sure that each data item (position, normal, uv, etc.) is transmitted to the correct 'channel' in the vertex shader input.

You can render without a VAO in legacy OpenGL, but this is generally more of a PITA, since you need to bind each vertex attribute separately each time you draw the object. Encapsulating all these bindings in a VAO lets you set them up once, then you have a 'plug and play' object that simply needs to be bound before a draw call, and all your vertex data will be ready to go.


---

### Answer by username_3 on 2017-11-20. Score: 2

Buffer objects contain your vertex data. Vertex array objects tell OpenGL how to *interpret* that data. Without the VAO, OpenGL just knows that you suck some bytes into some buffers. The VAO says that "in this buffer, at byte offset X, is an array of 4-vector floats, and that data will be fed to attribute index Y."

They're state objects. VAOs are no more "magical" than this C++ data structure:

```
struct VertexFormat
{
  bool enabled = false;
  int attribute_index;
  VertexFormatType data_type; //Is f32, f64, or int32.
  int num_components = 4;
  bool normalized = false;
  GLenum type;
  int binding;    //The `bindings` index this attribute gets its data from.
  intptr_t offset;
};

struct VertexBufferBinding
{
  BufferObject buffer;
  intptr_t offset;
  intptr_t stride;
  int instancing;
};

struct VertexArrayObject
{
  VertexFormat formats[16];
  VertexBufferBinding bindings[16];
};

```

The fields of `VertexFormat` are specified by the `glVertexAttrib*Format` or `glVertexAttrib*Pointer` functions. In the case of the latter, it also specifies the corresponding `VertexBufferBinding` data.

Note that `VertexBufferBinding` stores a buffer object. That's where that binding point reads its data.

This structure is not magical; it simply explains how to read vertex data from its associated buffers.


---

