I'm following basic tutorial on OpenGL 3.0. What is not clear to me why/if I have to bind, enable and unbind/disable all vertex buffers and textures each frame.
To me it seems too much gl**** calls which I guess have some overhead. For example here you see each frame several blocks like:
// do this for each mesh in scene
// vertexes
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glVertexAttribPointer( 0, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer );
glVertexAttribPointer( 1, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uv_buffer );
glVertexAttribPointer( 2, 2, GL_FLOAT,GL_FALSE,0,(void*)0);
// ...
glDrawArrays(GL_TRIANGLES, 0, nVerts );
// ...
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
imagine you have not just one but 100 different meshes each with it's own VBOs for vertexes,normas,UVs. Should I really do this procedure each frame for each of them? Sure I can encapsulate that complexity into some function/objects, but I worry about overheads of this gl**** function calls.
Is it not possible some part of this machinery to move from per frame loop into scene setup ?
Also I read that VAO is a way how to pack corresponding VBOs for one object together. And that binding VAO automatically binds corresponding VBOs. So I was thinking that maybe one VAO for each mesh (not instance) is how it should be done - but according to this answer it does not seems so?
First things first: Your concerns about GL call overhead have been addressed with the introduction of Vertex Array Objects (see #Criss answer). However the real problem with your train of thought is, that you equate VBOs with geometry meshes, i.e. give each geometry its own VBO.
That's not how you should see and use VBOs. VBOs are chunks of memory and you can put the data of several objects into a single VBO; you don't have to draw the whole thing, you can limit draw calls to subsets of a VBO. And you can coalesce geometries with similar or even identical drawing setup and draw them all at once with a single draw call. Either by having the right vertex index list, or by use of instancing.
When it comes to the binding state of textures… well, yeah, that's a bit more annoying. You really have to do the whole binding dance when switching textures. That's why in general you sort geometry by texture/shader before drawing, so that the amount of texture switches is minimized.
The last 3 or 4 generations of GPUs (as of late 2016) do support bindless textures though, where you can access textures through a 64 bit handle (effectively the address of the relevant data structure in some address space) in the shader. However bindless textures did not yet make it into the core OpenGL standard and you have to use vendor extensions to make use of it.
Another interesting approach (popularized by Id Tech 4) is virtual textures. You can allocate sparsely populated texture objects that are huge in their addressable size, but only part of them actually populated with data. During program execution you determine which areas of the texture are required and swap in the required data on demand.
You should use vertex array object (generated by glGenVertexArrays). Thanks to it you don't have to perform those calls everytime. Vertex buffer object stores:
Calls to glEnableVertexAttribArray or glDisableVertexAttribArray.
Vertex attribute configurations via glVertexAttribPointer.
Vertex buffer objects associated with vertex attributes by calls to
glVertexAttribPointer.
Maybe this will be better tutorial.
So that you can generate vao object, then bind it, perform the calls and unbind. Now in drawing loop you just have to bind vao.
Example:
glUseProgram(shaderId);
glBindVertexArray(vaoId);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
Related
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.
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.
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.
Just want to make sure I understand this correctly (I'd ask on SO Chat, but it's dead in there!):
We've got a Vertex Array, which we make "current" by binding it
then we've got a Buffer, which we bind to a Target
then we fill that Target via glBufferData
which essentially populates whatever was bound to that target, i.e. our Buffer
and then we call glVertexAttribPointer which describes how the data is laid out -- the data being whatever is bound to GL_ARRAY_BUFFER
and this descriptor is saved to our original Vertex Array
(1) Is my understanding correct?
The documentation is a little sparse about how everything correlates.
(2) Is there some kind of default Vertex Array? Because I forgot/omitted glGenVertexArrays and glBindVertexArray and my program worked fine without it.
Edit: I missed a step... glEnableVertexAttribArray.
(3) Is the Vertex Attrib tied to the Vertex Array at the time glVertexAttribPointer is called, and then we can enable/disable that attrib via glEnableVertexAttribArray at any time, regardless of which Vertex Array is currently bound?
Or (3b) Is the Vertex Attrib tied to the Vertex Array at the time glEnableVertexAttribArray is called, and thus we can add the same Vertex Attrib to multiple Vertex Arrays by calling glEnableVertexAttribArray at different times, when different Vertex Arrays are bound?
Some of the terminology is a bit off:
A Vertex Array is just an array (typically a float[]) that contains vertex data. It doesn't need to be bound to anything. Not to be confused with a Vertex Array Object or VAO, which I will go over later
A Buffer Object, commonly referred to as a Vertex Buffer Object when storing vertices, or VBO for short, is what you're calling just a Buffer.
Nothing gets saved back to the vertex array, glVertexAttribPointer works exactly like glVertexPointer or glTexCoordPointer work, just instead of named attributes, you get to provide a number that specifies your own attribute. You pass this value as index. All your glVertexAttribPointer calls get queued up for the next time you call glDrawArrays or glDrawElements. If you have a VAO bound, the VAO will store the settings for all your attributes.
The main issue here is that you're confusing vertex attributes with VAOs. Vertex attributes are just the new way of defining vertices, texcoords, normals, etc. for drawing. VAOs store state. I'm first going to explain how drawing works with vertex attributes, then explain how you can cut down the number of method calls with VAOs:
You must enable an attribute before you can use it in a shader. For example, if you want to send vertices over to a shader, you're most likely going to send it as the first attribute, 0. So before you render, you need to enable it with glEnableVertexAttribArray(0);.
Now that an attribute is enabled, you need to define the data it's going to use. In order to do so you need to bind your VBO - glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
And now we can define the attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);. In order of parameter: 0 is the attribute you're defining, 3 is the size of each vertex, GL_FLOAT is the type, GL_FALSE means to not normalize each vertex, the last 2 zeros mean that there's no stride or offset on the vertices.
Draw something with it - glDrawArrays(GL_TRIANGLES, 0, 6);
The next thing you draw may not use attribute 0 (realistically it will, but this is an example), so we can disable it - glDisableVertexAttribArray(0);
Wrap that in glUseProgram() calls and you have a rendering system that works with shaders properly. But let's say you have 5 different attributes, vertices, texcoords, normals, color, and lightmap coordinates. First of all, you would be making a single glVertexAttribPointer call for each of these attributes, and you'd have to enable all the attributes beforehand. Let's say you define the attributes 0-4 as I have them listed. You would enable all of them like so:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
And then you would have to bind different VBOs for each attribute (unless you store them all in one VBO and use offsets/stride), then you need to make 5 different glVertexAttribPointer calls, from glVertexAttribPointer(0,...); to glVertexAttribPointer(4,...); for vertices to lightmap coordinates respectively.
Hopefully that system alone makes sense. Now I'm going to move on to VAOs to explain how to use them to cut down on the number of method calls when doing this type of rendering. Note that using a VAO is not necessary.
A Vertex Array Object or VAO is used to store the state of all the glVertexAttribPointer calls and the VBOs that were targeted when each of the glVertexAttribPointer calls were made.
You generate one with a call to glGenVertexArrays. To store everything you need in a VAO, bind it with glBindVertexArray, then do a full draw call. All the draw bind calls get intercepted and stored by the VAO. You can unbind the VAO with glBindVertexArray(0);
Now when you want to draw the object, you don't need to re-call all the VBO binds or the glVertexAttribPointer calls, you just need to bind the VAO with glBindVertexArray then call glDrawArrays or glDrawElements and you'll be drawing the exact same thing as though you were making all those method calls. You probably want to unbind the VAO afterwards too.
Once you unbind the VAO, all the state returns to how it was before you bound the VAO. I'm not sure if any changes you make while the VAO is bound is kept, but that can easily be figured out with a test program. I guess you can think of glBindVertexArray(0); as binding to the "default" VAO...
Update: Someone brought to my attention the need for the actual draw call. As it turns out, you don't actually need to do a FULL draw call when setting up the VAO, just all the binding stuff. Don't know why I thought it was necessary earlier, but it's fixed now.
The terminology and sequence of APIs to be called is quite confusing indeed. What's even more confusing is how the various aspects - buffer, generic vertex attribute and shader attribute variable get associated. See OpenGL-Terminology for a pretty good explanation.
Further, the link OpenGL-VBO,shader,VAO shows a simple example with the necessary API calls. It's particularly good for those transitioning from immediate mode to the programmable pipeline.
Hope it helps.
Edit: As you can see from the comments below, people can make assumptions and jump to conclusions. The reality is that it's quite confusing for beginners.
Context
I am doing swarm simulation using GPU programming (both OpenCL and CUDA,
but not at the same time of course) for scientific purpose.
I use OpenGL for display.
Goal
I would like to draw the same object —namely the swarming particle, can be a simple triangle in 2D— N times at different positions and with
different orientations in the most efficient way knowing that:
the object is always exactly the same
the positions and orientations are calculated on the GPU and thus stored in the GPU memory
the number of particles N can be large
Current solution
So far, to avoid sending back the data to the CPU, I store the position and
orientation arrays in a VBO and use:
glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, velocity_vbo);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, 0);
glDrawArrays(GL_POINTS, 0, N);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
to draw a set of points with color-coded velocity without copying back the arrays to the CPU.
What I would like to do is something like drawing a full object instead of a simple point
using a similar way ie without copying back the VBO's to the CPU.
Basically I would like to store on the GPU the model of an object
(a Display List? a Vertex Array?) and to use the positions and orientations on the GPU
to draw the object N times without sending data back to the CPU.
Is it possible and how? Else, how should I do it?
PS: I like keeping the code clean so I would rather separate the display issues from the swarming kernel.
I believe you can do this with a geometry shader (available in OpenGL 3.2). See this tutorial for specific information.
In your case, you need to make the input type and output type of the geometry shader to GL_POINTS and GL_TRIANGLES respectively, and in your geometry shader, emit the 3 vertices of your triangle for each incoming point vertex.