Vertex Shader

From OpenGL Wiki
(Redirected from Vertex Attribute)
Jump to navigation Jump to search

The Vertex Shader is the programmable Shader stage in the rendering pipeline that handles the processing of individual vertices. Vertex shaders are fed Vertex Attribute data, as specified from a vertex array object by a drawing command. A vertex shader receives a single vertex from the vertex stream and generates a single vertex to the output vertex stream. There must be a 1:1 mapping from input vertices to output vertices.

Vertex shaders typically perform transformations to post-projection space, for consumption by the Vertex Post-Processing stage. They can also be used to do per-vertex lighting, or to perform setup work for later shader stages.

Invocation frequency[edit]

The OpenGL specification is fairly lenient on the number of times a vertex shader is invoked by the rendering system. Vertex Specification and Vertex Rendering define a vertex stream: an ordered sequence of vertices to be consumed. The vertex shader will be executed roughly once for every vertex in the stream.

A vertex shader is (usually) invariant with its input. That is, within a single Drawing Command, two vertex shader invocations that get the exact same input attributes will return binary identical results. Because of this, if OpenGL can detect that a vertex shader invocation is being given the same inputs as a previous invocation, it is allowed to reuse the results of the previous invocation, instead of wasting valuable time executing something that it already knows the answer to.

OpenGL implementations generally do not do this by actually comparing the input values (that would take far too long). Instead, this optimization typically only happens when using indexed rendering functions. If a particular index is specified more than once (within the same Instanced Rendering), then this vertex is guaranteed to result in the exact same input data.

Therefore, implementations employ a cache on the results of vertex shaders. If an index/instance pair comes up again, and the result is still in the cache, then the vertex shader is not executed again. Thus, there can be fewer vertex shader invocations than there are vertices specified.

However, you are guaranteed to have at least one vertex shader invocation for every unique set of attributes you use.

Note: It is entire possible that the invocation frequency of the vertex shader can change if Tessellation is active. Particularly if a Tessellation Control Shader is active. So the tricks you might play to save vertex shader invocations may not work when tessellating. Then again, they may work just as well. However, it is assured that they will not save you TCS invocations, as the TCS cannot use these optimizations.

Inputs[edit]

User-defined input values to vertex shaders are sometimes called "vertex attributes". Their values are provided by issuing a drawing command while an appropriate vertex array object is bound.

Vertex shader input variables are defined as normal for shader stages, using the in type qualifier. Vertex Shader inputs cannot be aggregated into Interface Blocks.

Each user-defined input variable is assigned one or more vertex attribute indices. These can be explicitly assigned in one of three ways. The methods for assigning these are listed in priority order, with the highest priority first. The higher priority methods take precedence over the later ones.

In-shader specification
The shader defines the attribute index. This is done using the layout(location = #) syntax:
layout(location = 2) in vec4 a_vec;
This assigns the attribute a_vec the index 2.
Pre-link specification
Before linking a program that includes a vertex shader, the user may tell OpenGL to assign a particular attribute to a particular index. This is done with the following function:
 void glBindAttribLocation(GLuint program​, GLuint index​, const GLchar *name​);
index​ is the attribute index to assign. name​ is the name of the vertex shader input to assign the given index to.
Note that it is perfectly legal to use this function to assign indices to names that are not mentioned in the vertex shader. The linking process will only use the names that are actually used by the vertex shader. Because of that, it is also perfectly legal to assign multiple names to the same index; this is only an error if a shader attempts to use both of the names that use the same index.
Automatic assignment
If neither of the prior two methods assign an input to an attribute index, then the index is automatically assigned by OpenGL when the program is linked. The index assigned is completely arbitrary and may be different for different programs that are linked, even if they use the exact same vertex shader code.

Note that like uniforms, vertex attributes can be "active" and non-active. Active inputs are those that the compiler/linker detects are actually in use. The vertex shader and GLSL program linking process can decide that some input are not in use and therefore they are not active. This is done even if an explicit attribute index is assigned in the vertex shader.

The active attributes can be queried via program introspection, either through the new, generic API or the old API.

Multiple attributes[edit]

Attributes may be arrays, matrices, and double-precision types (if OpenGL 4.1 or ARB_vertex_attrib_64bit is available). Or combinations of any of these. Some of these types are large enough to require that the input variable be assigned to multiple attribute indices.

Matrix inputs take up one attribute index for every column. Array attributes take up one index per element, even if the array is a float and could have use up to 4 indices.

Double-precision input variables of double or dvec types always take up one attribute. Even if they are dvec4.

These combine with each other. A mat2x4[2] array is broken up into four vec4 values, each of which is assigned an index. Thus, it takes up 4 indices; the first two indices specify the two columns of array index 0, and the next two indices specify the two columns of array index 1.

When an input requires multiple indices, it will always be assigned sequential indices starting from the given index. Consider:

layout(location = 3) in mat4 a_matrix;

a_matrix will be assigned attribute indices 3, 4, 5, and 6. This works regardless of what methods you use to assign vertex attribute indices to input variables.

Linking will fail if any index ranges collide. Thus, this will fail to link:

layout(location = 0) in mat4 a_matrix;
layout(location = 3) in vec4 a_vec;

Because a_matrix has four columns, it will take up the attribute indices on the range [0, 3]. That overlaps with a_vec's attribute index, and thus a linking error will occur.

This will also fail, assuming the implementation only allows 16 attribute indices:

layout(location = 0) in mat4 a_matrix1;
layout(location = 5) in mat4 a_matrix2;
layout(location = 10) in mat4 a_matrix3;
in mat4 bad_matrix;

Even though there are 4 total attribute indices available after the a_matrix* indices are assigned, they cannot be assigned sequentially. There is no attribute index for bad_matrix that will allow it to get 4 sequential indices. Thus, the linker will fail.

Attribute limits[edit]

In general, the number of attribute indices are the limitation on them. No attribute can be assigned an index higher than GL_MAX_VERTEX_ATTRIBS.

There is a case which makes this more complex: double-precision attributes (if OpenGL 4.1 or ARB_vertex_attrib_64bit is available). dvec3 and dvec4 only take up one attribute index. But implementations are allowed to count them twice when determining the limits on the number of attributes. Thus, while a dmat2x3[4] will only take up 8 attribute indices (4 array elements of 2 columns of dvec3s), the implementation is allowed to consider this as taking up 16 indices when determining if a shader is using up too many attribute indices. As such, a dmat2x3[5] may fail to link even though it only uses 10 attribute indices.

Note the use of the word "allowed". The implementation is free to count them only once, but you can't rely on it. So you need to assume that these will consume two input resources, even though they only use one index. Since there is no way to query whether any particular implementation will count them twice, you must assume that they will take up two resources.

Other inputs[edit]

V · E

Vertex Shaders have the following built-in input variables.

in int gl_VertexID;
in int gl_InstanceID;
in int gl_DrawID; // Requires GLSL 4.60 or ARB_shader_draw_parameters
in int gl_BaseVertex; // Requires GLSL 4.60 or ARB_shader_draw_parameters
in int gl_BaseInstance; // Requires GLSL 4.60 or ARB_shader_draw_parameters
gl_VertexID
the index of the vertex currently being processed. When using non-indexed rendering, it is the effective index of the current vertex (the number of vertices processed + the first​ value). For indexed rendering, it is the index used to fetch this vertex from the buffer.
Note: gl_VertexID will have the baseVertex​ parameter added to the index, if there was such a parameter in the rendering command.
gl_InstanceID
the index of the current instance when doing some form of instanced rendering. The instance count always starts at 0, even when using base instance calls. When not using instanced rendering, this value will be 0.
Warning: This value does not follow the baseInstance​ provided by some instanced rendering functions. gl_InstanceID always falls on the half-open range [0, instancecount​). If you have GLSL 4.60, you may use gl_BaseInstance to compute the proper instance index.
gl_DrawID
the index of the drawing command within multi-draw rendering commands (including indirect multi-draw commands). The first draw command has an ID of 0, increasing by one as the renderer passes through drawing commands.
This value will always be a Dynamically Uniform Expression.
gl_BaseVertex
the value of the baseVertex​ parameter of the rendering command. If the rendering command did not include that parameter, the value of this input will be 0.
gl_BaseInstance
the value of the baseInstance​ parameter of the instanced rendering command. If the rendering command did not include this parameter, the value of this input will be 0.

Outputs[edit]

Output variables from the vertex shader are passed to the next section of the pipeline. Many of the next stages are optional, so if they are not present, then the outputs are passed to the next one that is. They are in this order:

  1. Tessellation. If no Tessellation Control Shader is present, the Tessellation Evaluation Shader will get them.
  2. Geometry Shader
  3. Vertex Post-Processing

User-defined output variables can have interpolation qualifiers (though these only matter if the output is being passed directly to the Vertex Post-Processing stage). Vertex shader outputs can also be aggregated into Interface Blocks.


V · E

Vertex Shaders have the following predefined outputs.

out gl_PerVertex
{
  vec4 gl_Position;
  float gl_PointSize;
  float gl_ClipDistance[];
};

gl_PerVertex defines an interface block for outputs. The block is defined without an instance name, so that prefixing the names is not required.

These variables only take on the meanings below if this shader is the last active Vertex Processing stage, and if rasterization is still active (ie: GL_RASTERIZER_DISCARD is not enabled). The text below explains how the Vertex Post-Processing system uses the variables. These variables may not be redeclared with interpolation qualifiers.

gl_Position
the clip-space output position of the current vertex.
gl_PointSize
the pixel width/height of the point being rasterized. It only has a meaning when rendering point primitives. It will be clamped to the GL_POINT_SIZE_RANGE.
gl_ClipDistance
allows the shader to set the distance from the vertex to each user-defined clipping half-space. A non-negative distance means that the vertex is inside/behind the clip plane, and a negative distance means it is outside/in front of the clip plane. Each element in the array is one clip plane. In order to use this variable, the user must manually redeclare it with an explicit size. With GLSL 4.10 or ARB_separate_shader_objects, the whole gl_PerVertex block needs to be redeclared. Otherwise just the gl_ClipDistance built-in needs to be redeclared.

See also[edit]