4.1. The Vertex Processor
The vertex processor executes a vertex shader and replaces the fixed functionality OpenGL per-vertex operations. Specifically, when the vertex processor is executing a vertex shader, the following fixed functionality operations are affected:
The following fixed functionality operations are applied to vertex values that are the result of executing the vertex shader:
The basic operation of the vertex processor was discussed in Section 2.3.1. As shown in Figure 2.2, data can come into the vertex shader through attribute variables (built in or user defined), uniform variables (built in or user defined), or texture maps (a vertex processing capability that is new with the OpenGL Shading Language). Data exits the vertex processor through built-in varying variables, user-defined varying variables, and special vertex shader output variables. Built-in constants (described in Section 4.4) are also accessible from within a vertex shader. A vertex shader has no knowledge of the primitive type for the vertex it is working on.
OpenGL has a mode that causes color index values to be produced rather than RGBA values. However, this mode is not supported in conjunction with vertex shaders. If the frame buffer is configured as a color index buffer, behavior is undefined when a vertex shader is used.
4.1.1. Vertex Attributes
To draw things with OpenGL, applications must provide vertex information such as normal, color, texture coordinates, and so on. These attributes can be specified one vertex at a time with OpenGL functions such as glNormal, glColor, and glTexCoord. When set with these function calls, the attributes become part of OpenGL's current state.
Geometry can also be drawn with vertex arrays. With this method, applications arrange vertex attributes in separate arrays containing positions, normals, colors, texture coordinates, and so on. By calling glDrawArrays, applications can send a large number of vertex attributes to OpenGL in a single function call. Vertex buffer objects (i.e., server-side storage for vertex arrays) were added in OpenGL 1.5 to provide even better performance for drawing vertex arrays.
Vertex attributes come in two flavors: standard and generic. The standard attributes are the attributes as defined by OpenGL; these are color, secondary color, color index, normal, vertex position, texture coordinates, edge flag, and the fog coordinate. The color index attribute, which sets the current color index, and the edge flag attribute are not available to a vertex shader (but the application is allowed to send the edge flags to OpenGL while using a vertex shader). A vertex shader accesses the standard attributes with the following built-in names. A compiler error is generated if these names are used in a fragment shader.
// // Vertex Attributes // attribute vec4 gl_Color; attribute vec4 gl_SecondaryColor; attribute vec3 gl_Normal; attribute vec4 gl_Vertex; attribute vec4 gl_MultiTexCoord0; attribute vec4 gl_MultiTexCoord1; attribute vec4 gl_MultiTexCoord2; // . . . up to gl_MultiTexCoordN-1 where N = gl_MaxTextureCoords attribute float gl_FogCoord;
Details on providing generic vertex attributes to a vertex shader through the OpenGL Shading Language API are provided in Section 7.7.
Both standard attributes and generic attributes are part of the current OpenGL state. That means that they retain their values, once set. An application is free to set values for all generic and all standard attributes and count on OpenGL to store them (except for vertex position, see Section 7.7). However, the number of attributes a vertex shader can use is limited. Typically, this limit is smaller than the sum of all the standard and generic attributes. This limit is implementation specific and can be queried with glGet with the symbolic constant GL_MAX_VERTEX_ATTRIBS. Every OpenGL implementation is required to support at least 16 vertex attributes in a vertex shader.
To signal the end of one vertex, the application can set either the standard vertex attribute gl_Vertex or the generic vertex attribute with index zero. The gl_Vertex attribute is set with the glVertex command or one of the vertex array commands, and the generic attribute with index zero is set with glVertexAttrib with an index of zero. These two commands are equivalent, and either one signals the end of a vertex.
4.1.2. Uniform Variables
Shaders can access current OpenGL state through built-in uniform variables containing the reserved prefix "gl_". For instance, the current modelview matrix can be accessed with the built-in variable name gl_ModelViewMatrix. Various properties of a light source can be accessed through the array containing light parameters as in gl_LightSource.spotDirection. Any OpenGL state used by the shader is automatically tracked and made available to the shader. This automatic state-tracking mechanism enables the application to use existing OpenGL state commands for state management and have the current values of such state automatically available for use in the shader.
OpenGL state is accessible to both vertex shaders and fragment shaders by means of the built-in uniform variables defined in Section 4.3.
Applications can also define their own uniform variables in a vertex shader and use OpenGL API calls to set their values (see Section 7.8 for a complete description). There is an implementation-dependent limit on the amount of storage allowed for uniform variables in a vertex shader. The limit refers to the storage for the combination of built-in uniform variables and user-defined uniform variables that are actually used in a vertex shader. It is defined in terms of components, where a component is the size of a float. Thus, a vec2 takes up two components, a vec3 takes three, and so on. This value can be queried with glGet with the symbolic constant GL_MAX_VERTEX_UNIFORM_COMPONENTS.
4.1.3. Special Output Variables
Earlier we learned that results from the vertex shader are sent on for additional processing by fixed functionality within OpenGL, including primitive assembly and rasterization. Several built-in variables are defined as part of the OpenGL Shading Language to allow the vertex shader to pass information to these subsequent processing stages. The built-in variables discussed in this section are available only from within a vertex shader.
The variable gl_Position writes the vertex position in clipping coordinates after it has been computed in a vertex shader. Every execution of a wellformed vertex shader must write a value into this variable. Compilers may generate an error message if they detect that gl_Position is not written or read before being written, but not all such cases are detectable. Results are undefined if a vertex shader is executed and it does not store a value into gl_Position.
The built-in variable gl_PointSize writes the size (diameter) of a point primitive. It is measured in pixels. This allows a vertex shader to compute a screen size that is related to the distance to the point, for instance. Section 4.5.2 provides more details on using gl_PointSize.
If user clipping is enabled, it occurs as a fixed functionality operation after the vertex shader has been executed. For user clipping to function properly in conjunction with the use of a vertex shader, the vertex shader must compute a vertex position that is relative to the user-defined clipping planes. This value must then be stored in the built-in variable gl_ClipVertex. It is up to the application to ensure that the clip vertex value computed by the vertex shader and the user clipping planes are defined in the same coordinate space. User clip planes work properly only under linear transform. More details on using gl_ClipVertex are contained in Section 4.5.3.
These variables each have global scope. They can be written to at any time during the execution of the vertex shader, and they can be read back after they have been written. Reading them before writing them results in undefined behavior. If they are written more than once, the last value written will be the one that is consumed by the subsequent operations.
These variables can be referenced only from within a vertex shader and are intrinsically declared with the following types:
vec4 gl_Position; // must be written to float gl_PointSize; // may be written to vec4 gl_ClipVertex; // may be written to
4.1.4. Built-in Varying Variables
As explained previously, varying variables describe attributes that vary across a primitive. The vertex shader is responsible for writing values that need to be interpolated into varying variables. The fragment shader reads the interpolated results from varying variables and operates on them to produce a resulting value for each fragment. For each user-defined varying variable actually used by the fragment shader, there must be a matching varying variable declared in the vertex shader; otherwise, a link error occurs.
To properly communicate with the fixed functionality of OpenGL, the OpenGL Shading Language defines a number of built-in varying variables. A vertex shader can write certain varying variables that are not accessible from the fragment shader, and a fragment shader can read certain varying variables that were not accessible from the vertex shader.
The following built-in varying variables can be written in a vertex shader. (Those available from a fragment shader are described in Section 4.2.1.) The vertex shader should write to those that are required for the desired fixed functionality fragment processing (if no fragment shader is to be used), or to those required by the corresponding fragment shader.
varying vec4 gl_FrontColor; varying vec4 gl_BackColor; varying vec4 gl_FrontSecondaryColor; varying vec4 gl_BackSecondaryColor; varying vec4 gl_TexCoord; // at most will be gl_MaxTextureCoords varying float gl_FogFragCoord;
Values written to gl_FrontColor, gl_BackColor, gl_FrontSecondaryColor, and gl_BackSecondaryColor are clamped to the range [0,1] by fixed functionality when they exit the vertex shader. These four values and the fixed functionality to determine whether the primitive is front facing or back facing are used to compute the two varying variables gl_Color and gl_SecondaryColor that are available in the fragment shader.
One or more sets of texture coordinates can be passed from a vertex shader with the gl_TexCoord array. This makes the coordinates available for fixed functionality processing if no fragment shader is present. Alternatively, they can be accessed from within a fragment shader with the gl_TexCoord varying variable. Index values used to reference this array must be constant integral expressions or this array must be redeclared with a size. The maximum size of the texture coordinate array is implementation specific and can be queried with glGet with the symbolic constant GL_MAX_TEXTURE_COORDS. Using array index values near 0 may aid the implementation in conserving resources consumed by varying variables.
For gl_FogFragCoord, the value written should be the one required by the current fog coordinate source as set by a previous call to glFog. If the fog coordinate source is set to GL_FRAGMENT_DEPTH, the value written into gl_FogFragCoord should be the distance from the eye to the vertex in eye coordinates (where the eye position is assumed to be (0, 0, 0, 1)). If the fog coordinate source is set to GL_FOG_COORDINATE, the value written into gl_FogFragCoord should be the fog coordinate value that is to be interpolated across the primitive (i.e., the built-in attribute variable gl_FogCoord).
4.1.5. User-Defined Varying Variables
Vertex shaders can also define varying variables to pass arbitrary values to the fragment shader. Such values are not clamped, but they are subjected to subsequent fixed functionality processing such as clipping and interpolation. There is an implementation-dependent limit to the number of floating-point values that can be interpolated. This limit can be queried with glGet with the symbolic constant GL_MAX_VARYING_FLOATS.