VertexArrayObject, how can i set "default" attribute value? - opengl

I'm developing an OpenGL application and I'm trying to make ShaderPrograms and VAO's independent of each other. Saying independent I mean that both ShaderProgram and VAO can have different set of attributes.
While creating new ShaderProgram I explicitly bind list of known attributes to predefined locations even if shader does not use them.
BindAttributeLocation(program, StandardAttribute.Position, PositionAttributeName);
BindAttributeLocation(program, StandardAttribute.Color, ColorAttributeName);
BindAttributeLocation(program, StandardAttribute.Normal, NormalAttributeName);
BindAttributeLocation(program, StandardAttribute.TexCoord, TexCoordAttributeName);
BindAttributeLocation(program, StandardAttribute.Tangent, TangentAttributeName);
Pretty same thing I'm trying to do with VAO, but if mesh does not contain data for attribute I want to set default value:
vao.Bind();
if(mesh.Color == null) {
DisableVertexAttribArray(attribute);
VertexAttrib4f(attribute, 1, 1, 1, 1);
}
else {
EnableVertexAttribArray(attribute);
buffer.Bind();
BufferData(mesh.Color);
VertexAttribPointer(attribute, ...);
}
This code seems to be working (so far), but I'm not sure if this is a correct approach. Where do VertexAttrib4f stores data: in VAO, or is it context global state and I need to reset it after each draw call?

The current attribute value is not part of the VAO state. The clearest statement in the spec that confirms this is in the description of glGetVertexAttrib() (emphasis added):
Note that all the queries except CURRENT_VERTEX_ATTRIB return values stored in the currently bound vertex array object
where CURRENT_VERTEX_ATTRIB is the value you set with glVertexAttrib4f().
This means that the values are global context state.

Okay, I found good article about this: opengl.org
A vertex shader can read an attribute that is not currently enabled
(via glEnableVertexAttribArray​). The value that it gets is defined by
special context state, which is not part of the VAO.
Because the attribute is defined by context state, it is constant over
the course of a single draw call. Each attribute index has a separate
value. Warning: Every time you issue a drawing command with an array
enabled, the corresponding context attribute values become undefined.
So if you want to, for example, use the non-array attribute index 3
after previously using an array in index 3, you need to repeatedly
reset it to a known value.
The initial value for these is a floating-point (0.0, 0.0, 0.0, 1.0)​.

Related

Understanding VAO, VBO and program

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.

If I do not explicitly bind the attributes using glVertexAttribPointer, what default locations will be used?

Refer to "Explicit vs Automatic attribute location binding for OpenGL shaders"
If I do not explicitly bind the attributes using glVertexAttribPointer, what default locations will be used?
Where can I find the official link for it?
Are you asking how generic attributes in a GLSL shader will be assigned to attribute slots (locations)?
That is completely implementation defined if you do not do it yourself. Some will scan the vertex shader and assign them locations in alphabetical order, others will assign them slots based on the order they appear in, but none of this behavior is required. It could be completely random and change every time you run your program for all you know.
That is why you either explicitly bind vertex attributes to a location before linking, or query the location afterwards.
I think you might be mixing up a couple of different concepts. The question you link is about how locations are assigned to attributes in the vertex shader. glBindAttribLocation() or glGetAttribLocation() are used for that purpose.
glVertexAttribPointer() on the other hand specifies where the data for a attribute comes from, together with some related state of the attribute (type, stride, etc). The specific attribute it works on is given by its location, which is passed as the first argument of the call.
Now, if you never call glVertexAttribPointer() for an attribute, there are a few possible scenarios:
An attribute array is not enabled for the attribute. This happens if glEnableVertexAttribArray() was never called for the attribute, or glDisableVertexAttribArray() was last called. In this case, the current value of the attribute is used, which is the value set with calls like glVertexAttrib4f(), with a default value of (0.0f, 0.0f, 0.0f, 1.0f).
If the attribute array is enabled, the default values correspond to a call of:
glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, NULL);
If you have a VBO bound, this could be valid, since the last argument is a relative offset into the buffer.
If you don't have a VBO bound, the draw call will most likely crash, since it will try to source vertex data from the given pointer address, which is NULL.
All of this can be found in the official OpenGL spec documents, which are accessible at https://www.opengl.org/registry/.

Do OpenGL Vertex Array Objects store vertex buffer names and indices, or only indices?

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

How to pass to a vertex-shader dynamic data that should apply for all vertices?

I've a simple program that draws an object, and I want its position to ultimately respond to user-input.
I've tried to create a buffer object with just 2 GLfloats to hold the position and pass it in location 1, and learned that it only affects the first vertex (which actually makes sense, now that I think about it).
I've thought about using uniforms but it doesn't seem to be the correct way either (I've read that changing them can be slow).
What's the approach to this in OpenGL 3/4?
You can achieve this either by using uniforms or vertex attributes. I would suggest using a vertex attribute in the event that you ever want the vertices to have a unique value per-vertex. You can achieve that simply by supplying a vertex pointer instead of a constant vertex attribute.
The following command applies a constant value to every instance of a vertex attribute:
glVertexAttrib{1|2|3|4}f[v] (...)

OpenGL default value for unbuffered vertex attribute when using layout qualifiers

I'm assuming this will be one of those things that is "undefined", but I can't seem to find a concrete answer from google.
Let's say in my vertex shader I have:
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec3 vNormal;
layout(location = 2) in vec4 vColour;
But there is nothing buffered to location 2 with glEnableVertexAttribArray() or glVertexAttribPointer(). Can I expect the value to be anything particular?
I was assuming for a vec4 that it would be along the lines of {0,0,0,0}, {0,0,0,1} or {1,1,1,1}, but in my case it is {0,0,1,1}.
When I previously used glBindAttribLocation() to specify the locations, it defaulted to {1,1,1,1} on 4 different machines using 3 different operating systems (ubuntu 12.04, windows 7, and ubuntu 10.04).
Is it safe to assume the value will be {0,0,1,1} across machines? or was this simply a coincidence?
Can I expect the value to be anything particular?
Yes, it is a particular value.
Assuming that you correctly turned off the attribute array (ie: with glDisableVertexAttribArray on that attribute index), the value you get comes from the in-context vertex attribute, as set by the glVertexAttrib suite of functions. These are global context state, not stored within the VAO.
By default, they all start at (0, 0, 0, 1). However, if you have rendered with a particular attribute using an array in that attribute index, the context value is effectively destroyed. So you should reset the context value if you want to use it.
They are kind of undefined here, but that might not be a problem. There GL state consists of the CURRENT_VERTEX_ATTRIB values. Initially, they are (0,0,0,1). You can explicitely set the attribute values for those attribs where no array is enabled via the glVertexAttrib() family of functions.
The only thing to worry is what happens to the current values when the attribute array is actually enabled during drawing. To quote the Spec (Version 3.3), Section 2.8.3 Vertex Arrays - Drawing Command:
If an array corresponding to a generic attribute required by a vertex shader
is not enabled, then the corresponding element is taken from the current generic
attribute state (see section 2.7).
If an array corresponding to a generic attribute required by a vertex shader is
enabled, the corresponding current generic attribute value is undefined after the
execution of DrawArraysOneInstance.
So jou just have to specify a useful value after you had drawn with an array enabled for that particular attribute.
UPDATE
This behavior has actually changed beginning with OpenGL 4.2:
If an array corresponding to a generic attribute required by a vertex shader is
not enabled, then the corresponding element is taken from the current generic attribute
state (see section 2.7). Otherwise, if an array is enabled, the corresponding
current generic attribute value is unaffected by the execution of DrawArraysOneInstance.
So now, a glDraw*() call will never modify the currently set attribute values.