Confusion about binding the index of a non-existent attribute using glVertexAttribPointer - opengl

When binding an attribute index using glVertexAttribPointer, what happens when an associated program does not contain an attribute at said index?
Is the behaviour undefined, or is the attribute ignored altogether?
I have searched the docs quite extensively, and have not been able to find much info about the link between programs and dynamic attribute bindings.

A program is not associated to a vertex array object. The vertex attribute index is the binding point. If a binding point is not "needed" by the program this doesn't cause any issue.
[...] What about if there is an attribute at that index but it is of a different type than of that earlier specified using glVertexAttribPointer [...]
OpenGL 4.6 API Core Profile Specification - 10.2.1 Current Generic Attributes, page 349:
When values for a vertex shader attribute variable are sourced from a current generic attribute value, the attribute must be specified by a command compatible with the data type of the variable.
This means if the data type of the attribute is floating point, then you've to specify the array of vertex attribute data by glVertexAttribPointer. If the data type is integral the you've to use glVertexAttribIPointer (focus on the I).
If you ignore that, then the data in the vertex array buffer will be misinterpreted.
OpenGL 4.6 API Core Profile Specification - 10.3.5 Transferring Array Elements, page 361:
When a vertex is transferred to the GL by DrawArrays, DrawElements, or the other Draw* commands described below, each generic attribute is expanded to four components. If size is one then the x component of the attribute is specified by the array; the y, z, and w components are implicitly set to 0, 0, and 1, respectively. If size is two then the x and y components of the attribute are specified by the array; the z and w components are implicitly set to 0 and 1, respectively. If size is three then x, y, and z are specified, and w is implicitly set to 1. If size is four then all components are specified.
So the tuple size of the vertex data and the tuple size of the data type of the vertex attribute in the shader program (e.g. float, vec2, vec3, ...) are allowed to be different.
If the tuple size of the vertex attribute in the program is greater, then the data are expanded by 0 for the 2md and 3rd respectively 1 for the 4th component.
If the tuple size of the vertex attribute in the program is less, then the additional components in the vertex array are "not used".

Related

Are OpenGL indices and locations the same thing for uniforms and vertex attributes?

In the OpenGL Reference Pages, some functions are marked as using uniform locations, while other functions are marked as using uniform indices. Are these the same thing?
Similarly for vertex attributes, some functions are marked as using vertex attribute indices, while other functions are marked as using vertex attribute locations. Are these the same?
In your first case, the location for an Uniform is different from the index used for glGetActiveUniform().
For glGetActiveUniform() case, index is just a value between 0 and the value you get from glGetProgram( GL_ACTIVE_UNIFORMS,...) minus one. This API allows you to query any resources of the program, and you can iterate over all active uniforms with that method. The uniform locations may not start at 0, and may not be consecutive at all.
In your second example, glGetAttribLocation() and glEnableVertexAttribArray() both refer to the same index. The GL has a set of generic attributes, which are generally referenced by their indices, starting from 0. However, to make things a little bit more interesting, there is also glGetActiveAttrib() which is similiar to the glGetActiveUniform() one: here, the index refers just to the list of active attributes (in the range 0 to the value you get from glGetProgram( GL_ACTIVE_ATTRIBUTES,...) minus one, and not to the actual attribute index/location. Again, this API allows you to iterate over all attributes which are present (and active).

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 I need to take care to pack vertex attributes together?

If I want to pass two nominally independent attribute arrays of floats to a draw call, can I happily have a GLSL in float variable for each of them, or do I need to ensure to pack them into an in vec2 or similar and use the various components to ensure not consuming unnecessary GL_MAX_VERTEX_ATTRIBS "slots"?
Or, in other words; GL_MAX_VERTEX_ATTRIBS specifies, according to the docs, "the maximum number of 4-component generic vertex attributes accessible to a vertex shader". Does an attribute that is less than 4 components always count as one attribute towards this limit?
Does an attribute that is less than 4 components always count as one attribute towards this limit?
Yes, that is exactly what it means.
Each vertex attribute is 4-component, if you write it as float in your shader that actually does not change anything. If you want to see this in action, try setting up a 1-component vertex attribute pointer and then declaring that attribute vec4 in your vertex shader -- GL will automatically assign the values 0.0, 0.0, 1.0 for y, z and w respectively.
If you are hitting the vertex attribute limit (minimum 16) because you're using a bunch of scalars, then you should consider packing your attributes into a vec4 instead for optimal utilization.
There is a minor exception to this rule I described above, for data types with more than 4-components (e.g. mat4). A vertex attribute declared mat4 has 16-components and consumes 4 sequential attribute locations.

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.

How to 'bind' a element buffer array to vertex array object using direct state access?

For the other buffers there are functions like:
glVertexArrayVertexAttribOffsetEXT(
this->handle, // vao handle
vbo.getHandle(), // vbo handle
index, // specifies the index of the generic vertex attribute to be modified.
size, // number of components per generic vertex attribute
vbo.getType(), // specifies the data type of each component in the array
normalized, // specifies whether fixed-point data values should be normalized
stride, // specifies the byte offset between consecutive generic vertex attributes
offset // specifies a pointer to the first component of the first generic vertex attribute in the array
);
But i can't find a method for binding the element buffer to the vao. Or am i missing something there?
PS: does it make sense to add vertex-array-object and direct-state-access tags?
You can't find it because it's not part of it.
The DSA extension was designed prior to VAO being part of GL3.0, and modified later on to interact with it. I would not be surprised it's a hole in the specification. Feel free to contact the specification owner (listed at the top of the extension)