OpenGL: VAO/VBO confusion - c++

The OpenGL Wiki: Vertex Specification states that:
Note: The GL_ARRAY_BUFFER​ binding is NOT part of the VAO's state! I know that's confusing, but that's the way it is.
Below is how I use the VAO, which seems to work as intended. What is wrong here? My understanding of OpenGL (or OpenGL Wiki), my OpenGL driver (OSX 10.9) or the OpenGL Wiki?
// ------ Pseudo-code ------
// setup
[...]
glBindVertexArray(vertexArrayObjectIdx1);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferId1);
for each vertex attribute
glEnableVertexAttribArray(...);
glVertexAttribPointer(...);
glBindVertexArray(vertexArrayObjectIdx2);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferId2);
for each vertex attribute
glEnableVertexAttribArray(...);
glVertexAttribPointer(...);
// rendering
[...]
glBindVertexArray(vertexArrayObjectIdx1);
glDrawElements(...);
glBindVertexArray(vertexArrayObjectIdx2);
glDrawElements(...);

It means that when you rebind the VAO the GL_ARRAY_BUFFER does not get rebound
However the glVertexAttribPointer does bind the (then) bound GL_ARRAY_BUFFER to the correct attribute in the VAO so it does work like you want.
Actually they could have defined glVertexAttribPointer as:
void glVertexAttribPointer(GLuint index​, GLint size​, GLenum type​, GLboolean normalized​, GLsizei stride​, uint bufferName, const GLvoid * pointer​);
and eliminate it's dependency on the bound GL_ARRAY_BUFFER. But hindsight and all that...
Important to remember is that the GL_ARRAY_BUFFER is not important to drawing but the how the vertex attributes are bound is.
in contrast the GL_ELEMENT_ARRAY_BUFFER is stored in the VAO

Down below in the same Wiki entry, you can see the explanation as well - This is also why GL_ARRAY_BUFFER​ is not VAO state; the actual association between an attribute index and a buffer is made by glVertexAttribPointer​. ...

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.

Is a compiled shader compulsory in OpenGl 4?

I have an OpenGL 4.1 code using VAO and VBOs. Generation of buffer and array objects happens properly, however as soon as I want to draw my vertices, I get an INVALID OPERATION (code 1282) error. One of the possible explanations is that "the shader is not compiled".Hence my question: Is it a MUST to write & compile my own vertex and fragment shaders, or can I do without ?
As reference, my code:
Preparing:
glGenVertexArrays(1, vaoID); // Create new VAO
glBindVertexArray(vaoID);
glGenBuffers(1, vboID); // Create new VBO
glBindBuffer(GL_ARRAY_BUFFER, vboID); // Bind vbo1 as current vertex buffer
glBufferData(GL_ARRAY_BUFFER, sizeOfVertices, vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, floatsPerPosition, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, eboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfIndices, indices, GL_STATIC_DRAW);
// reset bindings for VAO, VBO and EBO
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Rendering:
glBindVertexArray(vaoID); // No Error
glDrawArrays(GL_TRIANGLES, 0, 6); // Generates Error 1282
glBindVertexArray(0);
In a core OpenGL profile, since 3.2, the use of a program object is not optional.
However, the only shader stage that is manditory is the vertex shader. The use of a fragment shader is optional, but of course, it would only be useful for depth or stencil operations (since it would not generate fragment colors).
In a compatibility OpenGL profile, you can render using the fixed-function pipeline, but you cannot use user-defined vertex attributes. You have to use the fixed-function attributes, set up with glVertexPointer, glColorPointer, etc. Note that NVIDIA plays fast-and-loose with the spec in this regard, mapping user-defined attributes to fixed-function ones.
According to the OpenGL specification, a shader must always be used when rendering geometry. When you have no shader enabled, the result of the draw call is undefined.
However, from what I can tell this is a bit more murky in practice. At least most NVidia and Intel drivers seem to come with a kind of "default shader" enabled by default, which inhibits the undefined behaviour.
These shaders have pre-specified vertex attribute input indices (for instance, NVidia uses 0 for vertices, 4 for vertex colours, etc), and implement what you could consider a default pipeline.
Please note here that while these default shaders exist, their implementation can vary significantly between vendors, or might not exist at all for specific vendors or driver versions.
So you should therefore always use a shader when drawing geometry in OpenGL 4.

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, VAOs and multiple buffers

I am writing a little graphics engine using OpenGL ( via OpenTK with C# ).
To define vertex attributes, I have a VertexDeclaration class with an array of VertexElement structures that are mapped to glEnableVertexAttribArray/glVertexAttribPointer calls.
Also, to support multiple vertex streams, I have a special structure holding a vertex buffer, vertex declaration, vertex offset and instance frequency (like the XNA's VertexBufferBinding structure).
Currently, whenever a drawing call is invoked, I iterate over all the set vertex streams and
bind their vertex buffers, apply vertex declarations, disable unused vertex attributes and draw the primitives.
I would like to use VAOs to cache the glEnableVertexAttribArray calls into them,
and whenever a vertex stream is applied, bind the VAO and change its array buffer binding.
Is that a correct usage of VAOs?
Is that a correct usage of VAOs?
No1.
glVertexAttribPointer uses the buffer object that was bound to GL_ARRAY_BUFFER at the moment the function was called. So you can't do this:
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, bufferObject);
glDrawArrays(...);
This will not use bufferObject; it will use whatever was bound to GL_ARRAY_BUFFER when glVertexAttribPointer was originally called.
VAOs capture this state. So the VAO will, for each vertex attribute, store whatever buffer object was bound to GL_ARRAY_BUFFER when it was called. This allows you to do things like this:
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, buffer1);
glVertexAttribPointer(0, ...);
glVertexAttribPointer(1, ...);
glBindBuffer(GL_ARRAY_BUFFER, buffer2);
glVertexAttribPointer(2, ...);
Attributes 0 and 1 will come from buffer1, and attribute 2 will come from buffer2. VAO now captures all of that state. To render, you just do this:
glBindVertexArray(VAO);
glDraw*();
In short, if you want to change where an attribute's storage comes from in OpenGL, you must also change it's format. Even if it's the same format, you must call glVertexAttribPointer again.
1: This discussion assumes you're not using the new ARB_vertex_attrib_binding. Or, as it is otherwise known, "Exactly how Direct3D does vertex attribute binding." If you happen to be using an implementation that offers this extension, you can effectively do what you're talking about, because the attribute format is not tied with the buffer object's storage. Also, the tortured logic of glVertexAttribPointer is gone.
In general, the way we solve this in the OpenGL world is to put as many things as possible in the same buffer object. Failing that, just use one VAO for each object.

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