Legacy Shaders

Legacy Shaders

The shaders described below are basic shaders, embodying "classic" shading techniques without taking advantage of modern updates to the shading language. Additional "old school" shaders are included with the RenderMan Pro Server distribution and can be found in $RMANTREE/lib/shaders but, aside from the Standard RenderMan Interface Shaders included therein, should be considered "interesting historical relics."


Surface Shaders

Surface shaders inherit the surface variables of the surfaces to which they are attached. A surface shader should always set the output color Ci and optionally the output opacity Oi that is emitted in the direction -I. I is the direction of the ray incident to the surface. The length of this vector is equal to the distance between the origin of the ray and the point on the surface. Thus the actual origin of the ray is available as P-I.

Turbulence

The following surface shader implements a simple turbulence procedural texture. The shader computes the texture by adding various octaves of noise, weighting each octave by 1/f, where f is the cutoff frequency of that octave. This texture is then used to modulate the opacity of the surface. The texture is generated in the named coordinate system "marble", which must have been established with by the use of an RiCoordinateSystem("marble") call before the instantiation of the turbulence shader. Notice that after the opacity has been computed, it is multiplied into the color, so that the colors and opacities output by the shader are premultiplied for use by pixel compositors.

surface
turbulence (float Kd=.8, Ka=.2)
{
    float a, scale, sum ;
    float IdotN;
    point M;

    /* convert to texture coordinate system */
    M = transform("marble", P);

    scale = 1;
    sum = 0;

    a = sqrt(area(M));

    while (a < scale) {
             sum += scale * float noise(M/scale);
             scale *= 0.5;
    }

    Oi = sum;
    Ci = Cs * Oi * (Ka + Kd * I.N * I.N / (I.I * N.N));
}

Ray tracer

The following is a procedure to implement a Turner Whitted-style ray tracer.

surface
whitted(
    float Ka =.8;        /* ambient coefficient */
    float Kd =.8;        /* diffuse coefficient */
    float Ks =.2;        /* specular coefficient */
    float Kss = 2;       /* specular exponent */
    float Kr =.8;        /* reflective coefficient */
    float Kt =.2;)       /* transmissive coefficient */
{
    vector Nn, H, T;
    float eta, eta2;

    /* Retrieve the relative index of refraction */
    if (incident("eta", eta) && opposite("eta", eta2))
            eta /= eta2;
    else
            eta = 1.0;

    Nn = faceforward(normalize(N), I);

    /* ambient term */
    Ci = Ka * ambient();

    /* diffuse and specular terms */
    illuminance(P, Nn, PI/2) {
            /* diffuse */
            Ci += Kd * Cl * L.Nn;

            /* specular */
            H = normalize(normalize(L)+I);
            Ci += Ks * Cl * pow(max(0,0, Nn.H), Kss);
    }

    /* reflection */
    Ci += Kr * trace(P, reflect(I, Nn));

    /* transmittance */
    T = refract(I, Nn, eta);
    if (length(T) != 0.0)
            Ci += Kt * trace(P, T);
}

Light Sources

There are several types of light source shaders, distinguished by their directional properties. The directional properties of light sources depend on whether the sources execute a solar or an illuminate statement. Light source shaders without explicit illuminate or solar``* statements are assumed to be non-directional, or *ambient*. The total amount of ambient light incident on a surface is normally returned to a surface shader through ``ambient. A solar statement indicates that the light source is a directional light source, while an illuminate statement indicates that the light source is a local light source. Local light sources have a position. The position can be a property of the shader or can be inherited from a surface. If the light source is attached to a geometric primitive the light source is an area light source.

Light sources set Cl inside a solar or illuminate block unless they are defining an ambient light. Inside these blocks the direction L points towards the surface. This variable is available so that light source output intensities can be directional. If the light source has a position, the length of L is the distance from the light source to the surface being shaded.

For example, consider the following light source:

light
phong(
       float intensity = 1.0;
       color color = 1;
       float size = 2.0;
       point from = point "shader" (0,0,0);
       point to = point "shader" (0,0,1);)
{
       uniform point R = normalize(to-from);

       solar(R, PI/2)
              Cl = intensity * color * pow(R.L/length(L), size);
}

The Phong shading model can be interpreted to be a procedural directional light source. The light source has a direction R and a size parameter that controls its fall-off. The solar statement specifies that the light source casts light in the forward facing hemisphere.

An environment background light source would be specified as follows:

light
reflection(string texturename = ""; float intensity = 1.0)
{
   solar()
          Cl = intensity * color environment(texturename, -L);
}

The solar statement implies the light is cast from infinity in all directions. The color of the light is given by the environment map.


Volume Shader

Volume shaders change Ci and Oi due to volumetric scattering, self-luminosity, and attenuation. A volume shader is called once per ray so it should explicitly integrate along the path of the ray.

The input Ci and Oi are the colors and opacities at the point P. The volume shader should set the color and opacity that result at the point P-I.

volume
fog( float distance = 1; color background = 0 )
{
     float d;

     d = 1 - exp( -length(I)/distance );
     Ci = mix( Ci, background, d );
     Oi = mix( Oi, color (1,1,1), d ); /* background is opaque. */
}

Displacement and Transformation Shaders

Displacement shaders move the position P of a surface. After a point of the surface is moved, the normals should be recalculated with calculatenormal unless the new normals can be computed as part of the displacement.

Transformation shaders specify a nonlinear transformation of all points in space to new points. Since transformation shaders are not bound to surfaces, they do not have access to the standard surface shader variables such as u and Cs.

The following shader places a sinusoidal bump on a surface.

displacement
ripple(float amplitude = 1.0, wavelength = 0.25)
{
    P += N * amplitude * sin(2 * PI * (s / wavelength));
    N = calculatenormal(P);
}

Imager Shaders

Imager shaders change the value of Ci and Oi. The exposure and quantization process specified in the section on Displays could be specified as the following imager:

imager
exposure(float gain=1.0, gamma=1.0, one = 255, min = 0, max = 255)
{
     Ci = pow(gain * Ci, 1/gamma);
     Ci = clamp(round(one * Ci), min, max);
     Oi = clamp(round(one * Oi), min, max);
}