/* 
 * Copyright (c) 1998 Thomas E. Burge.  All rights reserved.  
 * 
 *
 * FILE:  tebLaserLight.sl
 *
 *
 * DESCRIPTION:  
 *
 *    Quick Reference to Parameters:
 *    
 *        float   intensity = 1.0;
 *        color   lightcolor = color (1.0,0.0,0.0);
 *        point   from = point "shader" (0.0,0.0,0.0);
 *        point   to = point "shader" (0.0,0.0,1.0);
 *        float   coneangle = radians(10.0);
 *                 -- See below for why a cone angle is being used with laser.
 *        float   coneangledegrees = 0.0;
 *        string  shadowmap = "";
 *        float   shadowmapopacity = 1.0;
 *        float   shadowblur = 1.0;
 *        float   shadowsamples = 16;
 *        float   shadowbias = 0.0;
 *        float   lightlaserradius = 0.5; -- Radius in shader space. 
 *        float   lightlaserblur = 0.0;
 *        float   lightrelativelylarge = 0.0; -- Solar used, no coneangle.
 *
 *    Notes:
 *        When creating shadow maps with prman, create zfiles with 
 *        x and y pixel resolutions that are powers of two.  The aspect 
 *        ratio should be 1 and the following RIB statements should 
 *        appear in the RIB file creating the zfile:
 *
 *                Display ".z" "zfile" "z"
 *                Hider "hidden" "jitter" [0]
 *                PixelFilter "box" 1 1
 *                PixelSamples 1 1
 *                ShadingRate 1
 *        
 *        Attempt to tighten the fov of the spotlight to include only 
 *        those objects casting shadows and in shadow.
 *
 *    References:
 *          [ALIA96]  Alias|Wavefront, Rendering in Alias, 
 *                    110 Richmond St. East, Toronto, Ontario, 
 *                    Canada, M5C 1P1, 1996, pp. 84-95.
 *          [PIXA89]  Pixar, The RenderMan Interface, Version 3.1, 
 *                    Richmond, CA, pp. 160-165, September 1989.  
 *          [PIXA96]  Siggraph '96 RenderMan Birds of a Feather meeting,
 *                    New Orleans, August, 1996.
 *          [UPST89]  Upstill, Steve, The Renderman Companion: A 
 *                    Programmer's Guide to Realistic Computer Graphics,
 *                    Addison Wesley, 1989. 
 *
 */
#include "tebLightCommon.h"


light tebLaserLight( 
                   /* Remember there is no decay or falloff being used
		    *    in this laser light shader. 
		    */
		   uniform float   intensity = 1.0;

		   /* Default to a red laser, because it looks cool. */
		   uniform color   lightcolor = color (1.0,0.0,0.0);

		   /* [UPST89] page 340 has "from" and "to" set to
                    *    (0,0,0) and (0,0,1) values in camera space,
                    *    respectively.  The spec [PIXA89] uses "shader"
                    *    space which is more intuitive.
                    */
		   uniform point  from = point "shader" (0.0,0.0,0.0);
		   uniform point  to = point "shader" (0.0,0.0,1.0);

		   /* Give the smallest cone angle possible to make light 
                    *    shader more efficient.  Using solar() without
                    *    a cone angle can be used if lightrelativelylarge 
                    *    is nonzero (see below).
                    */
		   uniform float   coneangle = radians(30.0);

		   /* Override coneangle by specifying the angle in
                    *    degrees.  If you use this parameter and want to
                    *    animate the cone angle down to zero, set coneangle
                    *    to zero so when coneangledegrees is set to zero
                    *    and defaults to using coneangle, a value of zero 
                    *    is present.  
                    */
		   uniform float   coneangledegrees = 0.0;

		   /* Specify a depth map (zfile) using shadowmap.  Use
                    *    a shadow map with lasers, because unlike spotlights
                    *    without shadowmaps creating a level of ambient light,
                    *    a laser shooting through a solid object with no hole
                    *    for the laser can be slightly noticable.
                    * BMRT users can turn on shadows.  The following shadow
                    *    settings apply only to the use of shadow maps.
                    */
		   uniform string  shadowmap = "";

		   /* Setting shadowmapopacity makes objects that cast 
                    *    shadows act as if they were translucent.
                    *    Setting to zero essentially removes the shadowmap. 
                    */
		   uniform float  shadowmapopacity = 1.0;

		   /* The sampling width for swidth and twidth is set by
                    *    the value given to shadowblur.
                    */
		   uniform float  shadowblur = 1.0;

		   /* Supersample the shadow map the number of times
                    *    shadowsamples is set to.  The value shadowsamples 
                    *    represents a 2D sampling scheme, so it is typically
                    *    set to a squared integer value.
                    */
		   uniform float  shadowsamples = 16;

		   /* The value bias was introduced in PRMan 3.6 and is a 
                    *    parameter given to shadow() to override the 
                    *    options set by bias0 and bias1 that are used to 
                    *    prevent self-shadowing.  Leave bias set to zero 
		    *    and this shader will not use it when calling shadow().
                    */
		   uniform float  shadowbias = 0.0; /* bias0=bias1=0.35 */

		   /* The radius of the laser light in shader space units. */
		   uniform float  lightlaserradius = 0.5; /* Assumes cm. */

		   /* Amount of outer radius (shader space units) to blur. */
		   uniform float  lightlaserblur = 0.0;

		   /* If nonzero, shader will not use a light cone. 
                    * Use this if for some reason your setting the radius to
                    *    be huge such as a meter.  Using solar() for large 
                    *    radius avoids the problem of the coneangle cutting
                    *    off light for large objects close up.  
                    * No coneangle for a laser will probably be inefficient
                    *    if the scope of the light source covers many objects.
                    */
		   float   lightrelativelylarge = 0.0;
		   )
{
   uniform vector  A = normalize(to - from);
   uniform float   lightconeangle;
   varying float   attenuation = 1.0;
   varying float   lradius; /* Laser radius. */
   varying float   bradius; /* Inside blur radius. */
   varying vector  l;


   if ( lightrelativelylarge == 0.0 )
   {
      lightconeangle = (coneangledegrees==0.0 
			? coneangle : radians(coneangledegrees) );
      illuminate( from, A, lightconeangle ) {
	 /* Check if the perpendicular distance of point L relative
          *    to "from" is in the "lightlaserradius" range.  If not
          *    set the "attenuation" to zero.  The rules say that
          *    shadow() can't be in a conditional block that had a 
          *    conditional test involving a varying value such as L
          *    The following if-statement only sets "attentuation" 
          *    as a way of zeroing out the output color Cl.
          *
          * The following test is based on taking the parametric form
          *    of a line: 
          *         P(x) = Pinit + x*DIRECTION.  
          * When a line from point Q is perpendicular to line P(x), then 
          *    (Q-P(x)).DIRECTION = 0.  Basically the dot product equals
          *    cos(degrees(90)) which is zero.  
          * Replacing value P(x) with (Pinit + x*DIRECTION),
          *         (Q - Pinit - x*DIRECTION).DIRECTION = 0.
          * Distributing DIRECTION over (Q - Pinit - x*DIRECTION) gives
          *         (Q - Pinit).DIRECTION - x*DIRECTION.DIRECTION = 0.
          * Adding (x*DIRECTION).DIRECTION to noth sides gives,
          *         (Q - Pinit).DIRECTION = x*DIRECTION.DIRECTION.
          * Dividing both sides by DIRECTION.DIRECTION,
          *         x = ((Q - Pinit).DIRECTION)/(DIRECTION.DIRECTION).
          * Plugging x into P(x) = Pinit + x*DIRECTION gives,
          *  Point closest to Q = 
          *   (Pinit + (Q - Pinit).DIRECTION)*DIRECTION/(DIRECTION.DIRECTION
          * With DIRECTION begin normalized vector called A, Pinit being
          *   the origin of shader space (0,0,0), and Q being the vector 
          *   called L, then expression reduces to the following:
          *         (0 + (L - 0).A)*A/A.A
          * Simplifying zeros and noting that A.A = 1 gives 
          *         L.A * A
          * which equals P(X) where x is the point on the line closest to 
          * the point L.  Subtracting the point L.A * A from L and
          * take the length to get the distance.
          */
	 lradius = length( L - L.A * A );
	 bradius = lightlaserradius - lightlaserblur;
	 attenuation = 1 - smoothstep( bradius, lightlaserradius, lradius );

	 /* Refer to tebLightCommon.h for the function tebShadow(). */
	 attenuation *= tebShadow( shadowmap, Ps, 
				   shadowmapopacity, shadowsamples, 
				   shadowblur, shadowbias );
	 
	 /* Set final version of the spotlight color on surface point Ps. */
	 Cl = attenuation * intensity * lightcolor;
      }
   }
   else
   {
      solar( A, 0 )
	 /*solar( A, radians(90) )*/
	 /* In a solar() statement of the form "solar(A,lightconeanlge)", 
          *    where lightconeangle is nonzero L is 
          *    assigned something between A and -reflect(-(E-P),N) 
          *    in PRMan 3.7 and in BMRT2.3.6beta
          *    it is assigned the value A.  In BMRT 2.3.6beta the value 
          *    given to the L of a
          *    surface shader's illuminance() statement block is -A.  
          *    Changing L in the "solar(A,lightconeanlge)" statement block
          *    appears not to affect a BMRT's surface shader's L value.
          *    In PRMan 3.7 an altered L value in a light shader appears
          *    as a negated value assinged to the corresponding surface 
          *    shader's L value.
          */ 
	 /* In a solar() statement of the form "solar()", L is assigned 
          *    something unkown in PRMan 3.7 and in BMRT 2.3.6beta it is 
          *    assigned 
          *    a zero vector (0,0,0).  Note that if L were to be
          *    assigned a value while in the illuminate() statement 
          *    block, that value would be negated and assigned to a 
          *    surface shader's L value in it's illuminance() statement 
          *    block.  This is true for both PRMan 3.7 and BMRT 2.3.6beta.
          * Also note that in a solar() statement block that has no parameters
          *    (no direction or cone angle), the value L is meaningless.  
          * BMRT initializes L to zero only once, so if L were altered based
          *    on its given value, the alteration builds as the light shader 
          *    is called.  Inshort if "L+=1" appeared in a BMRT's "solar()"
          *    statement block, the L would be incremented each time the
          *    shader is called -- although the first value in the vector L
          *    appears to be getting walked on -- but you shouldn't be
          *    doing this kind'a stuff anyway.  Inshort don't do this.
          */
      {
	 /* When this shader calculates its own L value of (Ps-from) it
          *    is not assigned to L but instead a local variable l (lowercase
          *    L).  The reason for avoiding changing L is because L represents
          *    a laserbeam's parallel light rays going in the direction A 
          *    given as the first parameter to solar().  Changing L changes
          *    a surface shader's L value which ruins the laser effect and
          *    the reason for using "solar(A,0)" in the first place.
	  */
	 l = Ps - from;

	 /* Refer to comment above about the distance check used below. */
	 lradius = length( L - L.A * A );
	 bradius = lightlaserradius - lightlaserblur;
	 attenuation = 1 - smoothstep( bradius, lightlaserradius, lradius );

	 /* Refer to tebLightCommon.h for the function tebShadow(). */
	 attenuation *= tebShadow( shadowmap, Ps, 
				   shadowmapopacity, shadowsamples, 
				   shadowblur, shadowbias );

	 /* Set final version of the spotlight color on surface point Ps. */
	 Cl = attenuation * intensity * lightcolor;
     }
   }
}

[Affine Toolkit]
[RIB Utilities] [Bitmap Utilities] [Handy Little Utilities]
[Libraries] [Using the Libraries]