next up previous contents
Next: Simple Room Up: Get Your Hands Dirty Previous: Default Surface Shader   Contents


Stairs

Consider the following problem: You have a scene with a lot of staircases or for example a huge pyramid. Most of the time the camera shows the whole scene from distance which means that you can't see the individual steps very well. Instead of modelling each individual step you consider to create a simplified model without steps and faking the effect of having stairs within the shader:

Figure 12: Rendering the stairs with real geometry
\includegraphics[scale=0.6]{stairsfilm.01.ps}

Figure 13: Faking the stairs within the shader
\includegraphics[scale=0.6]{stairsfilm.02.ps}

/* stairs */

surface 
stairs(float Ka = 1, Kd = 0.5, Ks = 0.5, roughness = 0.1;
       color specularcolor = 1;
       float steps = 5;)
{
  normal Nf;
  float sv = mod(v * steps, 1);

  if (sv < 0.5)
    Nf = ntransform("object", "current", normal(0, -1, 0)); /* front */
  else
    Nf = ntransform("object", "current", normal(0, 0, 1));  /* up */

  Oi = Os;
  Ci = Os * (Cs * (Ka * ambient() + Kd * diffuse(Nf)) +
             specularcolor * Ks * specular(Nf, normalize(-I), roughness));
}

As you can see in figure 12 I rendered a simple staircase with 10, 50, and 100 steps. I used a Python program to generate the RIB file automatically based on a parameter for the number of steps. On the web page where you downloaded this document or where you read it right now you will find a copy of the Python script I used to generate the staircases. It's called stairs.py. You should generate the real geometry and render it with your favourite RenderMan compatible renderer to compare the results with the shader based version using the following RIB file. Change the parameter steps for the shader before you render the RIB file again:

Figure 14: Real geometry from different perspectives
\includegraphics[scale=0.6]{stairsfilm.03.ps}

Figure 15: Faked stairs from different perspectives
\includegraphics[scale=0.6]{stairsfilm.04.ps}

# stairs.shader.rib
Exposure 1.0 2.2
Display "stairs.shader.tiff" "file" "rgba"
Format 640 480 1.0
Projection "perspective" "fov" [ 30 ]
Translate 0 0.25 7
Rotate -30 1 0 0
Rotate 30 0 1 0
Rotate 90 1 0 0
Rotate 180 0 1 0
WorldBegin
  Surface "plastic"
  LightSource "spotlight" 1 
  "color lightcolor" [ 1.0 1.0 1.0 ] 
  "point from" [ 0.0 -1.5 5.0 ] 
  "point to" [ 0.0 0.0 0.0 ] 
  "float intensity" [ 10 ] 
  "float coneangle" [ 0.35 ]
# ribPatchMesh
  AttributeBegin
    Surface "stairs" "float steps" [ 100 ]
    PatchMesh "bilinear" 2 "nonperiodic" 2 "nonperiodic" 
    "P" [ -1.0 -1.0 -1.0 
           1.0 -1.0 -1.0 
          -1.0  1.0  1.0 
           1.0  1.0  1.0 ] 
  AttributeEnd
WorldEnd

You can improve the quality by introducing a fuzz area to get better anti-aliasing:

/* stairs */

surface 
stairs(float Ka = 1, Kd = 0.5, Ks = 0.5, roughness = 0.1;
       color specularcolor = 1;
       float steps = 4, fuzz = 0.05;)
{
  float p;
  normal Nf;
  normal front = ntransform("object", "current", normal(0, -1, 0));
  normal up    = ntransform("object", "current", normal(0, 0, 1));
  float sv = mod(v * steps, 1);

  if (sv < 0.5 - fuzz)
    {
      if (sv > fuzz || (v * steps) <= fuzz)
        {       
          Nf = front;
        }
      else
        {
          p = 0.5 + sv / (2 * fuzz);
          Nf = ((1.0 - p) * up + p * front);
        }
    }
  else if (sv > 0.5 + fuzz)
    {
      if (sv < (1.0 - fuzz) || v >= (1.0 - fuzz / steps))
        {
          Nf = up;
        }
      else
        {
          p = (sv - 1.0 + fuzz) / (2 * fuzz);
          Nf = ((1.0 - p) * up + p * front);
        }
    }
  else
    {
      p = (sv - 0.5 + fuzz) / (2 * fuzz);
      Nf = ((1.0 - p) * front + p * up);
    }

  Oi = Os;
  Ci = Os * (Cs * (Ka * ambient() + Kd * diffuse(Nf)) +
             specularcolor * Ks * specular(Nf, normalize(-I), roughness));
}

Exercise:

Try to think about other improvements you could introduce to make this solution available to a wider range of staircases. At the moment I assume that the staircase was modelled a certain way. How can you generalise it? For the case with 100 steps the difference between the real geometry and the shader version is hard to see but this is only true for this perspective from the camera. If you would look more or less straight from the front you should basically see only the front of the steps and nearly nothing from the top. This effect can be seen as well if you look at the top step of the staircase with only 10 steps in figure 12. How can you compensate for that in the shader?


next up previous contents
Next: Simple Room Up: Get Your Hands Dirty Previous: Default Surface Shader   Contents
Jan Walter 2004-02-09