4.3. Built-in Uniform Variables
OpenGL was designed as a state machine. It has a variety of state that can be set. At the time graphics primitives are provided to OpenGL for rendering, the current state settings affect how the graphics primitives are treated and ultimately how they are rendered into the frame buffer.
Some applications heavily utilize this aspect of OpenGL. Large amounts of application code might be dedicated to manipulating OpenGL state and providing an interface to allow the end user to change state to produce different rendering effects.
The OpenGL Shading Language makes it easy for these types of applications to take advantage of programmable graphics technology. It contains a variety of built-in uniform variables that allow a shader to access current OpenGL state. In this way, an application can continue to use OpenGL as a state management machine and still provide shaders that combine that state in ways that aren't possible with the OpenGL fixed functionality path. Because they are defined as uniform variables, shaders are allowed to read from these built-in variables but not to write to them.
The built-in uniform variables in Listing 4.1 allow shaders to access current OpenGL state. Any of these variables can be accessed from within either vertex shaders or fragment shaders. If an OpenGL state value has not been modified by an application, it contains the default value as defined by OpenGL, and the corresponding built-in uniform variable is also equal to that value.
Listing 4.1. Built-in uniform variables
As you can see, these built-in uniform variables have been defined so as to take advantage of the language features whenever possible. Structures are used as containers to group a collection of parameters such as depth range parameters, material parameters, light source parameters, and fog parameters. Arrays define clip planes and light sources. Defining these uniform variables in this way improves code readability and allows shaders to take advantage of language capabilities like looping.
The list of built-in uniform variables also includes some derived state. These state values are things that aren't passed in directly by the application but are derived by the OpenGL implementation from values that are passed. For various reasons, it's convenient to have the OpenGL implementation compute these derived values and allow shaders to access them. The normal matrix (gl_NormalMatrix) is an example of this. It is simply the inverse transpose of the upper-left 3 x 3 subset of the modelview matrix. Because it is used so often, it wouldn't make sense to require shaders to compute this from the modelview matrix whenever it is needed. Instead, the OpenGL implementation is responsible for computing this whenever it is needed, and it is accessible to shaders through a built-in uniform variable.
Here are some examples of how these built-in uniform variables might be used. A vertex shader can transform the incoming vertex position (gl_Vertex) by OpenGL's current modelview-projection matrix (gl_ModelViewProjectionMatrix) with the following line of code:
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
Similarly, if a normal is needed, it is transformed by the current normal matrix:
tnorm = gl_NormalMatrix * gl_Normal;
(The transformed normal would typically also need to be normalized in order to be used in lighting computations. This normalization can be done with the built-in function normalize, which is discussed in Section 5.4.)
Here are some other examples of accessing built-in OpenGL state:
gl_FrontMaterial.emission // emission value for front material gl_LightSource.ambient // ambient term of light source #0 gl_ClipPlane // first component of user clip plane #3 gl_Fog.color.rgb // r, g, and b components of fog color gl_TextureMatrix // 3rd column, 4th component of 2nd // texture matrix
The mapping of OpenGL state values to these built-in variables should be straightforward, but if you need more details, see the OpenGL Shading Language Specification document.