GL_CURRENT_VERTEX_ATTRIB - doc clarification - opengl

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.

Related

Can you store the position attribute in an attribute number other than 0

In OpenGL, I always see that the position attribute is always placed at attribute 0. Is it possible for the position attribute to be at number 1? Why is the position attribute always at attribute 0?
Outside of the now-removed gl_Vertex built-in attribute, there is no such thing as a "position attribute." GLSL has no idea which attribute corresponds to a "position". They're all just numbers to your vertex shader; they only gain meaning when you assign something to gl_Position.
Which is a vertex shader output. How you generate the value for that output is none of GLSL's business.
That having been said, older versions of OpenGL did anoint attribute 0 with special powers. But these were mainly vestigial elements from fixed-function glBegin/End-style programming, and they were not required to have the meaning "position". The only special status it had was that you had to put something there. That is, you couldn't not use attribute 0.
But again, that's long-since been removed from OpenGL. Nowadays, people put a "position" there merely by habit.

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.

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

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

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.

Why does OpenGL drawing fail when vertex attrib array zero is disabled?

I was having extreme trouble getting a vertex shader of mine to run under OpenGL 3.3 core on an ATI driver:
#version 150
uniform mat4 graph_matrix, view_matrix, proj_matrix;
uniform bool align_origin;
attribute vec2 graph_position;
attribute vec2 screen_position;
attribute vec2 texcoord0;
attribute vec4 color;
varying vec2 texcoord0_px;
varying vec4 color_px;
void main() {
// Pick the position or the annotation position
vec2 pos = graph_position;
// Transform the coordinates
pos = vec2(graph_matrix * vec4(pos, 0.0, 1.0));
if( align_origin )
pos = floor(pos + vec2(0.5, 0.5)) + vec2(0.5, 0.5);
gl_Position = proj_matrix * view_matrix * vec4(pos + screen_position, 0.0, 1.0);
texcoord0_px = texcoord0;
color_px = color;
}
I used glVertexAttrib4f to specify the color attribute, and turned the attribute array off. According to page 33 of the 3.3 core spec, that should work:
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).
But (most of the time, depending on the profile and driver) the shader either didn't run at all or used black if I accessed the disabled color attribute. Replacing it with a constant got it to run.
Much searching yielded this page of tips regarding WebGL, which had the following to say:
Always have vertex attrib 0 array enabled. If you draw with vertex attrib 0 array disabled, you will force the browser to do complicated emulation when running on desktop OpenGL (e.g. on Mac OSX). This is because in desktop OpenGL, nothing gets drawn if vertex attrib 0 is not array-enabled. You can use bindAttribLocation() to force a vertex attribute to use location 0, and use enableVertexAttribArray() to make it array-enabled.
Sure enough, not only was the color attribute assigned to index zero, but if I force-bound a different, array-enabled attribute to zero, the code ran and produced the right color.
I can't find any other mention of this rule anywhere, and certainly not on ATI hardware. Does anyone know where this rule comes from? Or is this a bug in the implementation that the Mozilla folks noticed and warned about?
tl;dr: this is a driver bug. Core OpenGL 3.3 should allow you to not use attribute 0, but the compatibility profile does not, and some drivers don't implement that switch correctly. Just make sure to use attribute 0 to avoid any problems.
Actual Content:
Let's have a little history lesson in how the OpenGL specification came to be.
In the most ancient days of OpenGL, there was exactly one way to render: immediate mode (ie: glBegin/glVertex/glColor/glEtc/glEnd). Display lists existed, but they were always defined as simply sending the captured commands again. So while implementations didn't actually make all of those function calls, implementations would still behave as if they did.
In OpenGL 1.1, client-side vertex arrays were added to the specification. Now remember: the specification is a document that specifies behavior, not implementation. Therefore, the ARB simply defined that client-side arrays worked exactly like making immediate mode calls, using the appropriate accesses to the current array pointers. Obviously implementations wouldn't actually do that, but they behaved as if they did.
Buffer-object-based vertex arrays were defined in the same way, though with language slightly complicated by pulling from server storage instead of client storage.
Then something happened: ARB_vertex_program (not ARB_vertex_shader. I'm talking about assembly programs).
See, once you have shaders, you want to start being able to define your own attributes instead of using the built-in ones. And that all made sense. However, there was one problem.
Immedate mode works like this:
glBegin(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glEnd();
Every time you call glVertex, this causes all of the current attribute state to be used for a single vertex. All of the other immediate mode functions simply set values into the context; this function actually sends the vertex to OpenGL to be processed. That's very important in immediate mode. And since every vertex must have a position in fixed-function land, it made sense to use this function to decide when a vertex should be processed.
Once you're no longer using OpenGL's fixed-function vertex semantics, you have a problem in immediate mode. Namely, how do you decide when to actually send the vertex?
By convention, they stuck this onto attribute 0. Therefore, all immediate mode rendering must use either attribute 0 or glVertex to send a vertex.
However, because all other rendering is based on the language of immediate mode rendering, all other rendering has the same limitations of immediate mode rendering. Immediate mode requires attribute 0 or glVertex, and therefore so too do client-side arrays and so forth. Even though it doesn't make sense for them to, they need it because of how the specification defines their behavior.
Then OpenGL 3.0 came around. They deprecated immediate mode. Deprecated does not mean removed; the specification still had those functions in it, and all vertex array rendering was still defined in terms of them.
OpenGL 3.1 actually ripped out the old stuff. And that posed a bit of a language problem. After all, every array drawing command was always defined in terms of immediate mode. But once immediate mode no longer exists... how do you define it?
So they had to come up with new language for core OpenGL 3.1+. While doing so, they removed the pointless restriction on needing to use attribute 0.
But the compatibility profile did not.
Therefore, the rules for OpenGL 3.2+ is this. If you have a core OpenGL profile, then you do not have to use attribute 0. If you have a compatibility OpenGL profile, you must use attribute 0 (or glVertex). That's what the specification says.
But that's not what implementations implement.
In general, NVIDIA never cared much for the "must use attribute 0" rule and just does it how you would expect, even in compatibility profiles. Thus violating the letter of the specification. AMD is generally more likely to stick to the specification. However, they forgot to implement the core behavior correctly. So NVIDIA's too permissive on compatibility, and AMD is too restrictive on core.
To work around these driver bugs, simply always use attribute 0.
BTW, if you're wondering, NVIDIA won. In OpenGL 4.3, the compatibility profile uses the same wording for its array rendering commands as core. Thus, you're allowed to not use attribute 0 on both core and compatibility.