Using a Vertex Buffer in two different Vertex Array Objects - c++

This is a theoretical question, so I don't have code until now.
Assuming that I have a VBO with vertex position data and am using it within a VAO to render an indexed (glDrawElements()) figure out of triangles with a special index array.
Now I want to reuse this data buffer within a second VAO to render some other figures consisting out of lines, but with a different index array.
How do I need to bind the buffers, so that I can reuse the vertex data of the first VAO?

no special code is needed to share the buffers between VAOs just bind them as you normally would.
setting up:
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, locBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleBuffer);
glVertexAttrPointer(...);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, locBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lineBuffer);
glVertexAttrPointer(...);
and when drawing:
glBindVertexArray(VAO[0]);
glDrawElements(...);
glBindVertexArray(VAO[1]);
glDrawElements(...);

Related

How do OpenGL buffers relate to the VAO?

I'm currently learning OpenGL, but I'm having some problems understanding how the different buffers relate to the VAO. In my following code, I'm creating one VAO and two buffers (VBO for the vertex positions and EBO for the vertex order). At this point, if I understood it correctly, there is no connection between the VAO, VBO and EBO. I basically just created one VAO and two buffers. Now with glBindVertexArray and glBindBuffer I tell the OpenGL state machine my currently used VAO and assign my created buffers to a specific buffer type. With glBufferData I then load my data into the buffers. As I understand it, the VAO is still empty at this point and only gets data loaded into with the glVertexAttribPointer function. Now, OpenGL interprets the Data from GL_ELEMENT_ARRAY_BUFFER and loads them into the VAO at index 0. With glEnableVertexAttribArray(0) I then specify that the data at index 0 from my VAO (the vertex positions) should be used in the rendering process.
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
In my main loop, I specify a shader for my triangles, bind a VAO for rendering and then draw the elements followed by swapping the front and back buffers.
glUseProgram(shader);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
But how exactly does OpenGL know the order from the vertices? I have only uploaded the vertex position data into my VAO, but not the order(element) data. Does glVertexAttribPointer perhaps take into account the currently bound data from the GL_ELEMENT_ARRAY_BUFFER when loading data into the VAO? What am I missing here?
Now, OpenGL interprets the Data from GL_ELEMENT_ARRAY_BUFFER and loads them into the VAO at index 0.
No. Well sort of, but not in the way you seem to be describing it.
Most buffer binding points bind a buffer to the OpenGL context. The GL_ELEMENT_ARRAY_BUFFER binding point is different. It attaches the buffer to the VAO that itself is bound to the context. That is, the act of calling glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) itself is what creates an association between the VAO and the index buffer. This association has nothing to do with glVertexAttribPointer.
This also means that if you don't have a VAO bound to the context, you cannot bind anything to GL_ELEMENT_ARRAY_BUFFER.

Why does OpenGL buffer unbinding order matter? [duplicate]

This question already has answers here:
What is the role of glBindVertexArrays vs glBindBuffer and what is their relationship?
(5 answers)
Closed 1 year ago.
I'm in the process of learning OpenGL (3.3) with C++, I can draw simple polygons using Vertex Buffer Objects, Vertex Array Objects, and Index Buffers, but the way I code them still feels a little like magic, so I'd like to understand what's going on behind the scenes.
I have a basic understanding of the binding system OpenGL uses. I also understand that the VAO itself contains the bound index buffer (as specified here), and if I'm not mistaken the bound vertex buffer too.
By this logic, I first bind the VAO, then create my VBO (which behind the scenes is bound "inside" the VAO?), I can perform operations on the VBO, and it will all work. But then when I come to unbind the buffers I used after I'm done setting up things, it seems that I must unbind the VAO first, then the vertex & index buffers, so the unbinding occurs in the same order as the binding, and not in reverse order.
That is extremely counter intuitive. So my question is, why does the order of unbinding matter?
(to clarify, I am rebinding the VAO anyway before calling glDrawElements, so I don't think I even need to unbind anything at all. it's mostly for learning purposes)
Here's the relevant code:
GLuint VAO, VBO, IBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0); //unbinding VAO here is fine
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//if I unbind VAO here instead, it won't render the shape anymore
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
}
I believe I might have figured it out. Looking at this unbinding order
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbinding VBO
glBindVertexArray(0); //unbinding VAO
clearly "ruins" my polygons, because unbinding the VBO while my VAO is still bound means the VBO, which is supposed to "contain" references to the buffers it uses, is now not bound to a vertex buffer anymore. It doesn't know about the buffers.
Unbinding the VAO first allows me to then unbind any buffers without affecting it. This would be the correct order.
glBindVertexArray(0); //unbinding VAO
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbinding VBO
OpenGL's binding system is a little hard to grasp, especially when different things depend on one another, but I think my explanation is correct. Hopefully this could help some other learners in the future.

OpenGL VAO VBO resize

I have ran into an issue that uploading new content of a different size to the buffer causes VAO to behave unpredictably. Causing my object to look as if the buffer size was incorrectly set.
1) I generate VAO and VBO for an object
glGenVertexArrays(1, &_vao); // Generate 1 VAO
glGenBuffers(1, &_vbo); // Generate 1 VBO
2) Get location of uniform variables and attributes
3) Set the bindings like this:
glBindBuffer(GL_ARRAY_BUFFER, _vbo); // Bind VBO first
glBindVertexArray(_vao); // Bind VAO properties to VBO
{
GLsizei packSize = DIM * sizeof(GLfloat) * 2;
glEnableVertexAttribArray(_position);
glVertexAttribPointer(_position, DIM, GL_FLOAT, GL_FALSE, packSize, (GLvoid*)0);
// And so on ...
}
glBindVertexArray(0); // Unbind VAO
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO
4) Then I load my data:
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(float),
_vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
The problem starts when I try to load new data of a different size:
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(float),
_vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And my buffer size seem to remain the same.
Though, if I define and bind my vao to vbo again (like in 3-d step)
glDeleteBuffers(1, &_vbo);
glGenBuffers(1, &_vbo);
// glBindBuffer... See step 3
// ...
It works.
Is it possible to avoid recreating the new buffer?
What is prefered way of resizing it?
Resize screenshot
Why it behaves such way?
I use OpenGL version 4.2.0 Build 10.18.10.3379
What is prefered way of resizing it?
The preferred way of resizing buffer objects is to not resize them. I'm being serious.
The OpenGL ARB created an entire alternate way of allocating storage for buffers, for the sole purpose of making it impossible to reallocate them later. OK, if you want to be technical, the purpose of immutable storage is to allow persistent mapping, which requires immutability, but if they just wanted persistent mapped buffers, they could have restricted the new API to just those.
Figure out what the maximum size of your data will be (or whatever maximum you want to support), allocate that up front, and just whatever part you want to.
Technically, your code ought to work. By the standard, if you resize a buffer object, things that reference it ought to be able to see the resized storage. But since implementations don't want you to resize them, high-performance applications don't resize them. So that code is rarely tested in real applications, and bugs can linger for quite some time.
Just don't do it.

OpenGL binding many textures while drawing the one mesh

I would like to bind for example 80 textures on one mesh and put it in my VBO.
How can I achieve this?
I've read glActiveTexture is able to do that, however it allows max around 32 textures (GPU dependant).
My VBO code:
//Generating VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d) + textureCoords.size()*sizeof(Vector2d), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vector3d), vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d), textureCoords.size()*sizeof(Vector2d), textureCoords.data());
glGenBuffers(1, &IND);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
//Drawing VBO:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_DOUBLE, 0, 0);
glTexCoordPointer(2, GL_DOUBLE, 0, (void*)(vertices.size()*sizeof(Vector3d)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
Binding many (100s of) textures
I'm not sure of a way to bind that many separate textures at once. There are bindless textures but I don't have much experience with that extension. You could also use an array texture if many of your textures are the same size. But the standard approach to this problem is to use a texture atlas, where you pack lots of textures into the one, record where they're placed and adjust the texture coordinates to match.
Update: you could also use many texture arrays to store texture atlases (see comments and #Ethan's answer).
Applying multiple textures to a mesh
How will I tell the VBO, what faces will have which texture?
I think a more immediate problem is is how you go about applying different textures (or materials) to the same mesh. There's a few things to consider...
The most common case for applying multiple textures is where each stores a different material attribute but they all use the same texture coordinates/"UVs". E.g. diffuse, normal, specular maps. I guess in the extreme case when you have 100s of different attributes is where you'd want an array texture.
If each texture needs to be mapped differently you'd have a separate per-vertex texture coordinate VBO for each texture. Then you'll have to decide how the textures interact or blend as they're applied.
You have completely separate materials/texture per face. Commonly there are only a few materials on the mesh. The way you render it is in separate batches, grouping by material. Bind the right texture, set the shader uniforms, draw triangle indices A to B.
If nearly every face has a different material. I guess this might be the case if you're drawing a tile based game with lots of different tiles.
The problem here is the number of draw calls becomes a bottleneck,
so you'll have to combine different materials into the same draw call.
You could do this by storing the material on vertex attributes, such as adding a vertex colour VBO.
Rather than just colour, you could store a per-vertex texture ID, and if you're using a texture atlas, the region in the atlas where your texture can be found.
This starts to get inefficient because you'll have the same material data stored multiple times on each vertex of your triangles.
To minimize the overhead, you could store a material index per vertex, which points to a material defined in a table somewhere (either in a small uniform array, or if you need more materials, another texture).
Then add texture ID and atlas region to the material in the table.
Hopefully this last point answers your question.
To be honest, if you have more than 32 textures for one mesh, you probably have a much bigger problem than binding issues. But if you insist on having that many textures, you have 2 options: Bindless or Texture array. However, there are drawbacks: Bindless will limit your hardware support. Texture array does require the textures to be of the same size and format. Personally I think Texture Array is a workable solution. You can try to resize your textures if possile, then group those with the same size & format into one array. Now, you have 32 arrays to work with, and that should be more than enough, e.g. one array for all albedo textures, one for all normal maps etc. Regarding resizing, consider scaling textures up to the largest size that you have, or maybe split into categories e.g. small, medium, large. Avoid arbitrary sizes.

OpenGL structure of VAO/VBO for model with moving parts?

I came from this question:
opengl vbo advice
I use OpenGL 3.3 and will not to use deprecated features. Im using Assimp to import my blender models. But im a bit confused as to how much i should split them up in terms of VAO's and VBO's.
First off a little side question. I use glDrawElements, do that mean i cannot interleave my vertex attributes or can the VAO figure out using the glVertexAttribPointer and the glDrawElements offset to see where my vertex position is?
Main question i guess, boils down to how do i structure my VAO/VBO's for a model with multiple moving parts, and multiple meshes pr. part.
Each node in assimp can contain multiple meshes where each mesh has texture, vertices, normals, material etc. The nodes in assimp contains the transformations. Say i have a ship with a cannon turret on it. I want to be able to roatate the turret. Do this mean i will make the ship node a seperate VAO with VBO's for each mesh containing its attributes(or multiple VBO's etc.).
I guess it goes like
draw(ship); //call to draw ship VAO
pushMatrix(turretMatrix) //updating uniform modelview matrix for the shader
draw(turret); //call to draw turret VAO
I don't fully understand UBO(uniform buffer objects) yet, but it seems i can pass in multiple uniforms, will that help me contain a full model with moveable parts in a single VAO?
first, off VAO only "remembers" the last vertex attribute bindings (and VBO binding for an index buffer (the GL_ELEMENT_ARRAY_BUFFER_BINDING), if there is one). So it does not remember offsets in glDrawElements(), you need to call that later when using the VAO. It laso does not prevent you from using interleaved vertex arrays. Let me try to explain:
int vbo[3];
glGenBuffers(3, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, data0, size0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, data1, size1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2);
// create some buffers and fill them with data
int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// create a VAO
{
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state
glEnableVertexAttribArray(0); // this is VAO saved state
// sets up one vertex attrib array from vbo[0] (say positions)
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO
glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state
glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state
glEnableVertexAttribArray(1); // this is VAO saved state
glEnableVertexAttribArray(2); // this is VAO saved state
// sets up two more VAAs from vbo[1] (say normals interleaved with texcoords)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state
// uses the third buffer as the source for indices
}
// set up state that VAO "remembers"
glBindVertexArray(0); // bind different vaos, etc ...
Later ...
glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer)
glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL);
glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int)));
// draws two parts of the mesh as triangle strips
So you see ... you can draw interleaved vertex arrays using glDrawElements using a single VAO and one or more VBOs.
To answer the second part of your question, you either can have different VAOs and VBOs for different parts of the mesh (so drawing separate parts is easy), or you can fuse all into one VAO VBO pair (so you need not call glBind*() often) and use multiple glDraw*() calls to draw individual parts of the mesh (as seen in the code above - imagine the first glDrawElements() draws the ship and the second draws the turret, you just update some matrix uniform between the calls).
Because shaders can contain multiple modelview matrices in uniforms, you can also encode mesh id as another vertex attribute, and let the vertex shader choose which matrix to use to transform the vertex, based on this attribute. This idea can also be extended to using multiple matrices per a single vertex, with some weights assigned for each matrix. This is commonly used when animating organic objects such as player character (look up "skinning").
As uniform buffer objects go, the only advantage is that you can pack a lot of data into them and that they can be easily shared between shaders (just bind the UBO to any shader that is able to use it). There is no real advantage in using them for you, except if you would be to have objects with 1OOOs of matrices.
Also, i wrote the source codes above from memory. Let me know if there are some errors / problems ...
#theswine
Not binding this during VAO initialization causes my program to crash, but binding it after binding the VAO causes it to run correctly. Are you sure this isn't saved in the VAO?
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
(BTW: sorry for bringing up an old topic, I just thought this could be useful to others, this post sure was! (which reminds me, thank you!!))