/*
* Copyright (c) 1998 Thomas E. Burge. All rights reserved.
*
*
* FILE: tebSpotLight.sl
*
*
* DESCRIPTION:
* A general spotlight lightsource shader that also includes
* parameters that are loosely based on the Alias's PowerAnimator.
*
*
* Quick Reference to Parameters:
*
* float intensity = 1.0;
* color lightcolor = color (1.0,1.0,1.0);
* float coneangle = radians(30.0);
* float coneangledegrees = 0.0;
* float conedeltaangle = radians(5.0);
* float conedeltaangledegrees = 0.0;
* point from = point "shader" (0.0,0.0,0.0);
* point to = point "shader" (0.0,0.0,1.0);
* float decay = 2.0;
* float beamdistribution = 2.0;
* string shadowmap = "";
* float shadowmapopacity = 1.0;
* float shadowblur = 1.0;
* float shadowsamples = 16;
* float shadowbias = 0.0;
* string lightstencil = "";
* string lightsecondstencil = "";
* float lightinvertstencil = 0;
* string lightgel = "";
* string lightsecondgel = "";
* float lightimageconeangle = 0.0;
* float lightimageconeangledegrees = 0.0;
* float lightimageblur = 1.0;
* float lightimageblurangle = 0.0;
* float lightimageblurangledegrees = 0.0;
* point lightup = point "shader" (0.0,1.0,0.0);
* float lightimagerotate = 0.0;
* float lightimagerotatedegrees = 0.0;
* float lightimagelerp = 0.0;
* float lightcutoff = 0.0;
*
* 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 tebSpotLight(
/* For standard spotlight parameters refer to [UPST89]
* page 340 for setting intensity, lightcolor,
* coneangle and conedeltaangle.
*/
uniform float intensity = 1.0;
uniform color lightcolor = color (1.0,1.0,1.0);
/* Cannot set coneangle wider than 90 degrees. */
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;
/* Set conedeltaangle from coneangle downto zero. */
uniform float conedeltaangle = radians(5.0);
/* Override conedeltaangle by specifying the angle in
* degrees.
*/
uniform float conedeltaangledegrees = 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);
/* Alias PA defaults to decay set to 1 and Alias Sketch!
* to 0. Sketch! RIBs do not export the value "decay",
* so users should add it in and match decay to the
* setting in Sketch! where 0=None, 1=Slow,
* 2=Realistic, and 3=Fast. Sketch! users should also
* add beamdistribution set to 0. This setting is based
* on what PowerAnimator likes to do.
* I'm going to set the default decay value to follow
* the square-law falloff with distance from light.
* This setting makes tebSpotLight default to acting
* like the standard spotlight shader.
* Refer to the [UPST89] page 341.
*/
uniform float decay = 2.0;
/* Alias PA RIBs typically have beamdistribution set to
* zero. So I believe if Alias Sketch! users set the
* decay level (refer to the "decay" above) and set
* beamdistribution to zero, they should see their
* RenderMan renderings match their Alias Sketch!
* renderings in light intensity.
*/
uniform float beamdistribution = 2.0;
/* Specify a depth map (zfile) using shadowmap. */
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 */
/* By setting lightstencil to a name of a single channel
* texture map, the texture blocks light where it is
* black (0.0,0.0,0.0) and lets light through where
* it is white (1.0,1.0,1.0). Using a stencil is like
* positioning in front of the spotlight a metal
* sheet with a pattern of holes that lets light
* through according to the pattern of holes.
*/
uniform string lightstencil = "";
/* Set lightimagelerp to blend between lightstencil
* and lightsecondstencil.
*/
uniform string lightsecondstencil = "";
/* If not zero, lightinvertstencil inverts the stencil. */
uniform float lightinvertstencil = 0;
/* Give the spotlight different colors depending on a
* texture. The texture is stretched over the end of
* the cone defining the spotlight. The center of
* the texture is the center hotspot of the spotlight.
*/
uniform string lightgel = "";
/* Set lightimagelerp to blend between lightgel
* and lightsecondgel.
*/
uniform string lightsecondgel = "";
/* If not zero, lightstencil and lightgel are mapped
* to a cone angle of lightimageconeangle. This
* allows the coneangle of the spotlight to change
* while not adjusting the size of the stencil and
* a gel images. The images remained locked as the
* spot of the spotlight shrinks or grows.
* Note that if coneangle is greater than
* lightimageconeangle, the spotlight is limited
* to lightimageconeangle.
*/
uniform float lightimageconeangle = 0.0;
/* Override lightimageconeangle by specifying the angle in
* degrees.
*/
uniform float lightimageconeangledegrees = 0.0;
/* Amount to blur the stencil and gel by using swidth
* and twidth.
*/
uniform float lightimageblur = 1.0;
/* Amount to blur the stencil and gel. This can soften
* a stencil a bit when set to a low number such as
* 0.1 degrees (0.001745 radians).
*/
uniform float lightimageblurangle = 0.0;
/* Override lightimageblurangle by specifying the angle in
* degrees.
*/
uniform float lightimageblurangledegrees = 0.0;
/* By default the direction "up" is considered to be the
* positive Y direction in shader space. Set lightup
* to orient lightstencil and lightgel.
*/
uniform point lightup = point "shader" (0.0,1.0,0.0);
/* You could rotate the stencil and gel images by
* setting lightup, but use lightimagerotate instead.
* This parameter should be more intuitive for
* rotating counter-clockwise the projected images.
*/
uniform float lightimagerotate = 0.0;
/* Override lightimagerotate by specifying the angle in
* degrees.
*/
uniform float lightimagerotatedegrees = 0.0;
/* If you use the new "disk" filter that comes with PRMan
* 3.8, the following comments about large blur do not
* apply anymore.
*/
/* Large lightimageblur and/or lightimageblurangle values
* begins to show artifacts in the image as a the
* begins to use a low resolution version of the texture
* map.
* If you want the look of a spotlight projecting an image
* going in and out of focus, take the stencil or gel
* image being used and blur it up in PhotoShop. Then
* assign the blurred stencil or gel to
* lightsecondstencil or lightsecondgel respectively.
* Use lightimagelerp from 0.0 to 1.0 to lerp between
* the images to produce an animation of the projected
* image becoming blurry or more in focus. The value
* 0.0 gives only lightstencil and lightgel. The value
* 1.0 gives only lightsecondstencil or lightsecondgel.
*/
uniform float lightimagelerp = 0.0;
/* Cut the lightsource off once it reaches the distance
* lightcutoff. If lightcutoff is zero it is ignored
* and the decay value listed above determines the
* spotlight's falloff.
*/
uniform float lightcutoff = 0.0;
)
{
uniform float cosoutside;
uniform float cosinside;
uniform vector A;
uniform vector UP;
uniform vector RIGHT;
varying float cosangle;
varying float len;
varying float nLdotA;
varying float attenuation;
uniform float lightconeangle;
uniform float lightconedeltaangle;
uniform float lightimageca;
uniform float lightangleblur;
uniform float lightrotation;
uniform float outsideconeangle;
uniform float twicelightconeangle;
varying float stencil,stencil2;
varying color gel = color (1.0,1.0,1.0);
varying color gel2;
varying float ss, tt;
uniform float costheta, sintheta;
varying float x = 0;
varying float y = 0;
uniform float halfdelta;
varying float ds,dt;
#ifdef BMRT
varying float dist;
#endif
/* Calculate a normalized vector pointing straight out of the spotlight. */
A = normalize(to - from);
lightconeangle = (coneangledegrees==0.0
? coneangle : radians(coneangledegrees) );
lightconedeltaangle = (conedeltaangledegrees==0.0
? conedeltaangle : radians(conedeltaangledegrees));
lightrotation = ( lightimagerotatedegrees == 0.0
? lightimagerotate : radians(lightimagerotatedegrees));
lightimageca = ( lightimageconeangledegrees == 0.0
? lightimageconeangle
: radians(lightimageconeangledegrees));
lightangleblur = ( lightimageblurangledegrees == 0.0
? lightimageblurangle
: radians(lightimageblurangledegrees));
/* The spotlight will be blocked a angles outside the cone angle of
* lightimageconeangle, so find the minimum angle to use.
*/
if ( lightimageca != 0.0 )
lightconeangle = min( lightconeangle, lightimageca );
cosoutside= cos(lightconeangle);
cosinside = cos(lightconeangle-lightconedeltaangle);
illuminate( from, A, lightconeangle )
{
/* In the above illuminate() statement
* "illuminate( from, A, lightconeangle )" the value L is assigned
* the value (Ps-from). Note that if L were 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.
* This can be seen by placing printf()'s in a light shader and surface
* shader. In the light shader's illuminate statement block
* print L, then set L = L + 1 to each of the three values in the L
* vector. In a surface shader print L in an illuminance()
* statement block. Note that the surface shader's L equals the
* a negative version of the lightsource's incremented L.
*/
/* Give Cl an initial color and then alter it along the way. */
Cl = lightcolor;
/* When calculating L, prman refers to the point "from" given to
* illuminate() to calculate L = Ps - "from".
*/
len = length(L);
/* Since we needed to have "len" anyway use it to normalize nLdotA,
* instead of having normalize() recalculate the length again.
*/
nLdotA = (L.A) / len;
cosangle = nLdotA;
/* Typically there is a divide by L.L to do an inverse square for
* the falloff of the light source intensity with distance.
* Refer to the [UPST89] page 341. But to handle
* the value decay, a division of the value pow(length(L),decay)
* is used. Alias provides a shader with PowerAnimator (8.2 and
* previous releases) called, ari_spotlight that is basically
* the standard spotlight shader with a variable "decay" added
* and Cl divided by pow(length(L),decay). One thing to note,
* this shader retains the L.L divide even though a division
* involve "decay" was added. The L.L should be removed to match
* the Alias renderer when the light source medium to long distance
* from the target objects.
*/
if ( len <= lightcutoff || lightcutoff == 0.0 )
{
attenuation = pow(cosangle, beamdistribution) / pow(len,decay);
attenuation *= smoothstep( cosoutside, cosinside, cosangle );
}
else
{
attenuation = 0.0;
}
/* The stencil and gel are set to cover the end of the cone defining
* the spotlight.
*/
if ( lightstencil != "" || lightgel != "" )
{
/* Set UP, RIGHT and A to form an orthonormal basis. */
UP = normalize(lightup - from);
/* Find direction pointing to the right of the spotlight. */
RIGHT = UP^A;
/* Set vector UP so that it is perpendicular to A which
* represents the direction of a ray of light shooting straight
* out of the spotlight.
*/
UP = A^RIGHT;
if ( lightimageca == 0.0 )
{
outsideconeangle = lightconeangle;
twicelightconeangle = 2 * lightconeangle;
}
else
{
outsideconeangle = lightimageca;
twicelightconeangle = 2 * lightimageca;
}
ss = -asin((L.UP)/len);
tt = -asin((L.RIGHT)/len);
ss += outsideconeangle;
tt += outsideconeangle;
ss /= twicelightconeangle;
tt /= twicelightconeangle;
/* Rotate the image about its texturecoordinate center. */
if ( lightrotation != 0.0 )
{
/* Rotate (ss,tt) about the center (0.5,0.5). */
costheta = cos(lightrotation);
sintheta = sin(lightrotation);
x = ss - 0.5;
y = tt - 0.5;
ss = x * costheta - y * sintheta + 0.5;
tt = x * sintheta + y * costheta + 0.5;
}
/* Unlike a surface shader that has the sample being calculated
* at the lowest u,v value of a micropolygon and du and dv
* indicating the sampling area. This light shader is going to
* actually sample the texturemap at the center of the sample.
* Inshort instead of (s,t) blurring to (s+ds,t+dt), we'll
* do (s-ds/2,t-dt/2) to (s+ds/2,t+dt/2) which
* isn't the norm for most shaders.
*
*/
halfdelta = (lightangleblur / twicelightconeangle);
ss -= halfdelta;
tt -= halfdelta;
ds = dt = 2 * halfdelta;
/* Larry added mkmip which allows for a boxfiltered texmap with
* with surrounding black. If you use that feature, the following
* comments and code no longer apply.
*/
/* Handle edge conditions when calculating ss, tt, swidth
* twidth for BMRT or when an inverted stencil is being used
* with prman. The texture() function in BMRT repeats a
* texture when s,t are out of the range [0,1]. PRMan allows a
* texture to have different "wrap modes" for its textures.
* The default is black, which has texture() return zero for
* s,t coordinates outside a [0,1] range.
*
* Cutting down the area around the edges where a texmap is being
* accessed may brighten the edge if white in the texmap is
* present. The brighter colors are the result of a texmap's
* edge color getting more emphasis when a black color
* surrounding the texmap is not being averaged in.
*/
#ifdef BMRT
ss = max( 0.0, ss );
tt = max( 0.0, tt );
dist = ss + ds;
if ( dist > 1.0 )
ds -= dist - 1.0;
dist = tt + dt;
if ( dist > 1.0 )
dt -= dist - 1.0;
#endif
/* If a stencil is not being used, the default value of 1.0 that
* was given to attenuation when it is declared above will
* be used.
*/
if ( lightstencil != ""
&& (lightsecondstencil == "" || lightimagelerp == 0.0))
{
/* Texture coordinates are in the following order:
* (0,0), (1,0), (0,1), and (1,1) where (0,0) is
* the lower left and (1,1) is the upper right.
* Refer to [UPST89] pages 246 and 251 and [PIXA89]
* page 39. Its hard to find a place that mentions
* the order of the four pairs of texture
* coordinates, so I stuck it in here. It is the
* order given to point used in RiTextureCoordinates().
*/
stencil = texture( lightstencil,
ss,tt, /* (0,0) */
ss+ds,tt, /* (1,0) */
ss,tt+dt, /* (0,1) */
ss+ds,tt+dt, /* (1,1) */
"swidth", lightimageblur,
"twidth", lightimageblur
#define _USE_DISK_
#ifdef USE_DISK
, "filter", "disk"
#endif
);
/* Invert the stencil value if lightinvertstencil is nonzero. */
if ( lightinvertstencil != 0 )
stencil = 1.0 - stencil;
attenuation *= stencil;
}
else if ( lightstencil != "" && lightsecondstencil != "" )
{
stencil = texture( lightstencil,
ss,tt,
ss+ds,tt,
ss,tt+dt,
ss+ds,tt+dt,
"swidth", lightimageblur,
"twidth", lightimageblur
);
stencil2 = texture( lightsecondstencil,
ss,tt,
ss+ds,tt,
ss,tt+dt,
ss+ds,tt+dt,
"swidth", lightimageblur,
"twidth", lightimageblur
);
/* Invert the stencil value if lightinvertstencil is nonzero. */
if ( lightinvertstencil != 0 )
{
stencil = 1.0 - stencil;
stencil2 = 1.0 - stencil2;
}
attenuation *= (1.0-lightimagelerp)*stencil
+ lightimagelerp*stencil2;
}
/* If a gel is not being used the lightcolor is left alone and
* its default value of (1.0,1.0,1.0) is used unless overridden
* by a parameterlist assignment of lightcolor.
*/
if ( lightgel != ""
&& (lightsecondgel == "" || lightimagelerp == 0.0))
{
gel = texture( lightgel,
ss,tt,
ss+ds,tt,
ss,tt+dt,
ss+ds,tt+dt,
"swidth", lightimageblur,
"twidth", lightimageblur
);
/* Scale lightcolor by the color given by gel. */
Cl *= gel;
}
else if ( lightgel != "" && lightsecondgel != "" )
{
gel = texture( lightgel,
ss,tt,
ss+ds,tt,
ss,tt+dt,
ss+ds,tt+dt,
"swidth", lightimageblur,
"twidth", lightimageblur
);
gel2 = texture( lightsecondgel,
ss,tt,
ss+ds,tt,
ss,tt+dt,
ss+ds,tt+dt,
"swidth", lightimageblur,
"twidth", lightimageblur
);
/* Scale lightcolor by the color given by gel. */
Cl *= (1.0-lightimagelerp)*gel + lightimagelerp*gel2;
}
}
/* 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 * Cl;
}
}
[Affine Toolkit]
[RIB Utilities]
[Bitmap Utilities]
[Handy Little Utilities]
[Libraries]
[Using the Libraries]