Home Tour Gallery Demo Order Plug-ins Testimonials Sitemap Help Dev Dev Dev

Last updated: May 15, 2003

 

Some of the following shaders are designed to be used with the PatchMesh object that Leveller creates when exporting a RIB file. Although they can be used on any object, doing so may create suboptimal results.

Elevation-based coloring
Elevation-based gradient colormapping
Slope-based coloring
Snowy peaks
Summertime snowy peaks
Quick shading
Masked texturing

The shaders are provided in commented source format to help you develop your own preferred heightfield shaders. As a filing aid, all our heightfield shaders start with the prefix 'levhf_'. The code is not warranted, but all the shaders were tested. Enjoy, and use at your own risk.

The Renderman API is Copyright Pixar, Inc.

 


Elevation-based coloring

Coloring a heightfield based on the altitude of its points is a standard way of communicating differences in elevation. In this example, we blend between two colors, the same way that Leveller does when using the 'App Default' colormap. The technique can also be used on bump maps to give richer effect to a texture.


  /*
    levhf_elev.sl
    Version 1.0 by Daylon Graphics Ltd.

    This is a simple matte shader that colors a point depending on 
    its elevation. The heightfield is assumed to be based on an object 
    (such as a "Pz" PatchMesh) where the elevations are oriented along 
    the Z axis in object space.
  */
  surface levhf_elev(color ColorLo = color(0,0,1), ColorHi = color(1,1,1))
  {
    point where = transform("object", P);
    color c = mix(ColorLo, ColorHi, zcomp(where));

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

    Oi = Os;
    Ci = c * Os * Cs * (1 * ambient() + 1 * diffuse(Nf));
  }

 


Elevation-based gradient colormapping

This type of coloring emulates Leveller's multistep colormaps. Note that in the case of the Spectrum colormap, a simple linear interpolation using the spline() function is adequate. For nonlinear gradients, a different approach (e.g., if-else blocks) may be necessary.


  /*
    levhf_elevgradient.sl
    Version 1.0 by Daylon Graphics Ltd.

    This is a simple matte shader that colors a point depending on 
    its elevation, using Leveller's "Spectrum" colormap. The heightfield 
    is assumed to be based on an object (such as a "Pz" PatchMesh) where 
    the elevations are oriented along the Z axis in object space.
  */
  surface levhf_elevgradient()
  {
    point where = transform("object", P);
    /*
       According to the Renderman documentation, spline() returns
       the second datum if f=0, and the second-to-last datum if 
       f=1. So we duplicate these items to get the desired interpolation.
    */
    color c = spline(zcomp(where),
                     color(0,0,0), 
                     color(0,0,0),
                     color(0,0,1),
                     color(0,.5,1),
                     color(0,.5,0),
                     color(1,.5,0),
                     color(1,0,0),
                     color(1,1,1),
                     color(1,1,1) 
		);


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

    Oi = Os;
    Ci = c * Os * Cs * (1 * ambient() + 1 * diffuse(Nf));
  }

 


Slope-based coloring


  /*
    levhf_slope.sl
    Version 1.0 by Daylon Graphics Ltd.

    This is a simple matte shader that colors a point depending on 
    its slope. The heightfield is assumed to have its elevations 
    oriented along the Y axis in default (world) space.
  */
  surface levhf_slope(
    color ColorFlat = color(1, 1, 1); 
    color ColorSteep = color(0, 0, 1); 
  )
  {
    /*
      Get the angle of the surface point's slope, which we assume 
      we can derive from the normal's Y element. The two statements below 
      are actually poor form; in a production shader, you would optimize 
      them to use ycomp(normalize(Ng)) directly -- there's no reason to 
      obtain degrees unless you absolutely need them.
    */
    float angle = 90 - (asin(ycomp(normalize(Ng)))) * 180 / PI;
    color c = mix(ColorFlat, ColorSteep, angle / 90);

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

    Oi = Os;
    Ci = c * Os * Cs * (1 * ambient() + 1 * diffuse(Nf));
  }

 


Snowy peaks

The Slope example blends between the two specified colors, which doesn't really give a good idea of how slope is used. This shader instead applies one color for one set of angles, and another color for the rest. The sharp break between the two colors shows exactly which slopes are being given which color.


  /*
    levhf_snowypeaks.sl
    Version 1.0 by Daylon Graphics Ltd.

    This is a simple matte shader that colors a point depending on 
    its slope, to simulate snow or other material deposited onto 
    a heightfield. The heightfield is assumed to have its elevations 
    oriented along the Y axis in default (world) space.
  */
  surface levhf_snowypeaks(
    color ColorSnow = color(1, 1, 1); 
    color ColorRock = color(.4, .4, .4);
    float Angle = 45;
  )
  {
    float angle = 90 - (asin(ycomp(normalize(Ng)))) * 180 / PI;
    color c = angle < Angle ? ColorSnow : ColorRock;

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

    Oi = Os;
    Ci = c * Os * Cs * (1 * ambient() + 1 * diffuse(Nf));
  }

 


Summertime snowy peaks

The Snowy Peaks example puts snow on every surface of low slope. In the summertime, mountains only have snow above a certain elevation, where the air is sufficiently cold. Acheiving the effect, of course, is simple -- use elevation and slope together.


  /*
    levhf_summersnow.sl
    Version 1.0 by Daylon Graphics Ltd.

    This is a simple matte shader that colors a point depending on its
    slope, to simulate snow or other material deposited onto a heightfield.
    Slope is not considered if the elevation of the point is below a certain 
    threshold. The heightfield is assumed to have its elevations oriented 
    along the Y axis in default (world) space.
  */
  surface levhf_summersnow(
    color ColorSnow = color(1, 1, 1); 
    color ColorRock = color(.4, .4, .4);
    float Angle = 45;
    float Elev = .66;
  )
  {
    float angle = 90 - (asin(ycomp(normalize(Ng)))) * 180 / PI;
    float elev = zcomp(transform("object", P));
    color c = elev > Elev && angle < Angle ? ColorSnow : ColorRock;

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

    Oi = Os;
    Ci = c * Os * Cs * (1 * ambient() + 1 * diffuse(Nf));
  }

 


Quick Shading

Sometimes you want illumination without shadows. This shader brightens or darkens the surface color depending on how each point is facing a specified vector. It emulates Leveller's Quick Shading mode which fakes shadows by simply darkening areas facing away from the Sun.


  /*
    levhf_qshade.sl
    Version 1.0 by Daylon Graphics Ltd.

    This is a simple color shader that brightens/darkens 
    a point depending on its relation to a given vector.
  */
  surface levhf_qshade(
    point SunDir = (.707, -.707,-.707); /* 45 degrees right, down, and south */
  )
  {
    float f = faceforward(normalize(Ng), I).SunDir;

    Oi = Os;
    Ci = Os * Cs * (1-f);
  }

 


Masked Texturing

The default "paintedplastic" texturing shader ignores the texture's alpha channel, if one is present. Since Leveller supports masked textures, this shader is provided in the samples/ribshaders folder.


/* txalpha.sl - Alpha-channel texturing shader
 * Copyright (C) 2003 Daylon Graphics Ltd.
 * Written by Ray Gardener (support@daylongraphics.com)
 *
 * The RenderMan (R) Interface Procedures and RIB Protocol are:
 *   Copyright 1988, 1989, Pixar.  All rights reserved.
 *   RenderMan (R) is a registered trademark of Pixar.
 *
 * DESCRIPTION:
 *    Apply a texture map to a plastic surface, indexing the texture
 *    by the s,t parameters of the surface. Alpha channel in the texture
 *    will blend the texture color with the primitive's color.
 *    Additionally, you can specify the strength of an overall 
 *    blend between the texture and the surface color.
 *    If the alpha channel is all 1.0 and Ob is 0.5, results 
 *    will match paintedplastic.
 *
 * PARAMETERS:
 *    Ka, Kd, Ks, roughness, specularcolor - the usual meaning.
 *    Ob - Overall texture/surface blending factor
 *      (0.0 prefers surface, 1.0 prefers texture).
 *    texturename - the name of the texture file.
 *
 */


surface
txalpha ( float Ka = 1, Kd = .5, Ks = .5, roughness = .1;
  color specularcolor = 1;
  float Ob = 1;
  string texturename = ""; )
{
  normal Nf;
  vector V;
  color Ct;
  float Ot;
  float numChannels;

  Ot = 1;

  if (texturename != "")
  {
    Ct = color texture(texturename);
    Ot = float texture(texturename[3]);



    /*  This part checks that texture has alpha, but it slows 
        down rendering (especially if the texture has its TIFF 
        directory holding unsorted tags, as warning messages 
        may display for every pixel access). This code could be
        redundant since the renderer converts textures to 
        internal RGBA textures anyway.

        if(1.0 == textureinfo(texturename, "channels", numChannels))
        {
          if(numChannels == 4)
            Ot = float texture(texturename[3]);
        }
    */


  }
  else
  {
    Ct = 1;
  }

  Nf = faceforward (normalize(N),I);
  V = -normalize(I);
  Oi = Os;
  Ci = Os * 
    (mix(Cs, Ct, Ot * Ob) * 
    (Ka * ambient() + Kd * diffuse(Nf)) +
    specularcolor * Ks * specular(Nf, V, roughness));
}