I have multiple VBOs and matching VAOs set up in my rendering engine. I am a bit confused about using glVertexAttribPointer. I have set it and it renders fine but I am curious if I am using one shader (a basic diffuse) with all of these different objects, do I set glVertexAttribPointer each time I create a VAO. I guess what's throwing me is I am trying to figure out if my setting an attribute pointer, is that set in the shader or the vertex array object. I assume it's the vertex array object but am hoping for some clarification.
Vertex attribute pointers are per vertex array object (VAO). The OpenGL 4.3 specification on page 318 in the description of glGetVertexAttribPointerv specifies: The value returned is queried from the currently bound vertex array object.
Related
(Speaking of OpenGL 3.3) Is there a way to store different vertex attributes in the same VBO? I don't mean interleaved with "stride", I mean for example positions at the beginning of the VBO and texture coordinates at the end of the VBO.
If yes, then is it also true for indices? Can I store vertex indices and vertex attributes in the same VBO and bind it for DrawElements type of draw calls?
Thanks!
Yes, no need for interleaved data.
The last parameter of the gl-command glVertexAttribPointer() "Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0."
Just compute that offset on your own and pass it to the command.
Can I store vertex indices and vertex attributes in the same VBO and
bind it for DrawElements type of draw calls?
If you use different glVertexAttribPointer or different glDrawxx there's no problem.
What you can't do is reading vertices and indices at the same if they have different type (float vs integer) and stride.
When created, do VAOs track just VBO indices (via glBindVertexBuffer), or also which VBO names are bound to those indices? If I specify a binding index of, say, 0 using glVertexAttribBinding during VAO creation, can I bind a different VBO to index 0 just prior to a draw call and have it use the contents of that VBO, or will it always use whatever VBO was bound to index 0 at the time the VAO was created?
I ask because a lot of examples I find precede calls to glVertexAttribFormat and glVertexAttribBinding with a call to glBindVertexBuffer, which should not be necessary if the VAO tracks only indices (since the binding index is given in glVertexAttribBinding).
As you're probably aware, this is fairly new functionality introduced in OpenGL 4.3. The way I read the spec, the mapping between attributes and buffers now has a level of indirection:
Each attribute has a property that specifies which binding index it uses.
Buffers are bound to binding indices.
You can look at this as two tables, one defining a mapping from attribute index to binding index, the other one from binding index to buffer name. Both of these tables are part of the VAO state.
I believe these can be specified completely independently, and in any order. glVertexAttribBinding() establishes the first association, between attribute index and binding index. glBindVertexBuffer() establishes the association between binding index and buffer name.
This understanding is confirmed by the state table in the spec. Table 23.4 in the GL 4.4 spec, captioned "Vertex Array Object State", lists:
VERTEX_ATTRIB_BINDING, which can be queried with glGetVertexAttribiv(), is the value of the binding index of a given attribute index.
VERTEX_BINDING_BUFFER, which can be queried with glGetIntegeri_v(), is the value of the buffer name for a given binding index.
Based on this, addressing your specific questions:
When created, do VAOs track just VBO indices (via glBindVertexBuffer), or also which VBO names are bound to those indices?
They track both.
can I bind a different VBO to index 0 just prior to a draw call and have it use the contents of that VBO
Yes, if you bind a different VBO to binding index 0, all attributes with binding index 0 will use the content of that VBO.
a lot of examples I find precede calls to glVertexAttribFormat and glVertexAttribBinding with a call to glBindVertexBuffer, which should not be necessary if the VAO tracks only indices
The VAO tracks the state set by all these calls, so it does make sense to use all of them as part of setting up the VAO. Tracking the entire vertex setup state in a VAO is the main purpose of having VAOs in the first place. It allows you to set up the state once during initialization, and then you need only a single call to glBindVertexArray() before your draw calls to set up the entire state again.
The answer is that they DO NOT store vertex names, only indices. If you bind a different VBO to the same index in a different VAO, you must re-bind the first VBO again before any glDraw call that uses the first VAO.
At least on my Macbook Pro with:
Renderer: NVidia GeForce GT 650M OpenGL Engine
Version: 4.1 NVIDIA-10.0.43 310.41.05f01
If I'm trying to do some OpenGL 3.3+ style VBO graphics, is it alright for me to first, enable attribute arrays and set vertex attribute pointers, then in an often refreshing VBO, load fresh data and bind a GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER then call drawELements? I have code that is crashing on drawElements, and I'm wondering if its because the order of my calls is messed up. I'll also mention that this is under the guise of Qt 5.
Whn you set your attribute pointers, it is crucial to have the correct GL_ARRAY_BUFFER bound. The current GL_ARRAY_BUFFER_BINDING at the time of the glVertexAttribPointer() call will become part of that attribute pointer state. It does not matter which GL_ARRAY_BUFFER is bound at draw time (in contrast to the GL_ELEMENT_ARRAY_BUFFER which is relevant for the glDrawElements() family of GL functions.
Im trying to implement modern OpenGL, but the problem is: most tutorials are based on 3.3+, and talk about GLSL 330, I only have GLSL 130. Therefore, many things are apparently different, since my VBO's do not work.
Could you give me general hints or a tutorial that explains how to use GLSL 130 with VBO's? In my case, I have the vbo loaded, but when I use my shader program, only vertices called with glVertex get rendered, it's like the vbo gets ignored (no input). How to solve this?
And can you use VBO's without shaders? I tried to do that, but it crashed...
Yes, VBOs can still be used in GLSL 130, and can still be used even without shaders. The purpose of the VBO is to hold the vertex attributes for drawing. Most up to date tutorials I've seen have you use the layout position specifier for indicating how to address the different attributes in your shader, i.e.
layout(location = 0) in vec3 Position;
This isn't supported in GLSL 130, so you have to have another way of relating the attribute with the VBO. It's pretty simple... you can use glBindAttribLocation or glGetAttribLocation. Calling glGetAttribLocation will give you the identifier you need to use in glVertexAttribPointer to associate the VBO data with the particular attribute. You can call this at any time after the program has been compiled. In addition, you can call glBindAttribLocation to specifically set the identifier that will be associated with a given attribute name if you call it after you've created the program object but before you link the shaders. This is handy because it lets you decide for yourself what the location should be, just as you would be able to with the layout specifier.
Finally, if you want to use a VBO without using a shader at all, then you still have to find a way of associating the data in the VBO with the various inputs that the fixed function pipeline expects. This is done using a now deprecated method called glEnableClientState() and glVertexPointer(), which together let you tell OpenGL what fixed function pipeline attribute you're going to populate, and how it can find the data in the VBO.
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.