Understand the relationship between glVertexAttribPointer, glEnableVertexAttribArray, VAO, VBO

[After OpenGL] abandons the functions and pipelines of the glEnable(), glColor(), glVertex(), and glEnable() processes, a new method is needed to pass data to the Graphics Card to render the geometry. We can use VBO, in Version 3+ we can use Vertex Array Object-VAO, VAO is an object that contains one or more Vertex Buffer Objects. The VBO is a memory buffer in the Graphics Card, which is used to store vertex information, color information, normal information, texture coordinate information and index information, etc.

VAO stores several object information linearly in the Graphics Card, instead of sending the data we need to the Graphics Card before. This is also the way that Direct3D works without immediate mode, which means that the application does not need to transmit data to the Graphics Card. to obtain higher performance. A VAO has multiple VBOs, as shown in the following figure:

A VAO is a container that wraps all the state that can be set by glVertexAttribPointer and some other functions. When using a VAO, all the state specified by a glVertexAttribPointer call will be stored in the current VAO. glVertexAttribPointer specifies the   data format and position of the vertex attribute array whose index value is index when rendering. There is also a context between them, and there is only one activated VAO, and the VBOs created after the VAO belong to the VAO. The associated VBO data is specified by fetching the currently active buffer object offset.

To put it bluntly, VAO can be imagined as a big bottle; VBO is a memory buffer used to save vertex information, color information, normal information, texture coordinate information and index information, etc.; after glVertexAttribPointer is called, it is equivalent to putting more A VBO is thrown into the specified bottle (the VAO created in the most recent code), and then the bottle cap is tightly closed and not opened, call glEnableVertexAttribArray (the parameter is the same as the first parameter of the glVertexAttribPointer function) , please refer to “Understanding the first parameter of glVertexAttribPointer” ), the bottle cap is opened, and after calling drawing functions such as: glDrawArrays, glDrawElements, glDrawElementsBaseVertex, etc., it is equivalent to the data stored in multiple VBOs in the bottle. , once and sent to the GPU for drawing. Using VBO and VAO saves the communication time between CPU and GPU when drawing multiple objects, and improves rendering performance.

It is important to note that I found this sentence on stackoverflow, if your VAO can’t draw something:
If you’re on OpenGL-4 core, you need to create a VAO first, otherwise nothing will draw

Note: Both VAOs and VBOs are used to store vertex information and send this information to the vertex shader . As for what vertices and vertex [shaders are] , I won’t say much here. Readers who don’t understand can use CSDN on their own.

B of VBO means Buffer , which is used to store vertex data; A of VAO means Array , but I think it is better to understand the meaning of Attribute (attribute) , which means the attribute of Buffer (VBO) .

That is, we use VBO to store data, and use VAO to tell the computer what attributes and functions these data have.

1. The role of VBO

VBO is a bridge for transferring information between CPU and GPU . We store data into VBO (this step is executed in CPU) , and then VBO will automatically send data to GPU .

The step of sending to the [GPU] does not require any human operation, and the user is only responsible for storing data into the VBO . as follows:

However, to the GPU , the VBO is just a bunch of numbers, how to interpret them? This is where the VAO is needed .

2. The role of VAO

VBO is to pass vertex data to GPU, then VAO is to explain vertex data to GPU. Some readers will be surprised that vertex data is nothing more than three-dimensional coordinates, three in a group, and it is passed on, so why do you need to explain it? So let’s look at the data in the following VBO:

float buffer = {
     // vertex coordinates (group of 3) // vertex color (group of 3) // texture coordinates (group of 2) 
    0.5f ,   0.5f , 0.0f ,                 1.0f , 0.0f , 0.0 f ,                1.0f , 1.0f ,
     0.5f , -0.5f , 0.0f ,                 0.0f , 1.0f , 0.0f ,                1.0f , 0.0f ,
    -0.5f , -0.5f , 0.0f ,                 0.0f ,0.0f , 1.0f ,                0.0f , 0.0f ,
    -0.5f ,   0.5f , 0.0f ,                 1.0f , 1.0f , 0.0f ,                0.0f , 1.0f
};
//The above data is only made up for this blog post and has no practical significance

It can be seen from the above data that the vertex data is not just three-dimensional coordinates in groups of three!

If we pass the above [buffers] to the VBO , and the VBO sends them to the GPU.

However , the vertex [shader does] n’t know how to interpret these numbers, whether to put them in groups of 3, first in groups of 3, then in groups of 2, or in groups of 3, 2, or 3?

The GPU doesn’t know that.

This requires the participation of the VAO, which is responsible for telling the GPU that the information in the VBO should be grouped together. The following program stores the description of the data in the VBO into a VAO:

//vertex coord
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

The above program seems to have three sections ( glVertexAttribPointer()+ glEnableVertexAttribArray()is a section), but they all exist in the same VAO . glVertexAttribPointer()(The role of the function and the function will not be introduced here glEnableVertexAttribArray(). Readers who do not understand can check it online.)

In some complex OpenGL programs, there may be multiple VBOs, but only one VAO . So, how to use one VAO to interpret multiple VBOs ?

3. One VAO and multiple VBOs

In an OpenGL program, there may be multiple VBOs, but only one VAO . So, how to use one VAO to interpret multiple VBOs ?

This involves the contextual knowledge of OpenGL: a complete [OpenGL] program is equivalent to a container. When we use VAO and VBO , we need to bind ( Bind operation ) and then use it. VAO/VBO without binding is not effective.

The relationship between a VAO and multiple VBOs is roughly as follows:

Then, according to the relationship between a VAO and multiple VBOs, and the knowledge of OpenGL context (binding), the operation process of using a VAO to explain multiple VBOs is as follows:

unsigned  int VBO[ 2 ], NEW;
    glGenVertexArrays(1, &VAO);
    glGenBuffers( 2 , FEB);

Then, bind the first VBO, write data to this VBO, and tell the VAO how to interpret the information of this VBO;
then, unbind the VBO.

Then, bind the second VBO, write data to this VBO, and store in the VAO information on how to interpret the VBO;
then, unbind the VBO.

The following program:

unsigned  int VBO[ 2 ], NEW;
    glGenVertexArrays(1, &VAO);
    glGenBuffers( 2 , FEB);

//= Bind VAO =======
glBindVertexArray(VAO);
//================================ ===================================

//= bind the first VBO======
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
//======================== ===========================================

glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof ( float ), &sphereVertices[ 0 ], GL_STATIC_DRAW); //Write data to the first VBO

// Tell the VAO how to interpret the information for the first VBO =
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 sizeof(float), (void)0);
glEnableVertexAttribArray(0);
//======== ===================================================== ======

//= Unbind the first VBO =====
glBindBuffer(GL_ARRAY_BUFFER, 0);
//============================ =======================================

//=Bind the second VBO======
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
//======================== ===========================================

glBufferData(GL_ARRAY_BUFFER, sizeof (texVertrices), texVertrices, GL_STATIC_DRAW); //Write data to the second VBO

// Tell VAO how to interpret the information of the second VBO =
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 sizeof(float), (void)0);
glEnableVertexAttribArray(1);
//======== ===================================================== ====

Leave a Comment

Your email address will not be published. Required fields are marked *