Shading Language Features and
    LimitationsIgnoring Out-of-range Texture Values
_lightingstart() and _needsurface()
Message Passing for Shader Execution
This section describes the specific features and limitations of the implementation of the RenderMan Shading Language present in PhotoRealistic RenderMan.
As of version 3.8, PRMan allows you to write new built-in SL functions in C or C++. Such functions overcome many of the limitations of SL-defined functions. Full documentation on the syntax, programming requirements, capabilities and limitations of this new feature are provided in the extensive on-line document RenderMan Shading Language Plugins.
PRMan 10.0 and higher support a new ignoreabove option for all texture-related shadeops. This allows texture filtering to ignore values over a user specified threshold. The option specifies a single float as an argument. All values which exceed the specified value are not averaged into any filtering that is done. This is mostly useful for non-mipped map floating point shadow or zfile textures. Often infinite values cause strange shadow behavior along silhouette edges, this may help alleviate some of this.
PRMan 10.0 and higher support string constant concatenation, using C syntax:
string s = "Hello" "World";
In PRMan, the pieces of attribute state that can be retrieved via the attribute() function are:
Name Type Comment "ShadingRate" float "Ri:ShadingRate" float Same as ShadingRate. This form is preferred "Matte" float "Ri:Matte" float Same as Matte. This form is preferred "Sides" float "Ri:Sides" float Same as Sides. This form is preferred "Ri:Color" color "Ri:Opacity" color "Ri:DetailRange" float[4] "Ri:TextureCoordinates" float[8] "Ri:Orientation" string Either inside or outside "Ri:ShadingInterpolation" string Either smooth or constant "Ri:Transformation" matrix The object to world transformation "cull:backfacing" float "cull:hidden" float "derivatives:centered" float "derivatives:extrapolate" float "dice:binary" float "dice:hair" float "dice:rasterorient" float "displacementbound:sphere" float "displacementbound:coordinatesystem" string "grouping:membership" string The name of the tracegroup or an empty string if there is no group (NOTE: due to an optimization, this is not implemented for surfaces with a ray depth of zero). "geometry:backfacing" float 1.0 if the geometry has had its orientation reversed (normals flipped), which may be due to various factors (negative determinant, orientation, or double shading). 0.0 otherwise. "GeometricApproximation:motionfactor" float "identifier:name" string "irradiance:handle" string "irradiance:filemode" string "irradiance:maxerror" float "irradiance:maxpixeldist" float "photon:estimator" float "photon:globalmap" string "photon:causticmap" string "photon:shadingmodel" string "sides:backfacetolerance" float "sides:doubleshaded" float "shade:strategy" string "stitch:enable" float "stitch:group" float "stochastic:sigma" float "trace:bias" float "trace:displacements" float "trace:maxspeculardepth" float "trace:maxdiffusedepth" float "trace:samplemotion" float "user:myname" variable allows a shader to access a user defined attribute name myname, and requires a variable with type matching the RiDeclare declaration."visibility:camera" float "visibility:diffuse" float "visibility:specular" float "visibility:transmission" float "visibility:photon" float 
In PRMan, the pieces of option state that can be retrieved via the option() function are:
Name Type Comment "BucketSize" float[2] returns the bucket size "limits:bucketsize" float[2] Same as BucketSize. Preferred. "limits:gridsize" float "limits:texturememory" float "limits:brickmemory" float "limits:geocachememory" float "limits:zthreshold" color "limits:othreshold" color "limits:extremedisplacement" float "Clipping" float[2] see RiClipping "Ri:Clipping" float[2] Same as Clipping. Preferred. "CropWindow" float[4] see RiCropWindow"Ri:CropWindow" float[4] Same as CropWindow. Preferred. "DepthOfField" float[3] see RiDepthOfField"Ri:DepthOfField" float[3] Same as DepthOfField. Preferred. "DeviceResolution" float[3] returns the resolution in x and y and the pixel aspect ratio. These are usually the three numbers passed to RiFormat, but may be different when FrameAspectRatio or ScreenWindow are non-square;"Format" float[3] returns the current resolution as specified in RiFormat"Ri:Format" float[3] Same as Format. Preferred. "Frame" float returns the current frame number as specified in RiFrameBegin"Ri:FrameBegin" float Same as Frame. Preferred. "FrameAspectRatio" float returns the current frame aspect ratio"Ri:FrameAspectRatio" float Same as FrameAspectRatio. Preferred. "Hider" string returns the name of the current hider"RiHider:name" string Same as Hider. Preferred. "RiHider:jitter" float "RiHider:mpcache" float "RiHider:mpmemory" float "RiHider:mpcachedir" string "RiHider:samplemotion" float "RiHider:subpixel" float "RiHider:maxvpdepth" float "RiHider:zfile" string "RiHider:reversesign" float "RiHider:depthbias" float "RiHider:emit" float "RiHider:secondarycaustics" float "RiHider:extrememotiondof" float "RiHider:sigma" float "RiHider:sigmablur" float "Shutter" float[2] see RiShutter "Ri:Shutter" float[2] Same as Shutter. Preferred. "searchpath:resource" "searchpath:shader" "searchpath:texture" "searchpath:archive" "searchpath:procedural" string returns the indicated searchpath"shadow:bias" float "shutter:offset" float "statistics:endofframe" float Enable end-of-frame statistics. "statistics:filename.xml" string The name of the statistics XML file "texture:enable gaussian" float "texture:enable lerp" float "trace:maxdepth" float "trace:specularthreshold" float "user:myname" allows a shader to access a user defined option name myname, and requires a variable with type matching the RiDeclare declaration.
The additional arguments that may be used in PRMan with the texture() function:
Attribute Value Comment "filter" "box" this is the default filter if not specified"filter" "disk" optimized for large blur sizes, and (unlike the other filters) is free of mipmap artifacts because it uses all mipmap levels in its computations; it is about twice as expensive as the other filters."filter" "gaussian" "gaussian" should produce higher quality results."filter" "lagrangian" The Lagrangian filter is designed from the ground up for speed and sharpness. Texture files with MIP map pyramids are required, and full pyramids are recommended. For each sample, the system selects the next highest resolution image plane and performs a 4x4 bicubic interpolation combined with a 4x4 decimation filter in one pass. The result is equivalent to a point sample of an exactly rescaled and subpixel-shifted image."filter" "radial-bspline" specifically designed for optimally filtering displacement textures."filter" "ewa" The elliptical weighted average filter uses an elliptical region in S-T space to filter textures. The ellipse may be specified explicitly using the four-point invocation of the texture() call, where the four points define the convex hull of the ellipse. The order of the four S-T points does not matter."lerp" 0,0selects whether to interpolate between adjacent resolutions of a multi-resolution texture in order to smooth the transition between resolutions."lerp"takes a uniform float value. Possible values are 0.0 to disable the interpolation and 1.0 to enable it. The default is 0.0 to not interpolate.
In PRMan, the specular and diffuse shadeops respond to two special parameters of the light shader. Any light shader which contains the following parameter
float __nondiffuse = 1
will be ignored by diffuse (note that there are two underbars). Similarly, any light which contains the following parameter
float __nonspecular = 1
will be ignored by both specular and phong. Please note that if the value of the parameter is 0.0, it is not ignored, so this behavior can be controlled both from the RIB file, or procedurally from inside the light shader, if desired. These variables may be either uniform or varying. These special parameters can also be accessed within illuminance statements, as described in the the Specification.
The shadow() function in PRMan has been enhanced to support soft shadows with true penumbral fadeout, simulating shadows of area light sources. The method uses multiple rendered shadow maps to infer visibility information from a light source whose extended geometry is also specified in the shadeop.
The enhanced shadow call is fully backwards-compatible with the Specification, but supports a new form to allow specification of multiple shadow maps in a single call:
float shadow(string maplist, texture coordinates[,parameterlist])
where maplist is a comma-separated list of shadowmap filenames.
In the past, the location of the point light source (as far as shadows were concerned) was implicit in the shadow map matrices. When using multiple maps to simulate an area light source, the user must also specify the size and shape of the intended light source in the shadow shadeop. The following new parameters to shadow support this new soft shadow method:
The old parameters "bias" and "samples" still apply when using the new soft-shadow form:
This new method of generating soft shadows requires multiple shadow maps to infer geometry between the surface being shaded and the light source. For best results, the views should be placed on or near the light source, pointing in the direction of the objects that will cast shadows. All views should fully contain the shadowing objects, although they will contribute slightly different information (due to their differing viewpoints). Specifying more views gives the renderer more information to work with, and thus can improve the quality of the shadows rendered. However, too many views can be unnecessarily expensive, so caution is advised. For most scenes, three to five shadow maps will be sufficient to capture the geometry sufficiently.
The shadow maps that are used for soft shadow information contain additional mip-map information that makes the soft shadow evaluation more efficient. When creating the .shad files, instead of txmake -shadow file.z file.shad you should use txmake -minmaxshadow file.z file.shad which will generate an extended shadow map file. These files are backwards-compatible with the normal shadow call (the new files can be used in the standard calls), but are required when using the soft shadow form.
An example of the soft-shadow form of shadow, using four shadow maps and a triangular light source would be:
attenuation = shadow("view1.shad,view2.shad,view3.shad,view4.shad", Ps, "source",
			Pl1, Pl2, Pl3, "gapbias", 0.0015, "bias", 0.001);
    where Pl1, Pl2, and Pl3 are uniform points (the vertices of the triangle), and view1.shad, view2.shad, view3.shad and view4.shad are new-format shadow map files.
In PRMan 11.0 support for "deep shadowmaps" was added. This output format stores more information per pixel than a normal shadowmap, and has three main advantages over normal shadowmaps:
Creation of these new shadow files is achieved with a new display driver, deepshad.
Starting in 11.0, deep shadow files are supported by the shadow() shadeop, which means that existing shaders can use these shadow files. In addition, the shadow() shadeop can now return a color (like texture()), which is necessary to take advantage of any color information in a deep shadow file.
Currently, the only way to access deep texture maps is through the shadow() shadeop.
The shadow call can also trace rays to compute whether a surface point is in shadow or not, as an alternative to using shadow maps. This functionality was added in release 11.0. Ray tracing is used when the special keyword "raytrace" is supplied as the "shadow map" name. For example, a light source shader might contain a line like this:
    attenuation = shadow("raytrace", Ps, "samples", samples);
    Since the shadow map name is usually passed in as a shader parameter
    from the RIB file, many light source shaders can be used for ray tracing
    just by supplying "raytrace" as the map name, without
    even needing to recompile the shader.   However, because ray traced
    shadow blur and other parameters can add new effects, most people will
    probably want to write new shaders.
    Note: the transmission function provides a direct interface to ray-traced shadow determination, with additional capabilities and options.
Note that shadow rays will only intersect objects that have their transmission visibility enabled. This attribute controls whether shadow and transmission rays can see particular primitives, which is similar to including or excluding particular objects from the shadow map generation pass when using the traditional map-based shadow call.
Ray traced shadows can be used to obtain colored shadows from semi-transparent objects. These colored results are obtained by assigning the results of the shadow call to a color rather than the typical float; this is similar to the deep shadow behavior described above.
The ray-tracing version of shadow() accepts the following optional parameters:
"blur" (float)
	  - controls the ray traced shadow blurriness.
	  Units are radians, describing the half-angle of the sample cone.
	  The effect is similar to sampling a spherical light source of
        finite size.  You should almost always increase the number of
	samples as the blur cone increases to reduce noise."samples" (uniform float)
	  - causes supersampling of the underlying
        transmission function."label" (uniform string)
	  - applies a label to the shadow rays, it can
	be queried by shaders on hit surfaces.
      "subset" (uniform string)
          - shadows rays will only be tested against objects that 
	are members of the named groups.
      The environment call usually looks up reflection colors in a previously rendered environment map. Starting with release 11.0, it can alternatively trace rays to reflections. This functionality overlaps signficantly with the trace and gather calls, but is provided so that existing shaders that make environment calls can continue to be used. Ray tracing will be used when the special keyword "raytrace" is provided as the environment map name. For example, a surface source shader might contain a line like this:
    color e = environment("raytrace", dir);
    Since the environment map name is usually passed in as a shader parameter
    from the RIB file, many existing surface source shaders can be used for 
    ray tracing just by supplying "raytrace" as the map name
    from the RIB file, without
    even needing to recompile the shader.
    Note that environment rays will only intersect objects that have their trace visibility enabled. This attribute controls whether environment, gather, and trace rays can see particular primitives, which is similar to including or excluding particular objects from the environment map generation pass when using the traditional map-based environment call.
When the function return value is assigned to a float, rather than a color,
    then environment returns occlusion, which is the fraction
    of rays that hit something; when samples=1 then the result
    will be either 0 or 1, when samples > 1 then the result will be fractional.
When ray tracing environments, the following optional parameters are supported:
blur"
        (float) - controls the samplecone of the underlying trace call.samples" 
        (uniform float)  - controls the samples of the underlying trace call.bias"
        (uniform float) - an offset used to prevent self intersection artifacts.occlusion"
        (output varying float)  - returns the alpha value of the environment map
        or the coverage of the underlying trace call.opacity" 
        (output varying color)  - returns the opacity of the environment or the
        underlying trace call.label" 
        (uniform string) - applies a label to the underlying trace call.
      subset"  (uniform string) -
        specifies that traced environments only consider objects that are
        members of the provided group name.
      maxdist" (uniform float) -
        specifies that traced environments only consider objects closer than the
        provided distance.
      In addition to the standard data names listed in Table 15.3 in the Specification, the textureinfo() shadeop supports additional query modes.
The exists option can be used to query whether a texture map is actually present, with the shadeop itself returning 1 if the texture exists or 0 otherwise. The variable passed in as the third argument will be ignored. This allows for the following usage:
if (textureinfo(texturename, "exists", 0)) {
    Ci = texture(texturename);
} else {
    Ci = color(1, 0, 0); /* Mark color as red if texture map is missing */
}
    The pixelaspectratio returns a float, which is the original aspect ratio of the source image used to generate the texture map (useful because a resize operation is often involved when creating the texture map). This lookup does not work on environment maps.
PRMan 10 and higher support two special no-op shadeops which serve as optimization hints to the Irma re-renderer.
The _lightingstart() shadeop marks the end of light-independent calculations (texturing and noise for example), and the beginning of light dependent calculations (such as calls to diffuse(), illuminance(), etc); this allows Irma to cache all shading results which occur before lighting.
The _needsurface() shadeop works in the same way for atmosphere shaders, except that it should be inserted just prior to any call which sets the value of the output color Ci.
The shader compiler attempts to place both shadeops in reasonable parts of the shaders. For complicated shaders, the result may not always be optimal and can be overridden by explicitly adding the statements to the shader sourcecode. For example:
surface
matte( float Ka=1, Kd=1 )
{
    normal Nf;
    Nf = faceforward(normalize(N),I);
    Oi = Os;
    _lightingstart();
    Ci = Os * Cs * ( Ka*ambient() + Kd*diffuse(Nf) ) ;
}
    
     
    Sending parameters with rays to shaders on hit objects
    When gather() is used to trace rays into the scene,
    it can send arbitrary values with each ray.  The sent values are
    used to override shader parameters with matching names in the
    shaders on objects hit by the rays.  The syntax is: 
    float val = (some override value);
    gather(..., "send:surface:Ks", val, ...) 
    which means take the local (shooting shader) variable "val" and
    use its value to override parameter "Ks" of the hit surface
    shader.  These sent overrides are far more general than the
    alternative string-only "label" mechanism, and the
       receiving shader need not use rayinfo() or be otherwise
       "ray-aware" to use them. 
Values sent in this way can be of any type.
    If a particular shader does not have the given parameter (same name
    and type), then the send is ignored.
   Gather retrieves values, such as the color of the hit surface, using similar variable-fetching syntax.
Sending parameters to LightSource shaders
       Similarly, surface and volume shaders calling illuminance()
       can now send parameter overrides to lightsource shaders directly.
    Illuminance() can also fetch
       back auxilliary values computed inside lightsource shaders as well.
       These extensions, which share the
       gather() messaging syntax,
       complement the existing lightsource and surface
       message passing functions:   the new "forward" send requires no
       special knowledge in the lightsource, and variables other than
       predefined "output" parameters can be fetched.
    
Here is an example which sets the light's "intensity" parameter and retrieves the light's "temperature" value after execution, if it exists:
     float k = 0;
     float val = (some override value);
     illuminance(..., "send:light:intensity", val, "light:temperature", k) {
         ... illuminance block, using k
     }
    Just as with gather, above, if the lightsource shader does not have
    the specified variables, then sends are ignored and fetches
    do not change the current local value.  Note that illuminance
    sends and fetches are restricted to the "light:" namespace
    of queries.
Irradiance maps 
Irradiance maps are sparse volumetric files containing samples representing
an irradiance (incoming illumination) function.  Irradiance maps 
are superseded by the new and more general point cloud files, and is no
longer supported.
float irradiancecache( string
operation, string handle, string filemode, point P, normal N, ... )
This function is no longer supported.
   
    Explicit Light Cache Control
   
    
       As an optimization, PRMan has always cached the results of
       light shader invocations between multiple calls to
       illuminance. This may sometimes lead to the wrong
       result if rerun light shaders change their output values due to
       a combination of message passing and changes in the invoking
       surface or atmosphere shader.  In prior releases, this
       behaviour could be defeated by the use of "P = P"
       prior to new calls to illuminance, or by using
       illuminance("category", P+vector(0), ...).
       PRMan 12.5 now allows explicit light-cache control via the
       illuminance parameter "lightcache". The new parameter
       is used this way:
    
    illuminance("category", ..., "lightcache", "reuse")
     or
    illuminance("category", ..., "lightcache", "refresh")
     
        The default setting is "reuse", which is the existing
        behavior: to use previously cached output values for all light
        shaders which match the category, if they exist from previous
        invocations of the light shaders (due to previous illuminance
        statements). The setting of "refresh" clears the
        output values and reruns the light shaders, again for only
        those light shaders which match the category.
        Using "lightcache" "refresh" is more efficient than
        the old method of using "P=P" before the illuminance
        call, because only the lights matching the category are
        affected.  It is similar to using illuminance("category",
        P+vector(0)), but it is more explicit, easier to
        understand, and possibly more efficient.
    
gridpattern()
float gridpattern( string pattern, float context, ... )
Gridpattern returns a one or a zero for each shading point,
according to the specified pattern and context.  Like other varying
functions, gridpattern returns a result which may be
different at each shading point on the underlying grid; however,
unlike most other functions, the output is intentionally a function
of the shading grid's structure.  It is typically used to produce
a mask using one of the built-in pattern generators,
the mask is then used in a varying conditional to apply specific
operations to the on subset of points.  Furthermore,
some patterns can be applied iteratively, in conjunction with a
preserved context, and will become successively more
refined in terms of the sets of points selected, until
all of the points on the grid have been visited.
The available patterns are:
  
  "gridpoint" 
	one shading point on at a time 
	convergent  
  "binaryrefinement" 
	sparse-to-dense sampling 
	convergent  
  "concentric" 
	rings around the periphery of the grid ¹ 
	convergent  
  "checkerboard" 
	alternating on and off points ¹ 
	non-convergent  
  "random" 
	a random distribution of on and off points 
	non-convergent  
  ¹ some
  patterns have undefined results on non-rectangular internal grid
  types  
  
Note: The internal structure and content of shading
grids are inherently implementation dependent, and they are strongly affected
by the input geometry types, shading rate, camera settings, and numerous other
tuning parameters.  There are no guarantees about the specific
behavior or reproducibility of patterns.
The context variable is used to carry state between iterative
calls to gridpattern; the meaning and usage of context
depends on pattern.  Usually context should be initialized
to zero prior to first use. Each pattern will modify context
differently and it should generally be assumed to be private data owned
by gridpattern. Some patterns guarantee convergence in the sense
that after a series of calls, all grid points will have been "visited" and
further calls will return zero for all points.
The shading language supports several familiar conditional constructs
which cause operations to occur on grid subsets; consider: 
   	if (s < 0.5) k += 1;
The varying variable k will only be incremented at the points which
satisfy the condition.  Similarly, gridpattern produces a varying
float mask which is 1 for some points, 0 for others.  This mask 
might be used directly (as a float) or used in further conditional expressions.
For example, for a shader executing on a tiny 5x5 grid:
   	varying float patctx = 0;  /* initialize the context */
   	varying float f = gridpattern("concentric", patctx);
the variable f will now contain the following pattern:
   1 1 1 1 1
   1 0 0 0 1
   1 0 0 0 1
   1 0 0 0 1
   1 1 1 1 1
the patctx variable allows gridpattern to track a particular
context through repeated calls, so a subsequent call to:
   	varying float g = gridpattern("concentric", patctx);
would produce, in g,    
and f+g would be 
   0 0 0 0 0
   0 1 1 1 0
   0 1 0 1 0
   0 1 1 1 0
   0 0 0 0 0
 
  
   1 1 1 1 1
   1 1 1 1 1
   1 1 0 1 1
   1 1 1 1 1
   1 1 1 1 1
 
After another iteration (in which only the center spot would be one), the 
pattern will have converged, meaning that all of the gridpoints
will have been visited and subsequent calls to gridpattern (with
the same context variable) will return all zeros.
Another pattern type, named "binaryrefinement", tries to select
a few widely spaced points for the first pass, and then more points which
are less widely spaced for the second pass, etc., until all points have been
visited.
	
	The while loop usually has the desirable behavior that 
	only shading points which satisfy the specified condition continue to be
	evaluated within the loop.  When all points finally fail the condition,
	or have had break applied to them, then the loop is complete.
	There are a few rare cases, such as with
	gridpattern, where it is instead desirable
	for every point which was active when the loop started to remain
	potentially active if any shading point passes the conditional. 
	In these situations, the addition of the "any"
	modifier string after while causes the success/fail state
	at every shading point to be reset (rather than preserved) each time
	through the loop.
	
    
The while "any" construct allows looping on
gridpattern calls until a convergence occurs.  In this mode a
different set of gridpoints will be active during each iteration. So a
typical convergence loop might look like this:
   	while "any" (0 != gridpattern("binaryrefinement", patctx)) {
    	    /* do things on this subset */
   	}
See the gridpattern example
for an illustration.
   
    Limitations
    
      The Shading Language compiler and interpreter in
      PhotoRealistic RenderMan has certain limitations which
      must be taken into consideration when shaders are written for
      PhotoRealistic RenderMan. If these are not understood,
      shaders which seem to compile correctly will produce incorrect
      results.
    
    Area Functions Inside Conditionals
    
      One shouldn't use any area or neighborhood-sensitive functions
      inside conditional blocks whose conditional test depends upon
      varying expressions.  The sensitive Shading Language
      functions are: texture(), environment(), bump(), shadow(),
      Deriv(), Du(), Dv(), area(), calculatenormal().  These
      functions depend on comparing various values at more than one
      point on the surface. A conditional will partition the object
      being shaded into two sets, those that passed the conditional
      and those that did not. Values are undefined in places where the
      conditional failed, but they are still referenced by their
      neighbors who did pass the conditional. This causes the
      comparisons to be undefined, and leads to visible artifacts. As
      a result, the following:
    
    
if (u < 0.5) {
        s0 = u * 2;
        Ci = texture("foo", s0, t);
} else {
        s0 = (u - 0.5) * 2;
        s0 = s0 * s0;
        Ci = texture("foo", s0, t);
}
    
      should be coded as:
    
    
if (u < 0.5) {
        s0 = u * 2;
} else {
        s0 = (u - 0.5) * 2;
        s0 = s0 * s0;
}
Ci = texture("foo", s0, t);
    
      This evaluates the texture access outside the conditional,
      allowing it to filter correctly.
    
    
      Note that this is not a problem for conditional blocks whose
      conditional test depends upon a uniform expression,
      since the object cannot be partitioned into two sets by a
      uniform expression, by definition.
    
     Broad Solar Lights
    
      The solar block is used by distantlight to
      specify a light which is emitted from infinity along a
      particular axis direction. In this use, the solar block
      takes two arguments, the axis vector A, and
      0.0, which is the angular width of the emission
      cone. The RenderMan specification refers to the fact that this
      cone can have non-zero width, and specifically mentions the use
      of solar with no arguments to write an environment
      mapping light source using a 360 degree cone.
    
    
      PhotoRealistic RenderMan does support solar cones of
      any angular width, including the zero-argument omnidirectional
      case. The meaning of a non-zero width solar cone is extremely
      confusing to explain. Nonetheless, imagine a distant light
      source which is willing to emit light in any of a range of
      directions (not just down its axis vector), and merely needs the
      renderer to tell it which direction is pointed most favorably
      toward the specular highlight of surface. Another way of
      thinking of it is a large area light source, located at
      infinity, where each point on the area light is emitting a
      little spotlight.
    
    
      The most obvious example is an environment-mapping light. The
      light wants to cast the environment texture map like a slide
      projector from infinity, and just needs to know which pixel on
      the map will reflect back into the camera. The pixel to choose
      is based entirely on the reflection direction R of the
      surface; the light itself is willing to send light in any
      direction as needed.
    
    
      The second example is a diffuse skylight, where light is
      arriving on the surface from everywhere above it, and would like
      to be colored by all of it (radiosity-style). In this case, the
      solar light cone would be a hemisphere pointed down.
    
    
      At this time, PhotoRealistic RenderMan will not
      point-sample the area light source, but it will attempt to find
      the most favorable direction by considering the size of the
      solar cone and the surface's reflection direction. The light
      direction vector L inside the solar block will
      be this direction. In the specific case of an omnidirectional
      light, this L will be exactly equal to -R. For
      narrower solar cones, it will be some vector between -R
      and A, such that it falls within both cones and is
      somewhat central to the intersection of the cones.
    
    
      Here is a light source which casts an environment map onto a
      surface. Notice the use of the __nondiffuse flag to put
      the environment only in the specular component (since
      environment maps are really specular reflections of the
      worldsphere).
    
    
light envir ( string mapname = ""; float __nondiffuse = 1; ) {
    solar() {
	Cl = environment(mapname, vtransform("world", -L));
    }
}
    
      Note: Some surface shaders use non-standard reflection
      directions for their specular highlights. For example, some
      anisotropic shaders (such as brushedmetal) have
      multiple specular highlights, none of them in the "normal"
      place.  solar's guess about which direction is the most
      favorable direction will be wrong in these cases.
    
    
   
      
    
      
	  
	     
	       
		  Pixar Animation Studios 
		
		  (510) 752-3000 (voice)   
		  (510) 752-3151 (fax)   
		  Copyright © 1996-
Pixar. All rights reserved. 
		  RenderMan® is a registered trademark of Pixar.