Making Shadows with RenderMan

Making Shadows with RenderMan

April 1991

Introduction

Adding shadows is one of the most effective ways of adding realism to a computer-generated image. The human visual system uses shadows to determine depth, light location, and direction, as well as spatial relationships between objects. PhotoRealistic RenderMan supports shadows using a shadow map algorithm. This algorithm is a compromise between shadow quality, ease of use, and rendering efficiency. Using a ray tracing algorithm to make shadows offers greater ease of use and higher quality, but at a price of slow execution speed and incompatibility with the other PhotoRealistic RenderMan rendering algorithms. Other algorithms, such as drop shadows (computing the shadow projection onto a surface, and adding dark-colored geometry to represent the shadow), are more efficient but much less flexible than shadow mapping. [1] The shadow map algorithm offers significantly more efficiency if multiple frames are to be rendered that have the same light locations and attributes.


Basic Method

The basic shadow map method is relatively easy to use, but it is not automatic. For each light that casts a shadow a shadow map image must be rendered. This image is rendered from the location of the light source. The image is then converted into a format suitable for use by special light shaders that can use the map to selectively light the scene. This selective lighting produces shadows. The basic approach is shown in Figure 1, below. [2] Each type of light must be handled differently to ensure that proper shadows are produced.

Direction of view

For lights that have a direction (such as spotlights and distant lights), the view for the shadow image is in the light direction. Point lights are handled differently, as will be explained later.

Camera translation

Listing 1 shows placecam.c, a simple program used to calculate the RenderMan transforms needed to place the camera at the light position and point it in the proper direction, given a location and aim point. These transforms are used as the camera transform for the map image. For lights with only a location (point lights) a translation to place the light at the origin is needed. This translation is simply the negation of the light's location components. The direction is computed in a special way described later.

Projections

Lights that are located at a point, such as spot lights and point lights, should have their shadow maps rendered using a perspective projection. The field of view for the perspective projection for a spot light should be calculated from the light cone angle. The cone angle for the standard RenderMan shaders is half the angle of the illuminated cone and is measured in radians, but the perspective field of view is measured in degrees and is the complete angle. The formula to convert from a cone angle to a field of view (fov) is:

fov = coneangle*360/p

The placecam program can also calculate the required field of view for a spot light using the above formula.

Point lights have an effective solid illumination angle of 360°. We can't make a shadow map covering this large an angle, so we need to make six shadow maps to cover the complete solid angle. These maps are made in the six major directions in world space: +x, -x, +y, -y, +z, -z. In order to avoid artifacts at the edges of these shadow maps they should be made with a field of view larger than 90°; 95° is usually sufficient. A rotation is added to the shadow image camera transform to point the camera in the correct direction. The RIB calls to perform the rotations are as follows:

Rotate -90, 0, 1, 0   # +X    -90° about the y axis
Rotate  90, 0, 1, 0   # -X     90° about the y axis
Rotate  90, 1, 0, 0   # +Y     90° about the x axis
Rotate -90, 1, 0, 0   # -Y    -90° about the x axis
Rotate   0, 0, 1, 0   # +Z     No Rotate needed
Rotate 180, 0, 1, 0   # -Z    180° about the y axis

Lights that come from a direction but have no location, such as distant lights, should have their shadow maps rendered using an orthographic projection. Orthographic projections have no field of view, so the area covered by the shadow map image is controlled by the ScreenWindow setting. ScreenWindow values are easy to calculate because they are just the extents of the scene in the camera space x and y directions. A description of setting a distant light map image ScreenWindow appears later in this document.

Shadow maps

When a shadow image is rendered, the zfile display driver is used to write a depth image of the scene. This image contains the depth of the first surface encountered at each image pixel. The format of the z file must be changed to a shadow texture file format before it is used to make an image. The image is reformatted using MakeShadow during rendering or using the txmake utility with the -shadow option from the command line.

Finally, special shadow light shaders must be used to access the shadow map during final image creation. These shaders use the shadow() shading language function to access the map. See Listing 2 (the shader code for the shadowdistant light shader) for an example of accessing a shadow map. Three shadow light shaders are provided with Developer's RenderMan: shadowdistant, shadowspot, and shadowpoint. Implementing the above procedure to produce shadows in your images will work, but it will not produce the highest image quality or be as efficient as possible. Several more complex issues must be addressed to produce optimal shadows.


Quality and Speed Issues

There are two major quality issues to be addressed when making images with shadows: self-shadowing and shadow map resolution. The former can actually affect the appearance of the object that casts the shadow; the latter affects the shadow's edges. There are also ways to create shadow maps as efficiently as possible.

Self-shadowing

Self-shadowing occurs when, because of numerical inaccuracies or other problems, shadows are incorrectly produced on the object that should be casting the shadow. In PhotoRealistic RenderMan, self-shadowing is avoided by having a "tolerance" around objects. No shadow will be cast on a point inside this tolerance. The tolerance is called the shadow bias. While there are two RIB calls used to set the bias, for our purposes they should both use the same value. Shadow bias must be set correctly or two different types of artifacts can be produced. If the bias is too small self-shadowing will occur and spots of shadow will appear on objects in the scene at inappropriate locations. If the bias is too large shadows will appear to be detached from objects. This is especially noticeable when an object is resting on and casting shadows on the same surface. To see examples of these two problems, render the file biasshad.rib to produce the required shadow map and then bias.rib with each of the five bias values in the RIB file.

Shadow map resolution

The number of pixels in a shadow map controls both the quality of the shadows in an image and the rendering time for the map. If there are too few pixels the individual shadow pixels will be visible in the image. This will give the shadows a jagged appearance or it will cause the edges of the shadow to be ragged. If the resolution is too high time is wasted rendering unnecessary pixels. Render resshad.rib with each of the resolutions given in the file and, for each new map, render res.rib to see the effect of the map resolution. The lowest-resolution map also shows that the correct bias value depends on the resolution of the map. For this reason, it is a good idea to test shadow bias at the resolution of the final image.

Shadow map rendering efficiency

When making a shadow map we want to use as many of the calculated pixels as possible; it makes no sense to spend time rendering pixels we won't use. This means we should only include an object, or part of an object, in the shadow map if it casts a shadow visible in the final image. We can control the absolute resolution of a shadow map using the Format statement, as with any RenderMan image. We control the objects included in the shadow map using either the "fov" parameter when using perspective projection, or the ScreenWindow parameters when using orthographic projection.

For additional efficiency you can, of course, remove objects from a RIB file when making the shadow maps. This will prevent these objects from casting shadows. Removing objects, especially if they cover a large area of the screen, can decrease rendering times substantially. This technique is often useful for objects that form the background in an image, since they usually cast no shadows and often cover large areas of the screen. Notice that the background patch in resshad.rib has been removed to speed up the shadow map rendering. Various special effects also require removing objects from the shadow map RIB files.


Examples of Making Shadows

Listing 8 (noshad.rib) is a RIB file with a distant, a spot and a point light, but no shadows. Listing 9 (allshad.rib) is the same, but includes the shadows. The RIB files distant.rib, spot.rib, and the set pointpx.rib, pointpy.rib, pointpz.rib, pointnx.rib, pointny.rib, and pointnz.rib show examples of making shadows for all three basic light types. All of these images show nine cylinders in a corner formed by three bilinear patches. A distant light comes from the top front right corner. A spot light with a 24° cone angle is located near the top front right corner. A point light is located where the middle pin in a setup would be, at a height of about two units above the floor patch.

For each shadow map we use the same rendering parameters and we remove all the shaders (Surface and LightSource statements) from the file. As a result, we'll get the maximum rendering speed without affecting the shadow quality. If there were displacement shaders we would leave them in the shadow map files because they would change the geometry of the scene and might affect the shadow map images. The zfile driver is used in each Display statement. At the end of each shadow map file, after WorldEnd, we added a MakeShadow statement to convert from the z file format to the shadow map file format. When examining the camera transforms in the RIB files, remember that transforms are applied in bottom-to-top order in RenderMan.

Distant light shadows

First, let's examine how we set up the shadow RIB file for the distant light. First we calculated the camera transform to make the shadow map. This was easy in our example because the distant light was in world space, so all we had to do is run the placecam program with the distant light "from" and "to" parameters. If any transforms had been active for the LightSource statement we would have had to apply these transforms to the "from" and "to" parameters before using placecam. We then added the orthographic projection needed for a distant light camera.

The hardest part of setting up the distant light shadow was to limit the view of the camera to cover only the objects that should cast shadows. We used a trial-and-error method to determine the parameters needed by the ScreenWindow statement. First we tried a default ScreenWindow of -1 1 -1 1. This was too small because it didn't cover all the cylinders. Next we tried -2 2 -2 2; this was too big on the right and bottom and too small on the top. We tried -2 1.8 -1.8 2.2; not too bad, but still too big on the right side. Finally we settled on -2 1.3 -1.8 2.2, which fits the cylinders well. We tried all these tests displaying to a framebuffer, using a very small window (64x64) after commenting out the MakeShadow statement.

Now that we had a shadow RIB file with the correct camera setup and rendering parameters (after we restored the Display and MakeShadow calls), we needed a first estimate for the image size to use for the shadow map generation. A good first try is a map size similar to the image size, in this case 256x256. Remember, a shadow map's size must be a power of two in both directions.

Spot light shadows

The shadow map RIB file for the spot light was generated in a similar manner, except it was easier to get the correct field of view for the camera. First we calculated the camera parameters using placecam and the "from", "to", and "coneangle" values from the spot light statement. The statements from placecam were used directly in the RIB file, as indicated in Listing 12, spot.rib. We started with a Format statement of 256 256 1 again as a first estimate for the correct shadow map size.

Point light shadows

The RIB files used for point light shadows were easy to build, but we needed six of them, one for each major world space direction (negative and positive x, y, and z). The camera transform for a point light consists of a Rotate statement to point the camera in the correct direction and a Translate statement to place the camera at the point light location. The Translate call simply negates the "from" coordinates of the point light source, moving the camera back to that point. The Rotate calls were described above. The shadow maps were made with a "perspective" projection and an "fov" greater than 90°. We used 95° here.

Adding maps to the image file

At this point we had files to make the shadow maps, but we still needed to modify the image file to use these maps. For the distant light we replaced the shader name "distantlight" with "shadowdistant" and added a "shadowname" parameter with the correct shadow map name. For the spot light we replaced the shader name "spotlight" with "shadowspot" and added the correct "shadowname" parameter. Finally, for the point light we replaced "pointlight" with "shadowpoint" and added the six file name parameters "sfpx", "sfnx", "sfpy", "sfny", "sfpz" and "sfnz".


Final Tune-up

The eight files (six for the point light, and one each for the spot and distant lights) are all the basic RIB files we need to create and use the shadow maps for our demonstration images, but we still needed to do some test renderings to determine the correct shadow bias value and map resolutions for good image quality.

A rule of thumb for setting the bias is to use 1% of the largest extent of the objects included in the image, measured in camera space. Unfortunately this number may be difficult to calculate for RIB files with complex geometry. A trial and error method is often best. Remember, bias too large will cause shadows to be "separated" from their objects and a bias too small will cause random dark spots on objects. We used a trial-and-error method and found a value of 0.1 to be correct for this image.

During our test rendering we found the shadow from the distant light to be of low quality because the map resolution was too low. We increased the resolution to 512x512 and this improved the shadow quality. The resolution of the spot light map seemed to be reasonable, and the resolution of the point light map was quite good.


Summary

We have now described and given examples for using the PhotoRealistic RenderMan shadow capabilities for an end user with access to RIB files. It was never intended for end users to have to follow this procedure, because we hoped all modeling program writers would include support for automatically making shadows in their programs when they added RenderMan support. Modeling programs have access to all of the model data and the power of the computer allowing them to use even more powerful techniques to produce shadows using RenderMan.


Example Files

Listing 1

placecam.c
/*
 * PlaceCamera(): establish a viewpoint, viewing direction and orientation
 *    for a scene. This routine must be called before RiWorldBegin().
 *    position: a point giving the camera position
 *    aim: a point giving the location at which the camera is aimed
 *    roll: an optional rotation of the camera about its direction axis
 *    coneangle: an optional spotlight shader cone angle
 */

#include <math.h>
#define PI 3.1415926535897932

usage()
{
    printf("usage:    placecam pos_x pos_y pos_z aim_x aim_y aim_z\n");
    printf(" [coneangle] [roll_angle]\n");
    printf(" Calculate RenderMan transforms needed for camera transform\n");
    printf(" from light position to aim point with the given roll angle.\n");
    exit(1);
}

typedef double        RtPoint[3];

main(int argc, char *argv[])
{
    RtPoint pos, aim, dir;
    double roll;
    double coneangle, fov;

    if (argc < 7) usage();

    pos[0] = atof(argv[1]);
    pos[1] = atof(argv[2]);
    pos[2] = atof(argv[3]);
    aim[0] = atof(argv[4]);
    aim[1] = atof(argv[5]);
    aim[2] = atof(argv[6]);


    if (argc > 6) coneangle = atof(argv[7]);
    else coneangle = 0.0;

    if (argc > 7) roll = atof(argv[8]);
    else roll = 0.0;

    printf("position: %0.2f, %0.2f, %0.2f\n", pos[0], pos[1], pos[2]);
    printf("aim:      %0.2f, %0.2f, %0.2f\n", aim[0], aim[1], aim[2]);
    printf("coneangle: %0.4f\n", coneangle);
    printf("roll:      %0.2f\n\n", roll);

    if (coneangle != 0.0) {
      fov = coneangle * 360.0 / PI;
      printf("Projection \"perspective\" \"fov\" [%0.2f]\n", fov);
    }

    dir[0] = aim[0] - pos[0];
    dir[1] = aim[1] - pos[1];
    dir[2] = aim[2] - pos[2];

    PlaceCamera(pos, dir, roll);
}

void
PlaceCamera(position, direction, roll)
    RtPoint position, direction;
    float roll;
{
    RiRotate(-roll, 0.0, 0.0, 1.0);
    AimZ(direction);
    RiTranslate(-position[0], -position[1], -position[2]);
}

/*
 * AimZ(): rotate the world so the direction vector points in
 *    positive z by rotating about the y axis, then x. The cosine
 *    of each rotation is given by components of the normalized
 *    direction vector.  Before the y rotation the direction vector
 *    might be in negative z, but not afterward.
 */
AimZ(direction)
RtPoint direction;
{
    double xzlen, yzlen, yrot, xrot;

    if (direction[0]==0 && direction[1]==0 && direction[2]==0)
      return;
    /*
     * The initial rotation about the y axis is given by the projection of
     * the direction vector onto the x,z plane: the x and z components
     * of the direction.
     */
    xzlen = sqrt(direction[0]*direction[0]+direction[2]*direction[2]);
    if (xzlen == 0)
      yrot = (direction[1] < 0) ? 180 : 0;
    else
      yrot = 180*acos(direction[2]/xzlen)/PI;

    /*
     * The second rotation, about the x axis, is given by the projection on
     * the y,z plane of the y-rotated direction vector: the original y
     * component, and the rotated x,z vector from above.
     */
    yzlen = sqrt(direction[1]*direction[1]+xzlen*xzlen);
    xrot = 180*acos(xzlen/yzlen)/PI;   /* yzlen should never be 0 */

    if (direction[1] > 0)
      RiRotate(xrot, 1.0, 0.0, 0.0);
    else
      RiRotate(-xrot, 1.0, 0.0, 0.0);
    /* The last rotation declared gets performed first */
    if (direction[0] > 0)
      RiRotate(-yrot, 0.0, 1.0, 0.0);
    else
      RiRotate(yrot, 0.0, 1.0, 0.0);
}

void
RiRotate(double angle, double x, double y, double z)
{
    if (fabs(angle) > 0.001) {
      printf("Rotate %0.2f %0.2f %0.2f %0.2f\n", angle, x, y, z);
    }
}
void
RiTranslate(double dx, double dy, double dz)
{
    printf("Translate %0.2f %0.2f %0.2f\n", dx, dy, dz);
}

Listing 2

shadowdistant.sl
/* @(#)shadowdistant.sl 1.1 (Pixar - RenderMan Division) 3/16/90 */

/*-______________________________________________________________________
**
**Copyright© 1988 Pixar.  All rights reserved.  This program or
**documentation contains proprietary confidential information and trade
**secrets of Pixar.  Reverse engineering of object code is prohibited.
**Use of copyright notice is precautionary and does not imply
**publication.
**
**RESTRICTED RIGHT NOTICE
**
**Use, duplication, or disclosure by the Government is subject to
**restrictions as set forth in subdivision (b)(3)(ii) of the Rights in
**Technical Data and Computer Software clause at 252.227-7013.
**
**Pixar
**1001 W. Cutting Blvd.
**Richmond, CA  94804
**
**_____________________________________________________________
*/

light
shadowdistant(
    float intensity=1 ;
    color lightcolor=1 ;
    point from = point "shader" (0,0,0) ;
    point to = point "shader" (0,0,1) ;
    string shadowname="";
    float samples=16;
    float width=1;
)
{
    solar( to - from, 0.0 ) {
      Cl = intensity * lightcolor;
      if (shadowname != "") {
          Cl *= 1 - shadow(shadowname, Ps, "samples", samples,
                      "swidth", width, "twidth", width);
          }
    }
}

Listing 3

biasshad.rib
##RenderMan RIB
version 3.03

#shadow map frame
#these parameters speed up map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

Display "bias.z" "zfile" "z"
Format 256 256 1

Projection "perspective" "fov" [24.00]

Rotate -27.12 1.00 0.00 0.00
Rotate -129.81 0.00 1.00 0.00
Translate 5.00 -4.00 -5.00

WorldBegin

TransformBegin
Scale 2.5 0.5 1.5
Surface "plastic"
Color .3 .6 .8
Polygon "P" [-0.5 -7.5 0 -0.5 7.5 0 2 7.5 0 2 -7.5 0]
TransformEnd

Cylinder 0.25 0 1.5 360
Disk 1.5 0.25 360

WorldEnd

MakeShadow "bias.z" "bias.shd"

Listing 4

bias.rib
##RenderMan RIB
version 3.03

#image frame
#Option "shadow" "bias0" [.02]        #grey spots, much too small
#Option "shadow" "bias1" [.02]
#Option "shadow" "bias0" [.05]        #grey spots at top, too small
#Option "shadow" "bias1" [.05]
Option "shadow" "bias0" [.1]          #ok
Option "shadow" "bias1" [.1]
#Option "shadow" "bias0" [.25]        #separation cylinder base, too big
#Option "shadow" "bias1" [.25]
#Option "shadow" "bias0" [1]          #complete separation, much too big
#Option "shadow" "bias1" [1]

Display "bias.tif" "tiff" "rgba"
Format 256 256 -1

Projection "perspective" "fov" [20]

Rotate -100 0 0 1
Rotate -10 1 0 0
Rotate -123 0 1 0
Translate 5 -0.5 -4

WorldBegin

LightSource "ambientlight" 1 "intensity" [0.05]
LightSource "shadowspot" 2 "intensity" [40]
 "coneangle" [0.20944]"conedeltaangle" [0.0174533]
 "from" [-5 4 5] "to" [1 0 0] "shadowname" ["bias.shd"]

TransformBegin
Scale 2.5 0.5 1.5
Surface "plastic"
Color .3 .6 .8
Polygon "P" [-0.5 -7.5 0 -0.5 7.5 0 2 7.5 0 2 -7.5 0]
TransformEnd

Surface "plastic"
Color [0.9 0.9 0.5]

Cylinder 0.25 0 1.5 360
Disk 1.5 0.25 360

WorldEnd

Listing 5

resshad.rib
##RenderMan RIB
version 3.03

#shadow map frame
#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

Display "res.z" "zfile" "z"

#These two resolutions show the effect of too few map pixels
#Format 64 64 1       #too low
#Format 256 256 1     #ok
Format 512 512 1      #very good (but slow to render and big)

Projection "perspective" "fov" [24.00]

Rotate -27.12 1.00 0.00 0.00
Rotate -129.81 0.00 1.00 0.00
Translate
5.00 -4.00 -5.00

WorldBegin

Cylinder 0.25 0 1.5 360
Disk 1.5 0.25 360

WorldEnd

MakeShadow "res.z" "res.shd"

Listing 6

res.rib
##RenderMan RIB
version 3.03

#image frame
Option "shadow" "bias0" [.1]          #ok
Option "shadow" "bias1" [.1]

Display "" "framebuffer" "rgba"
Format 256 256 -1

Projection "perspective" "fov" [20]

Rotate -100 0 0 1
Rotate -10 1 0 0
Rotate -123 0 1 0
Translate 5 -0.5 -4

WorldBegin

LightSource "ambientlight" 1 "intensity" [0.05]
LightSource "shadowspot" 2 "intensity" [40]
 "coneangle" [0.20944]"conedeltaangle" [0.0174533]
 "from" [-5 4 5] "to" [1 0 0] "shadowname" ["res.shd"]

TransformBegin
Scale 2.5 0.5 1.5
Surface "plastic"
Color .3 .6 .8
Polygon "P" [-0.5 -7.5 0 -0.5 7.5 0 2 7.5 0 2 -7.5 0]
TransformEnd

Surface "plastic"
Color [0.9 0.9 0.5]

Cylinder 0.25 0 1.5 360
Disk 1.5 0.25 360

WorldEnd

Listing 7

Imagegeometry.rib
TransformBegin
    Scale 2 0.33333 1
    Surface "plastic"

    Color .2 .4 .6
    Polygon "P" [-0.5 -7.5 0 -0.5 7.5 0 2 7.5 0 2 -7.5 0]

    Color .6 .4 .2
    Polygon "P" [-0.5 -7.5 0 2 -7.5 0 2 -7.5 5 -0.5 -7.5 5]

    Color .2 .6 .4
    Polygon "P" [2 -7.5 0 2 7.5 0 2 7.5 5 2 -7.5 5]
TransformEnd

Surface "plastic"
ObjectBegin 1
    Cylinder 0.15 0 1.35 360
    Disk 1.35 0.15 360
ObjectEnd

Color [0.9 0.9 0.5]

TransformBegin
    Translate 0 0 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
TransformEnd

TransformBegin
    Translate 1.03923 0.6 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -1.2 0
      ObjectInstance 1
    TransformEnd
TransformEnd

TransformBegin
    Translate 2.07846 1.2 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -2.4 0
      ObjectInstance 1
    TransformEnd
TransformEnd

TransformBegin
    Translate 3.11769 1.8 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -1.2 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -2.4 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -3.6 0
      ObjectInstance 1
    TransformEnd
TransformEnd

Listing 8

noshad.rib
##RenderMan RIB
version 3.03

Display "" "framebuffer" "rgba" "origin" [128 0]
#Format 256 192 -1
Format 128 96 -1

Projection "perspective" "fov" [28.0725]

Rotate -90 0 0 1
Rotate -3.83777 1 0 0
Rotate -116.565 0 1 0
Translate 5 -0.5 -4

WorldBegin

LightSource "ambientlight" 1 "intensity" [0.05]
LightSource "spotlight" 2 "intensity" [40]
 "coneangle" [0.20944]"conedeltaangle" [0.0174533]
 "from" [-5 2 5]"to" [2 0 0]
LightSource "pointlight" 3 "intensity" [3]"from" [2.07846 0 1]

    /* The contents of Listing 7: Imagegeometry.rib go here */

WorldEnd

Listing 9

allshad.rib
##RenderMan RIB
version 3.03

Option "shadow" "bias0" [0.1]                 #ok
Option "shadow" "bias1" [0.1]

Display "allshad.tif" "tiff" "rgba"
Format 256 192 -1

Projection "perspective" "fov" [28.0725]

Rotate -90 0 0 1
Rotate -3.83777 1 0 0
Rotate -116.565 0 1 0
Translate 5 -0.5 -4

WorldBegin

LightSource "ambientlight" 1 "intensity" [0.05]
LightSource "shadowdistant" 2 "intensity" [1]
 "from" [-5 5 5] "to" [2 0 0] "shadowname" ["distant.shd"]
LightSource "shadowspot" 2 "intensity" [40]
 "coneangle" [0.20944] "conedeltaangle" [0.0174533]
 "from" [-5 2 5]"to" [2 0 0] "shadowname" ["spot.shd"]
LightSource "shadowpoint" 3 "intensity" [3] "from" [2.07846 0 1]
 "sfpx" ["pointpx.shd"] "sfnx" ["pointnx.shd"]
 "sfpy" ["pointpy.shd"] "sfny" ["pointny.shd"]
 "sfpz" ["pointpz.shd"] "sfnz" ["pointnz.shd"]

    /* The contents of Listing 7: Imagegeometry.rib go here */

WorldEnd

Listing 10

Shadowgeometry.rib
ObjectBegin 1
    Cylinder 0.15 0 1.35 360
    Disk 1.35 0.15 360
ObjectEnd

TransformBegin
    Translate 0 0 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
TransformEnd

TransformBegin
    Translate 1.03923 0.6 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -1.2 0
      ObjectInstance 1
    TransformEnd
TransformEnd

TransformBegin
    Translate 2.07846 1.2 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -2.4 0
      ObjectInstance 1
    TransformEnd
TransformEnd

TransformBegin
    Translate 3.11769 1.8 0
    TransformBegin
      Translate 0 0 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -1.2 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -2.4 0
      ObjectInstance 1
    TransformEnd
    TransformBegin
      Translate 0 -3.6 0
      ObjectInstance 1
    TransformEnd
TransformEnd

Listing 11

distant.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "distant.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect
ratio should be 1
Format 512 512 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#orthographic projection is used for distant light shadows
Projection "orthographic"

#screen window values to include relevant geometry in shadow map
ScreenWindow -2 1.3 -1.8 2.2

#transform to place camera at distant light "from" and aim at "to"
Rotate -30.17 1.00 0.00 0.00
Rotate -125.54 0.00 1.00 0.00
Translate 5.00 -5.00 -5.00

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "distant.z" "distant.shd"

Listing 12

spot.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "spot.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 512 512 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for spot light shadows
#the "fov" should match the spot light cone angle converted properly
#here the "coneangle" is 0.20944 radians so the "fov" is 24 degrees
#the equation used is fov = coneangle * 360.0 / PI
Projection "perspective" "fov" [24.00]

#transform to place camera at spot light "from" and aim at "to",
# taken from placecam
Rotate -13.09 1.00 0.00 0.00
Rotate -125.54 0.00 1.00 0.00
Translate 5.00 -2.00 -5.00

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "spot.z" "spot.shd"

Listing 13

pointnx.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "pointnx.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 256 256 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for point light shadows
#the "fov" should be > 90.0 to eliminate map edge artifacts
Projection "perspective" "fov" [95.0]

#transform to place camera at point light "from"
#aim in the negative x direction by rotating 90 degrees about the y axis
Rotate 90.0 0.0 1.0 0.0
Translate -2.07846 -0 -1

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "pointnx.z" "pointnx.shd"

Listing 14

pointny.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "pointny.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 256 256 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for point light shadows
#the "fov" should be > 90.0 to eliminate map edge artifacts
Projection "perspective" "fov" [95.0]

#transform to place camera at point light "from"
#aim in the negative y direction by rotating -90 degrees about the x axis
Rotate -90.0 1.0 0.0 0.0
Translate -2.07846 -0 -1

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "pointny.z" "pointny.shd"

Listing 15

pointnz.rib

##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "pointnz.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 256 256 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for point light shadows
#the "fov" should be > 90.0 to eliminate map edge artifacts
Projection "perspective" "fov" [95.0]

#transform to place camera at point light "from"
#aim in the minus z direction by rotating 180 degrees about the y axis
Rotate 180.0 0.0 1.0 0.0
Translate -2.07846 -0 -1

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "pointnz.z" "pointnz.shd"

Listing 16

pointpx.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "pointpx.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 256 256 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for point light shadows
#the "fov" should be > 90.0 to eliminate map edge artifacts
Projection "perspective" "fov" [95.0]

#transform to place camera at point light "from"
#aim in the plus x direction by rotating -90 degrees about the y axis
Rotate -90.0 0.0 1.0 0.0
Translate -2.07846 -0 -1

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "pointpx.z" "pointpx.shd"

Listing 17

pointpy.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "pointpy.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 256 256 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for point light shadows
#the "fov" should be > 90.0 to eliminate map edge artifacts
Projection "perspective" "fov" [95.0]

#transform to place camera at point light "from"
#aim in the plus y direction by rotating 90 degrees about the x axis
Rotate 90.0 1.0 0.0 0.0
Translate -2.07846 -0 -1

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "pointpy.z" "pointpy.shd"

Listing 18

pointpz.rib
##RenderMan RIB
version 3.03

#shadow map files are made from z files
Display "pointpz.z" "zfile" "z"

#set the shadow map size in pixels
#values must be powers of 2, aspect ratio should be 1
Format 256 256 1

#these parameters speedup map rendering and do not diminish quality
Hider "hidden" "jitter" [0]
ShadingRate 1
PixelSamples 1 1
PixelFilter "box" 1 1

#perspective projection is used for point light shadows
#the "fov" should be > 90.0 to eliminate map edge artifacts
Projection "perspective" "fov" [95.0]

#transform to place camera at point light "from"
#aim in the plus z direction by rotating 0 degrees about the y axis
Rotate 0.0 0.0 1.0 0.0
Translate -2.07846 -0 -1

#portion of file between WorldBegin and WorldEnd is identical to image file
#except all Surface, LightSource, and Color statements have been removed
WorldBegin

    /* The contents of Listing 10: Shadowgeometry.rib go here */

WorldEnd

#convert a z file to a shadow map file so light shader can use it later
#z file can be removed now since it will not be used again
MakeShadow "pointpz.z" "pointpz.shd"

References

[1]WOO, ANDREW, POULIN, PIERRE, and FOURNIER, ALAIN, "A Survey of Shadow Algorithms," IEEE CG&E (November 1990)
[2]REEVES, WILLIAM T., SALESIN, DAVID H., and COOK, ROBERT L., "Rendering Antialiased Shadows with Depth Maps," Computer Graphics (SIGGRAPH '87 proceedings) 21(4) (July 1987).