/*
* 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]