Shader Examples

Of course, shaders can be much more complex than the simple plastic shader. The following scene displays several complicated shaders.

The images below were rendered in Lary Gritz's shareware RenderMan complient program BMRT (Blue Moon Rendering Tools). All you Linux users out there, rejoice!

A picture of three spheres

The above image uses four different shaders:

the ubiquitous teapots

The picture above shows the difference between bump mapping and true displacement mapping. Look closely at the sillutette of the teapot on the left--the surface of the teapot itself has been perturbed.

The textures in this scene include:


Next Page



Shader dented.sl

/*
 * dented.sl -- displacement shader for dents
 *
 * DESCRIPTION:
 *   Makes a surface appear worn and dented.
 * 
 * PARAMETERS:
 *   Km      the amplitude of the dents
 *   power     controls the fractal dimension of the dents (1 looks
 *             like previously crumpled paper or cloth, 3 looks
 *             like worn metal).
 *   frequency   the frequency of the dents
 *
 *
 * AUTHOR: written by Larry Gritz, based on the "dented" shader in
 *         RenderMan Companion, but with more control parameters.
 *
 * HISTORY:
 *      Dec 1992 -- written by lg for "Timbre Trees Examples" (jingle)
 *
 * last modified  12 Jan 1994 by Larry Gritz
 *
 * The RenderMan (R) Interface Procedures and RIB Protocol are:
 *     Copyright 1988, 1989, Pixar.  All rights reserved.
 * RenderMan (R) is a registered trademark of Pixar.
 */

displacement
dented ( float Km = 1, power = 3, frequency = 1, maxoctaves = 6; )
{
  float size;
  float magnitude = 0;
  float i;
  point PP;

  PP = transform ("shader", P);
  size = frequency;
  for (i = 0;  i < maxoctaves;  i += 1) {
      magnitude += abs (.5 - noise (PP*size)) / size;
      size *= 2;
    }
  P = P - (Km * pow (magnitude, power)) * normalize (N);
  N = calculatenormal (P);
}

Shader funkyglass.sl

/* funkyglass.sl - randomly colored "glass" 
 * (transparent, but no refl/refr).
 * (c) Copyright 1994, Larry Gritz
 *
 * The RenderMan (R) Interface Procedures and RIB Protocol are:
 *     Copyright 1988, 1989, Pixar.  All rights reserved.
 * RenderMan (R) is a registered trademark of Pixar.
 */



surface
funkyglass (float Ka = .2;
    float Kd = .2;
    float Ks = 1;
    float roughness = .08;
    color specularcolor = 1;)
{
  point PP, Nf, V;
  color Ct, Ot;

  V = normalize(I);
  Nf = faceforward (normalize(N),V);
  PP = transform ("shader", P);
  Ct = 2 * (color noise (PP) - .5) + .5;
  Ot = (comp(Ct,0) + comp(Ct,1) + comp(Ct,2))/3 + (1-Ct);

  Oi = Ot * (0.75 - 0.5*abs(V.Nf));
  Ci = ( Ct * (Ka*ambient() + Kd*diffuse(Nf)) +
      specularcolor * Ks*specular(Nf,-V,roughness));
}

Shader matte.sl

/* matte.sl - Standard matte surface for RenderMan Interface.
 * (c) Copyright 1988, Pixar.
 *
 * The RenderMan (R) Interface Procedures and RIB Protocol are:
 *     Copyright 1988, 1989, Pixar.  All rights reserved.
 * RenderMan (R) is a registered trademark of Pixar.
 */

surface mymatte (float Ka = 1;
       float Kd = 1;
)
{
  point Nf;
  float d, sigma, tau;

  Nf = faceforward (normalize(N),I);
  Oi = Os;
  Ci = Os * Cs * (Ka * ambient() + Kd * diffuse(Nf));
}

Shader spatter.sl

/*------------------------------------------------------------------
 * spatter - make surface look dark blue with white paint spatters,
 * like on that camping cookware. (Or any base color with any color
 * paint spatters).
 *
 * Ka, Kd, Ks, roughness, specularcolor - the usual meaning
 * specksize - size of the smallest paint specks
 * sizes - number of different sizes of paint specks (each double
 *  the previous size)
 * basecolor - the background color on which to spatter paint
 * spattercolor - the color of the paint spatters
 *-----------------------------------------------------------------*/
surface
spatter(float Ka=1, Kd=0.5, Ks=0.7, roughness=0.2, specksize=.01,
sizes = 5; color specularcolor = 1, basecolor = color (.1,.1,0.5),
spattercolor = color (1,1,1))
{
varying float speckle,size,scalefac,
      threshold = 0.7;
varying color paint;
varying point Nf, V;

Nf = faceforward(normalize(N),I);
V = -normalize(I);

/* "OR" together various-sized noise spots.
    If any white, make paint white*/
scalefac = 1/specksize;
paint = basecolor;
for (size=1; size<=sizes; size +=1) {
speckle = noise(transform("shader",P)*scalefac);
if (speckle > threshold) {
paint = spattercolor;
break;
}
scalefac /= 2;
}

/* get final color */
Oi = Os;
Ci = Os * (paint * (Ka * ambient() + Kd * diffuse(Nf)) +
specularcolor * Ks * specular(Nf,V,roughness));
}

Shader screen_aa.sl

/*
 * screen_aa.sl -- RenderMan compatible shader for a metalic screen.
 *
 * DESCRIPTION:
 * Makes a surface that looks like a metal screen. Strips of metal run
 * parallel to lines of s and t.  You can adjust the Ka, Kd, Ks, etc.
 * to change the material appearance.  This texture antialiases pretty
 * well, even with only one sample per pixel.
 *
 * PARAMETERS:
 * Ka, Kd, Ks, roughness, specularcolor - work like the plastic shader
 *   frequency - how many cycles of screen in st space
 *   density - how much of each cycle is opaque?
 *
 * AUTHOR: written by Larry Gritz
 */ 

#define boxstep(a,b,x) (clamp(((x)-(a))/((b)-(a)),0,1))
#define MINFILTERWIDTH 1.0e-7

surface
screen_aa (float Ka = 1, Kd = 0.75, Ks = 0.4, roughness = 0.1;
   color specularcolor = 1;
   float density = 0.25, frequency = 20;)
{
  point Nf;     /* Forward facing Normal vector */
  point IN;     /* normalized incident vector */
  float d;      /* Density at the sample point */
  float ss, tt; /* s,t, parameters in phase */
  float swidth, twidth, GWF, w, h;

  /* Compute a forward facing normal */
  IN = normalize (I);
  Nf = faceforward (normalize(N), I);

  /* Determine how wide in s-t space one pixel projects to */
  swidth = max (abs(Du(s)*du) + abs(Dv(s)*dv), MINFILTERWIDTH) *
frequency;
  twidth = max (abs(Du(t)*du) + abs(Dv(t)*dv), MINFILTERWIDTH) *
frequency;

  /* Figure out where in the pattern we are */
  ss = mod (frequency * s, 1);
  tt = mod (frequency * t, 1);

  /* Figure out where the strips are. Do some simple antialiasing. */
  GWF = density*0.5;
  if (swidth >= 1)
      w = 1 - 2*GWF;
  else w = clamp (boxstep(GWF-swidth,GWF,ss), max(1-GWF/swidth,0), 1)
 - clamp (boxstep(1-GWF-swidth,1-GWF,ss), 0, 2*GWF/swidth);
  if (twidth >= 1)
      h = 1 - 2*GWF;
  else h = clamp (boxstep(GWF-twidth,GWF,tt), max(1-GWF/twidth,0),1)
 - clamp (boxstep(1-GWF-twidth,1-GWF,tt), 0, 2*GWF/twidth);
  /* This would be the non-antialiased version:
   *    w = step (GWF,ss) - step(1-GWF,ss);
   *    h = step (GWF,tt) - step(1-GWF,tt);
   */
  d = 1 - w*h;

  Oi = d;
  if (d > 0) {
      Ci = Oi * ( Cs * (Ka*ambient() + Kd*diffuse(Nf)) +
 specularcolor * Ks*specular(Nf,-IN,roughness));
    }
  else
      Ci = 0;
}

Shader parquet_plank.sl

/*
 * parquet_plank.sl -- another surface shader for wood.
 *
 *DESCRIPTION:
 *Makes texture of wooden planks in s-t space.  This wood looks rather
 *like oak plank parquet floor tiles.  The actual wood & plank pattern
 *is based on my planks shader.  This shader works best if "s" and "t"
 *units are both the same size in world space.
 *
 * PARAMETERS:
 *   Ka, Kd, Ks, specular, roughness - work like the plastic shader
 *   txtscale - overall scaling factor for the texture
 *   plankwidth - width of each plank (in terms of s/t)
 *   plankspertile - number of planks in each parquet tile
 *   ringscale - scaling for the ring spacing
 *   grainscale - scaling for the fine grain
 *   groovewidth - width of grooves between planks (in terms of s/t)
 *   lightwood, darkwood - surface colors for the wood itself
 *   groovecolor - the color of the "grooves" between the planks
 *   plankvary - controls how much color varies from plank to plank
 *   grainy - relative graininess (0 = no fine grain)
 *   wavy - relative wavyness of the ring pattern
 *
 * ANTIALIASING: this shader does a pretty good job of antialiasing
 *   even with low sampling densities.
 *
 * AUTHOR: written by Larry Gritz, the George Washington University
 *    10 Feb 1995 - written by Larry Gritz, based on "plank" shader.
 *
 * last modified 10 Feb 1995 by Larry Gritz
 */

surface
parquet_plank (float Ka = 1, Kd = 0.75, Ks = .15, roughness = .025;
       color specularcolor = 1;
       float ringscale = 15, grainscale = 60;
       float txtscale = 1;
       float plankspertile = 4;
       color lightwood = color (0.57, 0.292, 0.125);
       color darkwood  = color (0.275, 0.15, 0.06);
       color groovecolor  = color (.05, .04, .015);
       float plankwidth = .05, groovewidth = 0.001;
       float plankvary = 0.8;
       float grainy = 1, wavy = 0.08; )
{
#define snoise(x) (2 * noise((x)) - 1)
#define boxstep(a,b,x) (clamp(((x)-(a))/((b)-(a)),0,1))
#define MINFILTERWIDTH 1.0e-7

  float r, r2;
  point Nf;
  float whichrow, whichplank;
  float swidth, twidth, fwidth, ss, tt, w, h, fade, ttt;
  color Ct, woodcolor;
  float groovy;
  float PGWIDTH, PGHEIGHT, GWF, GHF;
  float tilewidth, whichtile, tmp, planklength;

  PGWIDTH = plankwidth+groovewidth;
  planklength = PGWIDTH * plankspertile - groovewidth;
  PGHEIGHT = planklength+groovewidth;
  GWF = groovewidth*0.5/PGWIDTH;
  GHF = groovewidth*0.5/PGHEIGHT;

  /* Determine how wide in s-t space one pixel projects to */
  swidth = (max (abs(Du(s)*du) + abs(Dv(s)*dv), MINFILTERWIDTH) /
PGWIDTH) * txtscale;
  twidth = (max (abs(Du(t)*du) + abs(Dv(t)*dv), MINFILTERWIDTH) /
PGHEIGHT) * txtscale;
  fwidth = max(swidth,twidth);

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

  ss = (txtscale * s) / PGWIDTH;
  whichrow = floor (ss);
  tt = (txtscale * t) / PGHEIGHT;
  whichplank = floor(tt);
  if (mod (whichrow/plankspertile + whichplank, 2) >= 1) {
      ss = txtscale * t / PGWIDTH;
      whichrow = floor (ss);
      tt = txtscale * s / PGHEIGHT;
      whichplank = floor(tt);
      tmp = swidth;  swidth = twidth;  twidth = tmp;
    } 
  ss -= whichrow;
  tt -= whichplank;
  whichplank += 20*(whichrow+10);

  /*
   * Figure out where the grooves are.  The value groovy is 0 during
   * are grooves, 1 where the wood grain is visible.  Do some simple
   * antialiasing.
   */
  if (swidth >= 1)
      w = 1 - 2*GWF;
  else w = clamp (boxstep(GWF-swidth,GWF,ss), max(1-GWF/swidth,0), 1)
 - clamp (boxstep(1-GWF-swidth,1-GWF,ss), 0, 2*GWF/swidth);
  if (twidth >= 1)
      h = 1 - 2*GHF;
  else h = clamp (boxstep(GHF-twidth,GHF,tt), max(1-GHF/twidth,0),1)
 - clamp (boxstep(1-GHF-twidth,1-GHF,tt), 0, 2*GHF/twidth);
  /* This would be the non-antialiased version:
   * w = step (GWF,ss) - step(1-GWF,ss);
   * h = step (GHF,tt) - step(1-GHF,tt);
   */
  groovy = w*h;


  /*
   * Add the ring patterns
   */
  fade = smoothstep (1/ringscale, 8/ringscale, fwidth);
  if (fade < 0.999) {
      ttt = tt/4+whichplank/28.38 + wavy * noise (8*ss, tt/4);
      r = ringscale * noise (ss-whichplank, ttt);
      r -= floor (r);
      r = 0.3+0.7*smoothstep(0.2,0.55,r)*(1-smoothstep(0.75,0.8, r));
      r = (1-fade)*r + 0.65*fade;

      /*
       * Multiply the ring pattern by the fine grain
       */
      fade = smoothstep (2/grainscale, 8/grainscale, fwidth);
      if (fade < 0.999) {
	 r2 = 1.3 - noise (ss*grainscale, (tt*grainscale/4));
	 r2 = grainy * r2*r2 + (1-grainy);
	 r *= (1-fade)*r2 + (0.75*fade);
	}
      else r *= 0.75;
    }
  else r = 0.4875;
  

  /* Mix the light and dark wood according to the grain pattern */
  woodcolor = mix (lightwood, darkwood, r);

  /* Add plank-to-plank variation in overall color */
  woodcolor *= (1-plankvary/2 + plankvary * noise (whichplank+0.5));

  Ct = mix (groovecolor, woodcolor, groovy);

  /* Use the plastic illumination model */
  Oi = Os;
  Ci = Os * ( Ct * (Ka*ambient() + Kd*diffuse(Nf)) +
      specularcolor * Ks*specular(Nf,-normalize(I),roughness));
}