OpenGL default value for unbuffered vertex attribute when using layout qualifiers - opengl

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.

Related

GL_CURRENT_VERTEX_ATTRIB - doc clarification

The OpenGL 4 docs says:
GL_CURRENT_VERTEX_ATTRIB
params returns four values that represent the current value for the
generic vertex attribute specified by index. Generic vertex attribute
0 is unique in that it has no current state, so an error will be
generated if index is 0. The initial value for all other generic
vertex attributes is (0,0,0,1).
What does it mean in practice that "an error will be generated if index is 0" ?
Let's assume that I have a vertex shader with the following layout:
layout (location = 0) in vec3 pos;
I want to set a generic(constant) vertex attribute.
Can I use glVertexAttrib3f with an index which is equal 0 ?
glVertexAttrib3f(0, 1, 0, 0);
Later I would like to check the current vertex attribute this way:
glGetVertexAttribfv(0, GL_CURRENT_VERTEX_ATTRIB, data);
Is it correct ?
The text in the documentation is incorrect, relative to core OpenGL 3.2 or above. In the core profile of OpenGL, attribute 0 has state and that state can be queried.
In the compatibility profile up to 4.5 (and all GL versions before 3.0), attribute 0 does not have state. 4.5 changed the compatibility profile to give attribute 0 state. Indeed, the specification specifically calls this change out:
This is a change in behavior of the compatibilty[sic] profile for increased interoperability with core profile and OpenGL ES.
That all having been said, you really should just pretend that the generic attribute values don't exist. Since they are so rarely used, their performance characteristics are unknown. And the values of them are somewhat ephemeral; if you set a value, render something, then render something that uses an array for that attribute, the value you previously set will not be preserved, requiring you to set it again. This is quite unlike most OpenGL state.

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).

GLSL 410 default layout qualifier

I was putting together a small demo in OpenGL 4.1 last night and accidentally omitted the layout qualifier for my vertex positions:
layout(location = 0) in vec3 position;
Even though I forgot this line in my vertex shader, everything worked as normal. I was only using a single attribute, by the way. Is this behavior in the standard or did I just get lucky in my implementation?
The GLSL standard says
If a vertex shader input variable with no location assigned in the shader text has a location specified
through the OpenGL API, the API-assigned location will be used. Otherwise, such variables will be
assigned a location by the linker.
So the question becomes about the rest of your program. Were there any calls to glBindAttribLocation or glGetAttribLocation​?
If not you got lucky. Here's what OpenGL 4.1 core says (sect 2.11):
When a program is linked, any active attributes without a binding specified either through BindAttribLocation or explicitly set within the shader text will automatically be bound to vertex attributes by the GL. Such bindings can be queried using the command GetAttribLocation.
LinkProgram will fail if the assigned binding of an active attribute variable would cause the GL to reference a non-existent generic attribute (one greater than or equal to the value of MAX_VERTEX_ATTRIBS).
and a skim of the rest of the spec reveals an absence of discussion about attribute location allocation, meaning that it is up to some undefined mechanism to choose the binding.

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.

Usage of custom and generic vertex shader attributes in OpenGL and OpenGL ES

Since generic vertex attributes are deprecated in OpenGL, I tried to rewrite my vertex shader using only custom attributes. And I didn't work for me. Here is the vertex shader:
attribute vec3 aPosition;
attribute vec3 aNormal;
varying vec4 vColor;
vec4 calculateLight(vec4 normal) {
// ...
}
void main(void) {
gl_Position = uProjectionMatrix * uWorldViewMatrix * vec4(aPosition, 1);
vec4 rotatedNormal = normalize(uWorldViewMatrix * vec4(aNormal, 0));
vColor = calculateLight(rotatedNormal);
}
This works perfectly in OpenGL ES 2.0. However, when I try to use it with OpenGL I see black screen. If I change aNormal to generic gl_Normal everything works fine aswell (note that aPosition works fine in both contexts and I don't have to use gl_Vertex).
What am I doing wrong?
I use RenderMonkey to test shaders, and I've set up stream mapping in it with appropriate attribute names (aPosition and aNormal). Maybe it has something to do with attribute indices, becouse I have all of them set to 0? Also, here's what RenderMonkey documentation says about setting custom attribute names in "Stream Mapping":
The “Attribute Name” field displays the default name that can be
used in the shader editor to refer to that stream. In an OpenGL ES effect, the changed
name should be used to reference the stream; however, in a DirectX or OpenGL effect,
the new name has no affect in the shader editor
I wonder is this issue specific to RenderMonkey or OpenGL itself? And why aPosition still works then?
Attribute indices should be unique. It is possible to tell OpenGL to use specific indices via glBindAttribLocation before linking the program. Either way the normal way is to query the index with glGetAttribLocation. It sounds like RenderMonkey lets you choose, in which case have you tried making them separate?
I've seen fixed function rendering cross over to vertex attributes before, where glVertexPointer can wind up binding to the first attribute if its left unbound (I don't know if this is reproducible any more).
I also see some strange things when experimenting with attributes and fixed function names. Without calling glBindAttribLocation, I compile the following shader:
attribute vec4 a;
attribute vec4 b;
void main()
{
gl_Position = gl_Vertex + vec4(gl_Normal, 0) + a + b;
}
and I get the following locations (via glGetActiveAttrib):
a: 1
b: 3
gl_Vertex: -1
gl_Normal: -1
When experimenting, it seems the use of gl_Vertex takes up index 0 and gl_Normal takes index 2 (even if its not reported). I wonder if you throw in a padding attribute between aPosition and aNormal (don't forget to use it in the output or it'll be compiled away) makes it work.
In this case it's possible the position data is simply bound to location zero last. However, the black screen with aNormal points to nothing being bound (in which case it will always be {0, 0, 0}). This is a little less consistent - if the normal was bound to the same data as the position you'd expect some colour, if not correct colour, as the normal would have the position data.
Applications are allowed to bind more than one user-defined attribute
variable to the same generic vertex attribute index. This is called
aliasing, and it is allowed only if just one of the aliased attributes
is active in the executable program, or if no path through the shader
consumes more than one attribute of a set of attributes aliased to the
same location.
My feeling is then that RenderMonkey is using just glVertexPointer/glNormalPointer instead of attributes, which I would have though would bind both normal and position to either the normal or position data since you say both indices are zero.
in a DirectX or OpenGL effect, the new name has no affect in the shader editor
Maybe this means "named streams" are simply not available in the non-ES OpenGL version?
This is unrelated, but in the more recent OpenGL-GLSL versions, a #version number is needed and attributes use the keyword in.