how does a VBO get attached to a VAO - opengl

VAO being Vertex Array Object and VBO being Vertex Buffer Object. The calls for creating and binding/unbinding VAOs and VBOs have a general format as given below:
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER,
sizeof(GLfloat)* 9,
vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(0,
3, GL_FLOAT, GL_FALSE,
0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
I've followed some tutorials on the internet, and they say that the VBO is bound to the VAO, but in the above code, I don't get how the "connection" or "binding" is established between the VBO and the VAO? I mean how do we know which VBO is bound to which VAO and what if a VBO is to be bound to multiple VAOs?
So, the basic question is: what does VBO is bound to VAO mean, how do we know which VBO is bound to which VAO and how is this binding established?

how does a VBO get attached to a VAO
It is attached when glVertexAttribPointer is called.
Each attribute which is stated in the Vertex Array Objects state vector may refer to a different Vertex Buffer Object. This reference is stored when glVertexAttribPointer is called.
Then the buffer which is currently bound to the target ARRAY_BUFFER is associated to the attribute and the name (value) of the object is stored in the state vector of the VAO. The ARRAY_BUFFER binding is a global state.
This behaves different to the Index Buffer (ELEMENT_ARRAY_BUFFER). The index buffer binding is stated within the Vertex Array Object. When a buffer is bound to the target ELEMENT_ARRAY_BUFFER, then this buffer is associated to the vertex array object which is currently bound.
That means when you call glBindBuffer(GL_ARRAY_BUFFER, VBO);, then a global state is set that stores VBO. glVertexAttribPointer retrieves VBO from the global state and assoicates it to VAO.
When glBindBuffer(GL_ARRAY_BUFFER, ...) is called again, then the previous binding is lost, but of course it does not change any state of the VAO.
glBindVertexArray(VAO); # bind VAO (global state)
glBindBuffer(GL_ARRAY_BUFFER, VBO1); # bind VBO1 (global state)
glVertexAttribPointer(0, ...); # associate VBO1 to attribute 0 in VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO2); # bind VBO2 (change global state, VBO1 binding is lost)
glVertexAttribPointer(1, ...); # associate VBO2 to attribute 1 in VAO

Related

OpenGL binding order between EBO and VAO

I`m trying to create opengl triangle and I bumped up with some problem.
EBO : ElementArrayBufferObject
VAO : VertexArrayObject
while i trying to binding EBO before binding VAO it causing error and i don`t know why.
my code :
// Generate the VAO and VBO with only 1 object each
glGenVertexArrays(1, &VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Make the VAO the current Vertex Array Object by binding it
glBindVertexArray(VAO);
It causing problem while rendering.
and if i fix the code like this order.
// Generate the VAO and VBO with only 1 object each
glGenVertexArrays(1, &VAO);
// Make the VAO the current Vertex Array Object by binding it
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
it`s working as i expected.
I really don`t know why not working binding EBO before VAO.
The index buffer (ELEMENT_ARRAY_BUFFER) binding is stored within the Vertex Array Object. When glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO) is called the element buffer object is stored in the currently bound Vertex Array Object. Therefore the VAO must be bound before the element buffer with glBindVertexArray(VAO).
Note that compared to the index buffer (ELEMENT_ARRAY_BUFFER), the vertex buffer binding (ARRAY_BUFFER) is a global state.
Each attribute which is stated in the VAOs state vector may refer to a different ARRAY_BUFFER. This reference is stored when glVertexAttribPointer is called. Then the buffer which is currently bound to the target ARRAY_BUFFER, is associated to the specified attribute index and the name (value) of the object is stored in the state vector of the currently bound VAO.
However the index buffer is a state of the VAO. If a buffer is bound to the target ELEMENT_ARRAY_BUFFER, this buffer is assigned to the currently bound Vertex Array Object.

why data in VBO not associated with EBO are also fed to OpenGL?

I'm now maintaining an lagacy code and found "strange" usage in OpenGL.
First, the OpenGL version is 3.2 compability profile.
Then, there is nothing refering to VAO in the code, however, in Dont need to have a VAO? what #Dietrich Epp said is below :
If you use a compatibility OpenGL context, you don't need a VAO. In a sense, there is a "default" VAO which is always bound.
And what confused me is how the data are fed to OpenGL . The pseudocode may explain clear:
// foo.cpp
void PrimitiveLoading()
{
// load vertex position data
glBindBuffer(GL_ARRAY_BUFFER, postionVBO);
glBufferData(GL_ARRAY_BUFFER, /* postion data */);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// load vertex position index data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, /* postion index data */);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// load UV data
glBindBuffer(GL_ARRAY_BUFFER, uvVBO, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, /* UV data */);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/*
The postion data are loaded before ELEMENT, while the UV data are behind.
This means ELEMENT is associated with the postion but not the UV, right?
*/
}
void PrimitiveRendering()
{
// define the vertex postion format
glBindBuffer(GL_ARRAY_BUFFER, postionVBO);
glVertexAttribPointer(/*position attribute setting*/);
// define the uv format
glBindBuffer(GL_ARRAY_BUFFER, uvVBO);
glVertexAttribPointer(/*UV attribute setting*/);
glBindBuffer(GL_ARRAY_BUFFER, 0); // GL_ARRAY_BUFFER bind to 0
// draw
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionEBO);
glDrawElements(GL_TRIANGLES, positionEBO, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
/*
before drawing, GL_ARRAY_BUFFER bind to 0(not bind to both postionVBO and uvVBO), but it works.
And the data are fed to respectively postionVert and uvVert in foo.vert below as expected. how and why ?
Moreover, it seems the ELEMENT affects not not only postionVAO but also uvVAO.
*/
}
// foo.vert
version 150
in vec3 postionVert;
in vec2 uvVert;
...// other code
the questions are written as comments. Could anyone explain how this usage works?
The postion data are loaded before ELEMENT, while the UV data are behind.
This means ELEMENT is associated with the postion but not the UV, right?
No. Index arrays are not "associated" with any attribute. When you do indexed rendering, the index used applies to all attributes. You cannot use different indices to fetch different attributes.
before drawing, GL_ARRAY_BUFFER bind to 0(not bind to both postionVBO and uvVBO), but it works.
Of course it works. What is bound to GL_ARRAY_BUFFER does not matter for rendering purposes. It only matters when you call glVertexAttrib*Pointer, which takes the buffer that is currently bound to that binding point and hooks the given attribute index to that buffer.
Think of GL_ARRAY_BUFFER as just being a weird way of passing an additional parameter to glVertexAttrib*Pointer. Since you didn't call that function, the extra parameter isn't passed to anyone.
When you're "not using a VAO" in compatibility contexts, you're still using a VAO. The VAO-modifying functions all work exactly the same as they do for core contexts. The only difference is that in compatibility, VAO object 0 is a real vertex array object, while in core contexts it is not a valid object. So in compatibility contexts, there's always some VAO that is currently bound.

In OpenGL why won't my buffer object draw unless I respecify the vertex attributes again?

I thought the VAO (Vertex Array Object) was supposed to store state like the vertex attributes. When I create a VBO I specify my vertex attributes:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)nullptr);
glEnableVertexAttribArray(0);
// And so on
If I bind another VBO I have to call glVertexAttribPointer and glEnableVertexAttribArray three times, that's for every time I switch my VBO. I only have one VAO, I never change it. Is there something wrong? I only use one vertex layout and I'm not understanding what the VAO does if it loses this information each time I switch. Is it only one VBO per VAO?
If you don't want to respecify glVertexAttribPointer before calling a glDraw* function then you need several VAOs not just one. I think you are confusing the what a VBO and a VAO are. A VBO is just an inert piece of memory that contains data. A VAO contains all the information that OpenGL requires to draw a mesh, that includes:
- a reference to the Buffer object containing your vertex data (commonly named VBO)
- a reference to the Buffer object containing your vertex indices (if you are using glDrawElements*)
- the index of the different vertex attributes you are going to use and their layout in the Buffer object containing your vertex data (specified with glEnableVertexAttribArray and glVertexAttribPointer)
So basically for each mesh you are going to draw you need to prepare a corresponding vao:
// at scene preparation time
glBindVertexArray(vaoA); // the following functions will only affect vaoA
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_of_meshA);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_of_meshA);
foreach attrib of meshA
glEnableVertexAttribArray(***);
glVertexAttribPointer(***)
glBindVertexArray(0)
glBindVertexArray(vaoB); // the following functions will only affect vaoB
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_of_meshB);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_of_meshB);
foreach attrib of meshB
glEnableVertexAttribArray(***);
glVertexAttribPointer(***)
glBindVertexArray(0)
//And now at render time:
void render()
{
glBindVertexArray(vaoA);
glDrawElements(***);
glBindVertexArray(vaoB);
glDrawElements(***);
}
for more info check: https://www.opengl.org/wiki/Vertex_Specification

Passing float array to function

I am trying to load a VAO in OpenGL, but when running it doesn't draw.
When I use the code in my function directly into my main loop it runs fine but whenever I try to load the VAO via my function it doesn't work.
I already narrowed it down to something going wrong when passing the values to the function, because when I directly use the float array it does work.
I have the values defined as a static float array in my main function, and I'm loading it like this:
GLuint RenderLoader::load(float vertices[])
{
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
return VertexArrayID;
}
The problem is with sizeof(vertices). Since the array is passed into a function, it then becomes a pointer, and sizeof returns the size of the first element pointer only. It is only known as an array in the scope where it was first initialised.
One solution would be to pass the size as an additional parameter, but really the only solution is to use some sort of container, like vector which has a size() function.
When using a vector, you would then do it in the following way:
GLsizei size = vertices.size() * sizeof(vertices[0]); // Size in bytes
glBufferData(GL_ARRAY_BUFFER, size, &vertices[0], GL_STATIC_DRAW);

State in OpenGL

This is some simple code that draws to the screen.
GLuint vbo;
glGenBuffers(1, &vbo);
glUseProgram(myProgram);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
//Fill up my VBO with vertex data
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), &vertexes, GL_STATIC_DRAW);
/*Draw to the screen*/
This works fine. However, I tried changing the order of some GL calls like so:
GLuint vbo;
glGenBuffers(1, &vbo);
glUseProgram(myProgram);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
//Now comes after the setting of the vertex attributes.
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//Fill up my VBO with vertex data
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), &vertexes, GL_STATIC_DRAW);
/*Draw to the screen*/
This crashes my program. Why does there need to be a VBO bound to GL_ARRAY_BUFFER while I'm just setting up vertex attributes? To me, what glVertexAttribPointer does is just set up the format of vertexes that OpenGL will eventually use to draw things. It is not specific to any VBO. Thus, if multiple VBOs wanted to use the same vertex format, you would not need to format the vertexes in the VBO again.
Why does there need to be a VBO bound to GL_ARRAY_BUFFER while I'm just setting up vertex attributes?
No, you're not "just" setting up vertex attributes. You're actually creating a reference with the currently bound buffer object.
If there's no buffer object bound, then gl…Pointer will create a reference to your process address space pointed at the given address. Since this is a null pointer in your case, any attempt to dereference a vertex will cause a segmentation fault/access violation.
To me, what glVertexAttribPointer does is just set up the format of vertexes that OpenGL will eventually use to draw things.
No. It also creates a reference to where to get the data from.
It is not specific to any VBO.
Yes it actually is specific to the bound VBO, or the process address space if no VBO is bound. And changing the buffer binding will not update along the gl…Pointer references.
I believe that's because the last argument to glVertexAttribPointer is pointer which is an offset into a the VBO after glBindBuffer(nonzero) but when a VBO is not bound it's supposed to be a pointer to an actual array of data. So if you weren't using VBOs at all the last argument would be &vertexes and it wouldn't crash.