Understanding VAO and VBO - opengl

I am using two shaders to render all the items in my scene. Each item is drawn by one shader only.
Every shader has different attributes. In my case, one shader has only vertex coordinates and color, while the second shader has vertex coordinates, texture coordinates and color.
Each shader has a VAO corresponding with these attributes.
What I do to render the scene is loop through all shaders. For each shader, I call glUseProgram, I call glBindVertexArray with the VAO associated with the shader and also initialize the attributes. Then once the shader is active I loop through all the items in my scene to render them with the current shader.
Now to simplify each item has a draw method which contains the following:
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
//s->setupVertices();
glDrawElements(m_primitive, m_elementSize, GL_UNSIGNED_INT, (GLvoid*)(sizeof(GLuint) * 0));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
If I run the program like this, the items are not rendered correctly, but I noticed that if I uncomment the setupVertices() line (this is where the glVertexAttribPointer for the current shader are called), then everything is rendered fine.
Now this is something I don't understand. From what I understood on VAO, VAO store information on the vertex attributes, so I was expecting that once I call glBindVertexArray with the current VAO, the data for the vertex layout are remembered correctly and there's no need to re-specify the vertices layout for each buffer object; but it looks like this is necessary otherwise all items are rendered wrongly.
Am I doing something wrong/missing? Or I didn't understand a bit about VAO/VBO work?

Related

Why does this shader to draw a triangle in opengl not get run multiple times

I am learning to use OpenGL through some youtube tutorials online. At 24:43 is the code I am talking about: https:
//www.youtube.com/watch?v=71BLZwRGUJE&list=PLlrATfBNZ98foTJPJ_Ev03o2oq3-GGOS2&index=7
In the previous video of the series, the guy says that the vertex shader is run 3 times (for a triangle) and the fragment shader is run once for every pixel within the shape however in the video I have linked, there is nothing telling the vertex shader to run 3 times and there is nothing telling the fragment shader to be run multiple times either. Can someone please explain why?
Also I am struggling to understand the terminology being used. For example, in the vertex shader is the code: in vec4 position . And in the fragment shader there is the code out vec4 color. I searched around google alot for what this means but I couldn't find what it means anywhere.
1.
A vertex shader is executed for each vertex of the primitives that need to be drawn. Since only a triangle (i.e. primitive with three vertices) is being drawn in the example, the vertex shader is obviously executed three times, once for each vertex of that triangle. The scheduling of the vertex shaders is done by OpenGL itself. The user does not need to take care of this.
A fragment shader is executed for each fragment generated by the rasterizer (i.e. the rasterizer breaks primitives down into discrete elements called fragments). A fragment corresponds to a pixel. Though this is not a bijection, for some pixels there can be no fragments and for some pixels there can be more than one fragment depending on the scene to draw. The scheduling of the fragments is done by OpenGL itself. The user does not need to take care of this.
The user effectively only configures the configurable stages of the pipeline, binds the programmable shaders, binds the shader input and output resources, and binds the geometry resources (vertex and index buffers, topology). The latter corresponds in the example to the vertex buffer containing the three vertices of the triangle, and the GL_TRIANGLES topology.
So given the example:
// The buffer ID.
unsigned int buffer;
// Generate one buffer object:
glGenBuffers(1, &buffer);
// Bind the newly created buffer to the GL_ARRAY_BUFFER target:
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Copies the previously defined vertex data into the buffer's memory:
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);
// Set the vertex attributes pointers
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
...
// Bind the buffer as a vertex buffer:
glBindVertexArray(buffer);
...
// Draw a triangle list for the triangles with the vertices at indices [0,3) = 1 triangle:
glDrawArrays(GL_TRIANGLES, 0, 3);
A similar well-explained "How to draw a triangle"-tutorial.
2.
layout(location = 0) in vec4 position;
A user-defined input value to a vertex shader (i.e. vertex attribute) of type vec4 (a vector of 4 floats) with name position. In the example, each vertex has a position which needs to be transformed properly in the vertex shader before passing eventually to the rasterizer (assignment to gl_Position).
3.
layout(location = 0) out vec4 color
A user-defined output value to a fragment shader of type vec4 (a vector of 4 floats) with name color. In the example, the fragment shader outputs a constant color (e.g., red) for each fragment to be eventually written to the back buffer.
References
Some useful OpenGL/GLSL reference:
Learn OpenGL
And if you want to skip all CPU boiler plate and just focus on the shaders themselves, you can take a look at ShaderToy to facilitate prototyping.

How does OpenGL know how to use the normal data with glDrawElements()?

I spent days to construct a working example of rendering a cube in OpenGL with simple lighting
I have:
vertices = {...};
normals = {...};
vertex_indices = {...};
normal_indices = {...};
(1) I setup my VBOs
glBufferSubData(GL_ARRAY_BUFFER, 0, vertSize, &vertices[0]); // vertices
glBufferSubData(GL_ARRAY_BUFFER, vertSize, normSize, &normals[0]); // normals
(2) I enable my vertex pointers
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,..)
glEnableVertexAttribArray(1);
glVertexAttribPointer(1,..)
(3) I also setup my index buffer
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indcSize, & vertex_indices[0], GL_STATIC_DRAW);
and then call glDrawElements in my render method
glDrawElements(GL_TRIANGLES, (int)vertex_indices.size(), GL_UNSIGNED_INT, 0);
I don't pass the normal indices anywhere but everything seems to work fine.
I don't think I understand glDrawElements correctly. How did the lighting work without the normal indices? was glDrawElements suppose to only get the vertex indices?
I don't think I understand glDrawElements correctly. How did the lighting work without the normal indices? was glDrawElements suppose to only get the vertex indices?
In OpenGL, there are no separate indices per attribute. As far as OpenGL is concerned, a vertex is an n-tuple of all attributes, like position, color, normal vector, tex coords, whatever.
In the case of your cube, you will need at least 24 vertices. There are only 8 corner positions, but each corner is connected to 3 different faces, each with a different normal. This means, that you need 3 separate vertices at each corner, all at the same position, but all differing by their normal direction.
Consequently, glDrawElements works with only one index array, and this is the index into all enabled vertex attribute arrays at the same time. Your normal_indices array is not used at all. If it still works as intended, your normal data happens to be organized in the correct way.

Using a Vertex Buffer in two different Vertex Array Objects

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(...);

OpenGL Texture Loading Predicament

OK, so I made a library that handles basic OpenGL rendering. It contains three buffers, one for vertices, uv's and normals. In the main render function is where I bind the buffers, enable vertex attributes, and then call glDrawArrays(). But I ran into an unexpected issue that is more engineering based then code based which is that I can only bind one texture at a time. So all the vertices will have the same textures when I draw them, How can I get around this? If you need any more source I will post it.
Main Render Function
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,this->_VBO);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,this->_TBO);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER,this->_NBO);
glDrawArrays(GL_TRIANGLES,0,this->polyCount);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
Buffers:
//Designated Vertex Buffer
std::array<GLfloat,BUFFER_SIZE> BUFFER_1;
UINT bufferIndex1;
//Designated Normal Buffers
std::array<GLfloat,BUFFER_SIZE> BUFFER_2;
UINT bufferIndex2;
//Designated UV Buffer
std::array<GLfloat,BUFFER_SIZE> BUFFER_3;
UINT bufferIndex3;
What we would normally do here is split the mesh up into sub-meshes, by "material". An object with a different texture is technically a different material, so you would render it separately. You can render a single mesh using multiple textures by using something called an Atlas. That is to say, you pack your textures into a single bitmap and choose texture coordinates within that bitmap depending on the texture you want to use.

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!!))