shader() example

This light shader projects a texture from a stencil image onto the scene. This shader should be called from another shader (like the diffuse shader to determine the light's color. This shader sets the color argument to the color of the light. In this case, color is set to black if the light cannot be seen at the surface point being shaded.

A view of a tilted plane with a projected texture from the light source A view from beside the light source

This only works for a light source located on the Z axis. In your assignment, you need to be able to move the light source anywhere.


void
lightShader(int WhichLight, float *color)
{
   float localU, localV;

   vec_set(color,0,0,0);

   /* Do a simple projection */

   /* First, project onto UV plane, parallel to XY plane, by scaling x and y */
   localU = surfacePosition[0] / lights[WhichLight].uscale;
   localV = surfacePosition[1] / lights[WhichLight].vscale;

   /* Add perspective: divide u and v by z distance from light to surface */
   localU /= (-surfacePosition[2] + lights[WhichLight].position[2]);
   localV /= (-surfacePosition[2] + lights[WhichLight].position[2]);

   /* Rescale to between 0 and 1 */
   localU = ((localU + 1) / 2.0);
   localV = ((localV + 1) / 2.0);
   
   if((localU >= 0) && (localU <= 1) && (localV >= 0) && (localV <= 1))
   {
      int iu = localU * theTexture->width;
      int iv = theTexture->height - localV * theTexture->height;
      float tcolor[3];
      
      /* Evaluate the texture here */
      if((iu >= 0) && (iu < theTexture->width) &&
         (iv >= 0) && (iv < theTexture->height))
      {
	  Pixel pixel = ImagePixel(theTexture, iu, iv);
	  vec_set(tcolor, pixel.r / 255.0, pixel.g / 255.0, pixel.b / 255.0);
      }
      else
         vec_set(tcolor,0,0,0);

      vec_comp_mult(lights[WhichLight].color,tcolor,color);
   }
}

This is the diffuse shader again, augmented to use the above light shader.
void
shader(float *color)
{
   float ambientColor[3] = { 0.1, 0.1, 0.1 };
   float eye2Surf[3];
   int i;

   /* Compute vector from surface to eye. */
   vec_sub(eyePosition,surfacePosition,eye2Surf);
   vec_normalize(eye2Surf);

   /* For each light, compute its contribution */
   vec_set(color,0,0,0);

   for(i=0 ; i<numLights ; i++)
   {
      float light2Surf[3];
      float edotn;
      float tmp[3];
      float lcolor[3];

      /* Can we see the light? */
      lightShader(i, lcolor);

      /* Compute vector from light to surface. */
      vec_sub(lights[i].position,surfacePosition,light2Surf);
      vec_normalize(light2Surf);

      /* Add diffuse component. */
      edotn = vec_dot(light2Surf,surfaceNormal);
      if(edotn > 0)
      {
         vec_scale2(edotn,diffuseColor,tmp);
         vec_comp_mult(tmp,lcolor,tmp);
         vec_add(color,tmp,color);
      }
   }
   vec_add(color,ambientColor,color);

   vec_clamp(color, 0, 1);
}

This is a configuration file that could be used with the above.
#
# This stuff has nothing to do with the shader, only scene layout
#
string patchObject = plane.obj
int loDice = 10
int hiDice = 200
int   numLights = 1
vec   eyePosition = 0 0 20
vec   light0Pos = 0 0 20
vec   light0Dir = 0 0 -1
vec   light0Up  = 0 1 0
color light0Color = 1 1 1
float light0UScale = 1
float light0VScale = 1
#
# Shader variables go here
#
string whichShader = diffuse
color diffuseColor = 0.4 0.4 0.4
string textureName = stencil2.ppm

hanrahan@cs.stanford.edu
beers@graphics.stanford.edu

Copyright © 1997 Pat Hanrahan and Andrew C. Beers