Many rendering systems implement a fixed number of parameterized shading models. The scene description language can choose among the types of light sources supported by the system, and specify one of the supported shading models for each surface along with the specific parameters for that surface. Clearly, such rendering systems significantly limit the range of effects that can be produced, and don't lend themselves to extensions when a new shading trick or a new type of procedural texture comes along. What we need is a systematic and modular way for specifying arbitrary complex and general shading mechanisms for 3D objects. In other words, we need a language for specifying shading. Such languages are referred to as "shading languages".
Shading languages were introduced by Cook in 1984 under the name of "Shade Trees". What is a shade tree? A shade tree can be viewed as a hierarchical data structure that describes a particular (complex) shading mechanism. Alternatively, it can be looked upon as a program for computing the shading on the objects with which the tree is associated. Note the strong analogy between shade trees and CSG trees (recall that a CSG tree is a hierarchical way of describing a solid, but it is also a program for computing the solid).
Before we explain what a shade tree is, we must define the a couple
of terms. An appearance parameter is any value that can be used
in a shading calculation: surface normal, the color of a light source,
the specular exponent of a surface, a bump map, etc. A shading operation
is any operation that can appear in a shading calculation, such as a dot
product, vector normalization, etc. Each node in a shade tree corresponds
to a basic shading operation. Each node produces one or more appearance
parameters as output, and can use zero or more appearance parameters as
input. Thus, a shade tree is really similar to the tree (or graph) that
a compiler constructs when it parses an arithmetic expression in a conventional
programming language, such as C. In order to evaluate the shading tree
it is traversed in postorder, performing the calculation corresponding
to each node after its children have been evaluated. The result of evaluating
the root node is the final output of the shading calculation. Thus, one
way to implement shade trees in a rendering system is to define a high-level
programming language for specifying shading calculations. This language
enables programmers to write shaders as routines with input parameters
and output values. These shaders can be compiled or interpreted to produce
the corresponding shade tree, which is then evaluated by the renderer as
needed.
Light source shaders are given various parameters describing the light source and a point in the scene and return the color of the light reaching the specified point from the corresponding light source. There can be any number of such shaders in the scene, and each one can be turned on or off for any object in the scene.
Surface shaders computes the reflected light in a given outgoing direction at a point on a surface, using the normal, the light sources, and perhaps other information.
Volume shaders are associated with volumes of space both inside and outside the objects of a scene. They describe what happens to a ray of light passing through the volume from a specified origin to a specified destination. A volume shader can be associated with the interior of an object, with the exterior of an object, and with the atmosphere in the scene.
Transformation shaders lie on the blurred border between geometry and shading. They take a point in space and produce another point. They can use arbitrary defomations of space, and they are concatenated with the scene transformation.
Displacement shaders are somewhat similar to transformation shaders, but instead of deforming the entire space of the scene they perturb points on the surface of an object. Thus, they may use the properties of the surface at the point to be displaced, such as the normal, or any other property of interest.
Imager shaders transfrom an input color to another set of values, whose meaning can be arbitrary.
Data types:
float - the only scalar type in the language, no integers!
string - can't be modified
point - a vector of three floats
color - an abstract data type for representing colors, reflectances,
opacities, etc.
A variety of operators and functions that operate of these data types
is built into the RenderMan shading language.
A shader is defined by preceeding its declaration with one of the shading language keywords: light, displacement, surface, volume, transformation, or imager. Shaders can use functions, which are defined similarly to C. Functions can return float, color, point, or string. The default return type is float. All function parameters are by reference. Recursion is forbidden. Shaders and functions are specified similarly, except that the shader does not explicitly return values. Functions can be called by other shaders or functions, but shaders can't.
Global Variables: shaders can assume that certain global variables
have been assigned valid values by the renderer before the shader is called.
For example, a surface shader typically requires at least the point where
the the reflected light is to be computed, and the direction of interest.
This information is provided by the global point variable P and
I, respectively. Other global variables serve as a means for the shader
to communicate its results to the renderer. In surface shaders those variables
are Ci and Oi, which represent color of light from surface and opacity
of surface, respectively.
Instance variables: In the RenderMan interface, shaders are
instanced in the course of the scene description. For example, different
instances of light shaders are defined to place light sources in the scene,
and surface shaders are instanced by attaching them to surfaces of objects
in the scene. When the shader is instanced, it may use several instance
variables as parameters. For example, a surface shader may have the instance
parameters Ka and Kd defined. When attaching the surface shader to the
surface, values for these parameters can be specified. These variables
must have default values assigned to them when they are declared in the
definition of the shader.
Shader classes and instances: RenderMan shaders resemble classes in an object-oriented language, such as C++. There is a general shader class from which the six main shader types are inherited. Whenever we write a RenderMan shader we inherit one of these six types. Writing a shader is like writing a class with a single public member function. The instance variables of the shader correspond to data members of the class (data members that are set once and for all by the class constructor, when an object of that class is defined). The global variables correspond to the parameters of the member function. When a particular shader is attached to a surface in the scene, this corresponds to creating an instance of the class with the instance variable given as arguments to the class constructor.
Uniform and varying variables: All variables in the shading language (including instance variables) can be classified as uniform or varying. Uniform variables are variables that do not depend on position. Varying variables can change as a function of position. For example, the parametric coordinates of the position on the surface (s,t) are varying variables. The normal N is a varying variable for curved surfaces, but a uniform variable for planar surfaces. The distinction between uniform and varying variables is important, because it allows to significantly optimize the shader, once it has been bound to a particular surface.
Built-in functions: For ease of programming, many useful built-in
functions are provided in RenderMan. These include many scalar math functions
(sin(), radians(), sqrt(), clamp(), round(), etc), derivative functions
(Du(), Dv()), a noise() function (in one, two, or three directions, returning
either a point or a color), and various shading, coloring,
and lighting functions: ambient(), diffuse(), phong(), specular(). There
are also functions for access to texture maps, bump maps, environment maps,
and shadow maps. Various geometric functions operating on points and normals
are also provided.