Soft Shadows with RenderDotC

Since its introduction, RenderDotC has supported standard depth map shadows through the Shading Language shadow() function. Sometimes the user may want to get Soft Shadows with true penumbral effects like many raytracing renderers offer. RenderDotC now supports soft shadows through the use of several shadow maps and an extended shadow() call. 

The approach is actually very similar to raytracing, since it actually traces rays from the surface to points on an area lightsource. The difference is that instead of tracing rays through the actual scene geometry, it uses the shadow maps as a scene representation and traces rays through them. This provides high quality soft shadows without the cost of conventional raytracing and also inherits the typical advantages of shadow mapping: 

  • The cost of computing soft shadows is independant from geometric complexity of the scene and only depends on the number and resolution of depth maps provided. This allows the user a better tradeoff between speed and quality.
  • Since it doesn't use raytracing, scene geometry is accesed in a coherent manner and can be discarded after being drawn. This reduces memory use and enables the renderer to handle larger amounts of geometry.
This soft shadow algorithm does not use true arealights. The area light is only used for soft shadow computation, they are independant from shading, so it does not automatically account for other area light effects like non-point hightlights. 

The Area Light Source

The Shading Language shadow() call now accepts the new parameter "source", followed by one, two, three or four Points in current space defining a point, line, triangle or bilinear patch respectively. This one is used as the origin of light for shadow computation. 
The "samples" switch in this case is used to set the number of rays traced from the surface element to different points on the light source. Higher numbers will reduce noise, but will lead to higer rendering times. 

Multiple Shadow Maps

It is possible, to get soft shadows out of one shadow map, but due to the lack of information you might get some artifacts, especially when the light source is near and big in respect to the object. In some cases you might get away with that, though. The important thing for shadow map generation is that all shadow maps cover all the objects which are supposed to cast shadows. It's not so important from where you generate your shadow maps, they don't even have to be anywehere near the actual light source. It's more important to cover all of the surfaces which will cast shadows. 
The illustration shows the concept of soft shadow generation via shadow maps. The two shadow maps are generated from two different positions on the light source and due to their different position they cover slightly different parts of the surface. Rays are traced from the surface point P to points on the lightsource you defined via "source". Three sample rays are shown in the picture and the ray to point x1 would be considered unoccluded if only the shadow map from location 1 would be given since the part that ray intersects is not covered by that shadow map. For this reason the modified shadow() call now accepts more than one texturemap. Several texturemaps are given as comma-sperated list: "shadow1.map,shadow2.map,shadow3.map..." Normal shadow maps are accepted, but you can speed up soft shadow rendering with the "minmax" switch for MakeShadow or the -Z (capital) switch when using texdc. An example .rib statement would be: 

MakeShadow "shadow.z" "shadow.shd" "minmax" [1] 

Gap Bias

The Gap Bias defines how different the depth values of adjacent pixels in the shadow map have to be, to be considered disconnected. 

Here is an example shader: 



light arealight(color lightcolor = color(1,1,1); 
                float intensity = 1; 
                string maplist = ""; 
                float numsamples = 1; 
                point Pl1 = point "shader" (0, 0, 0); 
                point Pl2 = point "shader" (1, 0, 0); 
                point Pl3 = point "shader" (0, 1, 0); 
                point Pl4 = point "shader" (1, 1, 0); 
                float shadowbias = 0.001; 
                float gapbias = 0.01) 
{ 
    varying float attenuation; 

    /* Base illumination at average of light positions */ 
    illuminate ((Pl1 + Pl2 + Pl3 + Pl4) * 0.25) { 
        attenuation = shadow(maplist, Ps, "source", Pl1, Pl2, Pl3, Pl4, 
            "samples", numsamples, "bias", shadowbias, "gapbias", gapbias); 
        Cl = lightcolor * intensity * (1-attenuation); 
    } 
} 



arealight.sl 

And here is an example RIB file to test the functionality: 



Declare "minmax" "integer" 
Declare "Pl1" "uniform point" 
Declare "Pl2" "uniform point" 
Declare "Pl3" "uniform point" 
Declare "Pl4" "uniform point" 
Declare "maplist" "uniform string" 
Declare "shadowbias" "uniform float" 
Declare "gapbias" "uniform float" 
Declare "numsamples" "uniform float" 
Option "shadow" "bias" [0.6] 

FrameBegin 1 
  # First Soft Shadow Map image (upper left) 
  Display "sphere1.z" "file" "z" 
  Format 256 256 1.0 
  PixelSamples 1 1 
  Hider "hidden" "jitter" [0] 
  Projection "perspective" "fov" 20 
  Rotate -37.74 1 0 0 
  Rotate 39.29 0 1 0 
  Translate -9 -11 11 
  WorldBegin 
    TransformBegin 
      Rotate -90 1 0 0 
      Cylinder 2 -2 2 360 
      Disk 2 2 360 
    TransformEnd 
  WorldEnd 

  Identity 

  # Second Soft Shadow Map image (upper right) 
  Display "sphere2.z" "file" "z" 
  Format 256 256 1.0 
  PixelSamples 1 1 
  Hider "hidden" "jitter" [0] 
  Projection "perspective" "fov" 20 
  Rotate -37.74 1 0 0 
  Rotate 50.71 0 1 0 
  Translate -11 -11 9 
  WorldBegin 
    TransformBegin 
      Rotate -90 1 0 0 
      Cylinder 2 -2 2 360 
      Disk 2 2 360 
    TransformEnd 
  WorldEnd 

  Identity 

  # Third Soft Shadow Map image (lower left) 
  Display "sphere3.z" "file" "z" 
  Format 256 256 1.0 
  PixelSamples 1 1 
  Hider "hidden" "jitter" [0] 
  Projection "perspective" "fov" 20 
  Rotate -32.34 1 0 0 
  Rotate 39.29 0 1 0 
  Translate -9 -9 11 
  WorldBegin 
    TransformBegin 
      Rotate -90 1 0 0 
      Cylinder 2 -2 2 360 
      Disk 2 2 360 
    TransformEnd 
  WorldEnd 
   
  Identity 
   
  # Fourth Soft Shadow Map image (lower right) 
  Display "sphere4.z" "file" "z" 
  Format 256 256 1.0 
  PixelSamples 1 1 
  Hider "hidden" "jitter" [0] 
  Projection "perspective" "fov" 20 
  Rotate -32.34 1 0 0 
  Rotate 50.71 0 1 0 
  Translate -11 -9 9 
  WorldBegin 
    TransformBegin 
      Rotate -90 1 0 0 
      Cylinder 2 -2 2 360 
      Disk 2 2 360 
    TransformEnd 
  WorldEnd 

  Identity 

  MakeShadow "sphere1.z" "sphere1.shd" "minmax" [1] 
  MakeShadow "sphere2.z" "sphere2.shd" "minmax" [1] 
  MakeShadow "sphere3.z" "sphere3.shd" "minmax" [1] 
  MakeShadow "sphere4.z" "sphere4.shd" "minmax" [1] 

  Display "softshadows.tif" "file" "rgb" 
  Format 640 480 1.0 
  PixelSamples 2 2 
  Hider "hidden" "jitter" [1] 
  Projection "perspective" "fov" 16 
  Translate 2 0 40 
  Rotate -30 1 0 0 
  WorldBegin 
    LightSource "ambientlight" 1 "intensity" 0.02 "lightcolor" [1 1 1] 
    LightSource "arealight" 2 "lightcolor" [1 1 1] "intensity" 1.6 "Pl1" [8 12 -12] "Pl2" [12 12 -8] "Pl3" [8 8 -12] "Pl4" [12 8 -8] "maplist" ["sphere1.shd,sphere2.shd,sphere3.shd,sphere4.shd"] "shadowbias" [0.6] "gapbias" [0.1] "numsamples" [32] 
    Color [0.9 0.7 0.1] 
    Surface "plastic" 
    TransformBegin 
      Rotate -90 1 0 0 
      Cylinder 2 -2 2 360 
      Disk 2 2 360 
    TransformEnd 
    Color [0.7 0.6 0.4] 
    Patch "bilinear" "P" [-20 -2  20  20 -2  20  -20 -2 -20  20 -2 -20] 
  WorldEnd 



softshadows.rib

This guide was written by Timm Dapper <td@mirage-3d.org>

Copyright © 2001-2006 Dot C Software, Inc. All rights reserved.
Dot C Software, Inc., 182 Kuuhale St., Kailua, HI 96734
(808) 262-6715 (voice) (808) 261-2039 (fax)
The RenderMan® Interface Procedure and RIB Protocol are:
Copyright © 1988, 1989, Pixar. All rights reserved.
RenderMan® is a registered trademark of Pixar.