Understanding VAO, VBO and program - opengl

I have been learning OpenGL by myself, and some concepts in OpenGL confuses me.
I understand that VBO is the buffer resides on the server side for undescribed data, VAO is the description of the VBO, and Program is the shader rendering pipeline used to display meshes to the screen.
what keeps confusing me is the relationship between all three of them, as I can see, after VBO is created and filled, VAO is the generated for program attributes specification. does that mean each time when we bind a VAO we have to use certain program ahead? please correct me if this is not correct. and some brief introduction about interactive between these OpenGL concepts would be great.
thanks

does that mean each time when we bind a VAO we have to use certain program ahead
The VAO describes (among other things) the format of vertex data. As a part of that format, it describes which data goes to which vertex attributes. It does this by assigning attributes "locations".
Your vertex shader has a number of user-defined input variables. These inputs are each assigned a "location".
When you render, the vertex format specifies which VS inputs are filled in, based on the locations that match. Therefore, you don't have to restrict your usage of a VAO to a specific VS. But, you must use a VAO with a compatible program. One which has inputs that match the format's locations.
If your VAO specifies that attribute locations 0, 1, and 4 will be filled with floating point data, then any VS's you use with that VAO must be compatible with that. It technically doesn't have to actually use locations 0, 1, or 4, but if it does, it must use floating-point input values. Any unused locations provided by the format will effectively be ignored (though they will almost certainly still be read from the buffer).
If the VAO puts floating-point data in attributes 0, 1, and 4, but the VS expects unsigned integer data in attribute 1, then you have a problem.

Related

What is the best way to draw multiple VAO Using the same shader but not having the same texture or colors

I'm wondering what would be the best thing to do if I want to draw
more than ~6000 different VAOs using the same shader.
At the moment I bind my shader then give it all information needed (uniform) then looping through each VAO to binding and draw them.
This code make my computer fall at ~ 200 fps instead of 3000 or 4000.
According to https://learnopengl.com/Advanced-OpenGL/Instancing, using glDrawElementsInstanced can allow me to handle a HUGE amount of same VAO but since I have ~6000 different VAO It seems like I can't use it.
Can someone confirm me this? What you guys would do to draw so many VAO and save many performance as you can?
Step 1: do not have 6,000 different VAOs.
You are undoubtedly treating each VAO as a separate mesh. Stop doing this. You should instead treat each VAO as a separate vertex format. That is, you only need a new VAO if you're passing different kinds of vertex data. The number of attributes and the format of each attributes constitute the format information.
Ideally, you only need between 4 and 10 separate sets of vertex formats. Given that you're using the same shader on multiple VAOs, you probably already have this understanding.
So, how do you use the same VAO for multiple meshes? Ideally, you would do this by putting all of the mesh data for a particular kind of mesh (ie: vertex format) in the same buffer object(s). You would select which data to retrieve for a particular rendering operation via tricks like the baseVertex parameter of glDrawElementsBaseVertex, or just by selecting which range of index data to draw from for a particular draw command. Other alternatives include the multi-draw family of rendering functions.
If you cannot put all of the data in the same buffers for some reason, then you should adopt the glVertexAttribFormat style of VAO usage. That way, you set your vertex format data with glVertexAttribFormat calls, and you can change the buffers as needed with glBindVertexBuffers without ever having to touch the vertex format itself. This is known to be faster than changing VAOs.
And to be honest, you should adopt glVertexAttribFormat anyway, because it's a much better API that isn't stupid like glVertexAttribPointer and its ilk.
glDrawElementsInstanced can allow me to handle a HUGE amount of same VAO but since I have ~6000 differents VAO It seems like I can't use it.
So what you should do is to combine your objects into the same VAO. Then use glMultiDrawArraysIndirect or glMultiDrawElementsIndirect to issue a draw of all the different objects from within the same VAO. This answer demonstrates how to do this.
In order to handle different textures you either build a texture atlas, pack the textures into a texture array, or use the GL_ARB_bindless_texture extensions if available.

Process of setting up a VAO in OpenGL

Can I get a more overall/general description of this?
I've been trying to research these things all week, but I only come into super technical explanations or examples.
Could somebody explain the overall process or goal of these VAO's? Maybe outline a bit of a "step-by-step" flowchart for setting up a VAO in OpenGL?
I've never been someone who learns by examples... so all the things I've found online have been really unhelpful so far.
Your Vertex Buffer Objects (VBOs) contain the vertex data. You set up attribute pointers which specify how that data should be accessed and interpreted in order to draw a vertex - how many components are there to each vertex, how are they stored (GL_FLOAT for example) etc.
The Vertex Array Object (VAO) saves all these attributes. Their purpose is to allow you to set up these attributes once and then restore them with one state change whenever you need to use them.
The advantage of this is you can easily set up multiple states and restore them - if I want to draw a cube and a triangle these are two different states - I create a VAO for each and the VAO saves the state for each of them. When I want to draw the cube, I restore the state for the cube only.
Setup
Setup has four steps:
Create the VAO
Bind the VAO
Set up the state
Unbind the VAO
Creating a VAO is very simple:
GLuint vao_name;
glGenVertexArrays(1, &vao_name);
This will generate one vertex array, and store it's name in vao_name.
Once your VAO is created you need to bind it:
glBindVertexArray(vao_name);
Now, any changes you make to the attribute pointers or bindings to the element array buffer will be saved. This is a call to any of the following:
glVertexAttribPointer(...)
glEnableVertexAttribArray(...)
glDisableVertexAttribArray(...)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)
Whenever you make one of these calls, the corresponding state is saved in the currently bound VAO. And when you later bind the VAO again, the state is restored.
Once you have set up the state you can unbind the VAO. Do this by binding VAO 0:
glBindVertexArrays(0);
You could also bind a different VAO and set up a different state for that. When this happens it is safe to make changes to the attribute pointers without disrupting your previous state.
Drawing
When you want to draw something all you have to do is restore the VAO:
glBindVertexArray(cube_vao)
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(triangle_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0); //Unbind the VAO
Edit:
These are some answers that helped me when I was trying to understand VAOs:
glVertexAttribPointer overwrite, glVertexAttribPointer clarification, When should glVertexAttribPointer be called?
Also, the OpenGL specification explains it well once you've got your head around the basics: https://www.opengl.org/registry/
The VAO holds all information about how to read the attributes from the VBOs.
This includes for each attribute, which VBO it is in; the offset, the stride, how it is encoded (int, float, normalized or not), how many values per attribute. In other words the parameters of glVertexAttribPointer (and the bound GL_ARRAY_BUFFER at the time of the call.
It also holds the element array buffer that holds the indexes.
For what VAO's are, see #ratchet-freak's answer.
As for the goal of VAO's, it's a matter of improving performance by allowing one single state change to setup all vertex attributes bindings, which not only means fewer function calls but also more opportunity for the OpenGL implementation to optimize for this state as a whole.
For VAO, an understanding of VBOs and Shader is a pre-requisite. VAOs provide a way to “pre-define” vertex data and its attributes.
One way to understand is to draw with VBOs and then draw the same with VAOs. You will notice that it is similar to drawing with VBOs, except that it is first "saved" in a VAO for later use. Subsequently, the VAO is made active to actually draw the saved state.
See VBO, Shader, VAO for a fairly good example.

What is the purpose of VAO in OpenGL

I'm starting to learn modern OpenGL, and as the title says, I just wanted to be sure of the purpose of VAO's in the rendering pipeline.
When rendering we use VBO to store datas, and then we use OpenGL functions like: glAttribe to say to the GPU that we are going to use this datas "in That way", like: the first 3 floats in the vertices that we passes through vbo are in fact positions, and the next 3 floats are colors etc... So then I readed that we need some VAO that stores the descriptions of the vertices but what's the goal there ?
Thanks in advance.
Vertex array objects store a set of buffer names (usually vertex and index buffers) to get vertex data from, as well as how the vertices are layed out in the vertex buffers.
Their main purpose is so that when you want to render a different model from a different set of buffers, instead of binding each buffer and then setting the vertex attribute formats each time, you just bind a different VAO, and all the buffers and attributes are set up for you.
Not only is this more convenient for the programmer, it reduces the number of OpenGL calls required and thus CPU usage, which can clear up a CPU bottleneck.

Drawing multiple models using multiple openGL VBO's

rather than post lots of code, I will phrase this question intuitively. I hope you understand what I am getting at.
I am making a game and in the code I have a model class that loads a model and sets up the VBO for it.
In the loading function, it generates a new VBO ID and loads the vertex data from a file into that buffer by binding it etc. (This works fine)
At the beginning of the program I make one model object and load a .obj file.
In the render function, I simply call the DrawArrays() function (with the neccessary extra stuff) and as I said, everything works fine as the model appears on the screen with no problems.
The problem however, is when I make two model objects at the beginning of the program and load a different .obj file into each one.
The issue is that when I play, only the second model is drawn on screen.
The problem is because I don't properly understand how VBO's work.
This is how I "think" VBO's work.
You can generate as many VBO ID's as you want.
You can bind each ID to make it the active buffer.
You can load vertex data into that buffer.
You now effectively have many different ID's each referring to a "set of vertex data".
By calling the DrawArray function it draws every buffer you have generated (effectively displaying all your models on screen)
Now I know this is wrong because in my limited understanding I can't see how I could turn models on/off. But no matter how many tutorials I look at I can't answer this question because they all focus on displaying that ONE FIRST VBO, which incidentally I can do.
So... if that made sense, could anyone enlighten me?
You're doing it mostly right, but the drawing command does not draw every buffer you have generated. If you want to draw 2 objects with data in different buffers, you'll have to issue 2 drawing commands.
Let me explain, based on how I do it:
You create buffers using glGenBuffers. Before you can use a buffer, you have to "bind" it, that is, make it active using glBindBuffer. When a buffer is active, you can do stuff with it (populate with data for example). Note that there are different bind targets, so you can, for example, have one active array buffer (for vertex data) and one active element array buffer (for index data).
When you want to draw stuff, you have to specify what exactly you want to draw (I'll assume now that you're using your own shader) Usually you specify at least your vertex data and index data. To do this, you first bind your buffer with your vertex data (as an array buffer), then call glVertexAttribPointer with you attribute id. This tells OpenGL that the bound buffer is now the source for the current attribute. Then, you bind your index buffer as the element array buffer and call glDrawElements (not sure how glDrawArrays would work here).
You cannot use multiple VBOs at once for the same attribute - the call to bind another buffer just overwrites the previous call and makes the second buffer active, which, I assume, is why only your second object gets drawn.
You can also use VAOs to simplify the drawing - basically you assign an id to binding commands, then you can execute them with one line (think display lists).
So, my loading (of one object) looks like this:
Create buffers (let's say buffer 1 is for vertex data, buffer 2 for index data).
Bind buffer 1 as an array buffer.
Fill buffer with vertex data.
Repeat 2 and 3 for buffer 2 as element array buffer and index data, respectively.
And my drawing (again, of one object):
Bind buffer 1 as an array buffer.
Use glVertexAttribPointer to specify that this buffer goes to a specific attribute.
Bind buffer 2 as an element array buffer.
Call DrawElements
For the second object, you have to repeat everything.
Follow these steps to render your models, assuming model1 vertices are stored in vertexBuffer and model2 vertices in vertexBuffer2:
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, <no. of vert>);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer2);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, <no. of vert>);
//swap buffers depending on your windowing toolkit
Make sure to not perform glClear in the middle of the two model renders.
All the best!
what you want to do is set the vertexArrayAttribute back to the first object data before each call to drawArrays
the draw arrays function uses the bindings stored in the VAO to find the data needed to render everything
so to render 2 models you create a second VAO bind it and call glVertexAttribPointer as needed. for drawing you bind the VAO and call drawArrays for each model

OpenGL How Many VAOs

I am writing an OpenGL3+ application and have some confusion about the use of VAOs. Right now I just have one VAO, a normalised quad set around the origin. This single VAO contains 3 VBOs; one for positions, one for surface normals, and one GL_ELEMENT_ARRAY_BUFFER for indexing (so I can store just 4 vertices, rather than 6).
I have set up some helper methods to draw objects to the scene, such as drawCube() which takes position and rotation values and follows the procedure;
Bind the quad VAO.
Per cube face:
Create a model matrix that represents this face.
Upload the model matrix to the uniform mat4 model vertex shader variable.
Call glDrawElements() to draw the quad into the position for this face.
I have just set about the task of adding per-cube colors and realised that I can't add my color VBO to the single VAO as it will change with each cube, and this doesn't feel right.
I have just read the question; OpenGL VAO best practices, which tells me that my approach is wrong, and that I should use more VAOs to save the work of setting the whole scene up every time.
How many VAOs should be used? Clearly my approach of having 1 is not optimal, should there be a VAO for every static surface in the scene? What about ones that move?
I am writing to a uniform variable for each vertex, is that correct? I read that uniform shader variables should not change mid-frame, if I am able to write different values to my uniform variable, how do uniforms differ from simple in variables in a vertex shader?
Clearly my approach of having 1 is not optimal, should there be a VAO for every static surface in the scene?
Absolutely not. Switching VAOs is costly. If you allocate one VAO per object in your scene, you need to switch the VAO before rendering such objects. Scale that up to a few hundred or thousand objects currently visible and you get just as much VAO changes. The questions is, if you have multiple objects which share a common memory layout, i.e. sizes/types/normalization/strides of elements are the same, why would you want to define multiple VAOs that all store the same information? You control the offset where you want to start pulling vertex attributes from directly with a corresponding draw call.
For non-indexed geometry this is trivial, since you provide a first (or an array of offsets in the multi-draw case) argument to gl[Multi]DrawArrays*() which defines the offset into the associated ARRAY_BUFFER's data store.
For indexed geometry, and if you store indices for multiple objects in a single ELEMENT_ARRAY_BUFFER, you can use gl[Multi]DrawElementsBaseVertex to provide a constant offset for indices or manually offset your indices by adding a constant offset before uploading them to the buffer object.
Being able to provide offsets into a buffer store also implies that you can store multiple distinct objects in a single ARRAY_BUFFER and corresponding indices in a single ELEMENT_ARRAY_BUFFER. However, how large buffer objects should be depends on your hardware and vendors differ in their recommendations.
I am writing to a uniform variable for each vertex, is that correct? I read that uniform shader variables should not change mid-frame, if I am able to write different values to my uniform variable, how do uniforms differ from simple in variables in a vertex shader?
First of all, a uniforms and shader input/output variables declared as in/out differ in various instances:
input/output variables define an interface between shader stages, i.e. output variables in one shader stage are backed by a corresponding and equally named input variable in the following stage. A uniform is available in all stages if declared with the same name and is constant until changed by the application.
input variables inside a vertex shader are filled from an ARRAY_BUFFER. Uniforms inside a uniform block are backed a UNIFORM_BUFFER.
input variables can also be written directly using the glVertexAttrib*() family of functions. single uniforms are written using the glUniform*() family of functions.
the values of uniforms are program state. the values of input variables are not.
The semantic difference should also be obvious: uniforms, as their name suggests, are usually constant among a set of primitives, whereas input variables usually change per vertex or fragment (due to interpolation).
EDIT: To clarify and to factor in Nicol Bolas' remark: Uniforms cannot be changed by the application for a set of vertices submitted by a single draw call, neither can vertex attributes by calling glVertexAttrib*(). Vertex shader inputs backed by a buffer objects will change either once per vertex or at some specific rate set by glVertexAttribDivisor.
EDIT2: To clarify how a VAO can theoretically store multiple layouts, you can simply define multiple arrays with different indices but equal semantics. For instance,
glVertexAttribPointer(0, 4, ....);
and
glVertexAttribPointer(1, 3, ....);
could define two arrays with indices 0 and 1, component sized 3 and 4 and both refer to position attributes of vertices. However, depending on what you want to render, you can bind a hypothetical vertex shader input
// if you have GL_ARB_explicit_attrib_location or GL3.3 available, use explicit
// locations
/*layout(location = 0)*/ in vec4 Position;
or
/*layout(location = 1)*/ in vec3 Position;
to either index 0 or 1 explicitly or glBindAttribLocation() and still use the same VAO. AFAIK, the spec says nothing about what happens if an attribute is enabled but not sourced by the current shader but I suspect implementation to simply ignore the attribute in that case.
Whether you source the data for said attributes from the same or a different buffer object is another question but of course possible.
Personally I tend to use one VBO and VAO per layout, i.e. if my data is made up of an equal number of attributes with the same properties, I put them into a single VBO and a single VAO.
In general: You can experiment with this stuff a lot. Do it!