PhotoRealistic RenderMan 3.8
Release Notes

Pixar
September, 1998

Introduction

These release notes describe significant changes and enhancements to the RenderMan Toolkit for the 3.8 release (and the 3.8C bug fix release) over the 3.7 release. In successive sections, we cover

Subdivision Surfaces

PRMan now includes support for Catmull-Clark subdivision surfaces. Ordinary cubic B-spline surfaces are rectangular grids of tensor-product patches. Subdivision surfaces generalize these to control grids with arbitrary connectivity, so that when you want a five-sided patch at a shoulder joint you can get it, and when you need more resolution near a character's eyes and mouth you can have it without being required to increase the resolution all across the rows and columns of the control mesh. PRMan's subdivision surfaces are extended to support creases, either infinitely sharp (C0 but not C1) or rounded in a controllable way.

The RI/RIB interface for subdivision surfaces looks a lot like RiPointsPolygon, with additional parameters to permit the specification of semisharp creases, integer datatypes attached to vertices and edges, and other enhancements.

RiSubdivisionMesh(RtToken scheme,
		RtInt nfaces, RtInt nvertices[], RtInt vertices[],
		RtInt ntags, RtToken tags[], RtInt nargs[],
		RtInt intargs[], RtFloat floatargs[],
		parameterlist)

RiSubdivisionMesh defines a subdivision mesh or surface obeying the subdivision scheme specified by scheme. The token scheme is currently limited to "catmull-clark", specifying the Catmull-Clark subdivision method. The subdivision mesh is made up of nfaces faces. The array nvertices, of length nfaces, contains the number of vertices in each face. The array vertices contains, for each face vertex, an index into the vertex primitive variable arrays. The array vertices has a length equal to the sum of all the values in the array nvertices. All the arrays are 0-based.

A component is either a face, a vertex, or a chain of edges. Components of the subdivision mesh may be tagged to have various user-defined properties. The token array tags, of length ntags, identifies these tags. Each tag has zero or more integer arguments, and zero or more floating-point arguments. The number of arguments provided with each tag is specified by the array nargs, which has a length of ntags times two. For each tag, nargs contains an integer specifying the number of integer operands found in the array intargs, followed by an integer specifying the number of floating-point operands found in the array floatargs. Thus, the length of intargs is equal to the sum of all the even-numbered elements of the array nargs. The length of floatargs is equal to the sum of all the odd-numbered elements of the array nargs.

Several tags are currently defined. The "crease" tag specifies that a certain chain of edges should be a crease. This tag has n integer arguments specifying a chain of vertices that make up the crease, and one floating-point argument giving the crease's sharpness. A crease with sharpness s is subdivided using the sharp subdivision mask for the first s subdivision steps. If s is RI_INFINITY, the edge uses the sharp mask forever and the surface will be C0 but not C1 across the edge. Each sequential pair of vertices in a crease must be the endpoints of an edge of the subdivision mesh. A mesh may have any number of independent "crease" tags.

The "corner" tag may be used to mark certain vertices. This tag has n integer arguments containing the vertex numbers of the corners and either one or n floating-point arguments that specify the sharpness of the corners. A corner with sharpness s will remain fixed for the first s subdivision steps. If s is RI_INFINITY, the corner will stay fixed forever; the surface will interpolate the vertex in a C0 but not C1 manner.

The "interpolateboundary" tag specifies that the subdivision mesh should interpolate all boundary faces to their edges. This tag has zero integer arguments and zero floating-point arguments. It has the same effect as specifying that all the boundary edge-chains are sharp creases and that boundary vertices with exactly two incident edges are sharp corners.

The "hole" tag specifies that certain faces are holes. This tag has n integer arguments, one for each face that is a hole, and zero floating-point arguments. Each face is specified by its index in the nvertices array.

parameterlist is a list of token-array pairs where each token is one of the standard geometric primitive variables or a variable that has been defined with RiDeclare. The parameter list must include at least position ("P") information. If a primitive variable is varying, the array contains n elements of the type corresponding to the token. The number n is equal to the maximum value in the array vertices plus one. If the variable is uniform, the array contains nfaces elements of the associated type.

The RIB Binding is

SubdivisionMesh scheme
	nvertices vertices
	tags nargs intargs floatargs
	parameterlist
The number of faces is determined implicitly by the length of the nvertices array. The number of tags is determined implicitly by the length of the tags array, and must match the value as determined from the nargs array.

New Display System

Previously PRMan only allowed color, opacity and depth information to be written to displays. People who wanted to extract other information from scenes, say to provide inputs for non-photorealistic post-processes, were required to run multiple PRMan passes with different shaders that computed the needed values and assigned them to Ci.

In release 3.8, the display subsystem is completely rewritten to allow any number of values computed in a shader to be written into files or framebuffers, all in a single rendering pass. The new display subsystem has a new display-driver API using dynamic shared object files (DSOs) to implement drivers. Driver-writing for the new API is covered in the rewritten Display Driver Guide.

The Display RIB command has been modified to allow for arbitrary specification of the output variable. See the section on arbitrary output variables below for more details.

Since display drivers are now loaded dynamically, PRMan looks in the rendermn.ini file to determine where to find them.

Suppose rendermn.ini contains the lines

and suppose a RIB file specifies The following sequence of actions takes place:

Initially, the driver name "file" is taken from the Display statement. With that in hand, PRMan searches for /displaytype/file in rendermn.ini and, on finding the value tiff, rewrites the driver name from "file" to "tiff". Similarly, had the Display command specified "framebuffer", PRMan would have looked for /displaytype/framebuffer and rewritten the driver name to be the contents of the environment variable $RMANFB or "myfb" if $RMANFB were not set.

Having looked up the display type, PRMan searches for a driver command by examining the /display/tiff line. The command is internal, which indicates that the driver is in a DSO using the new display driver protocols. Had the display type instead been "myfb", the driver command would have been /usr/me/bin/mydspyserver, and PRMan would have run this command and communicated with it using the old (pre release 3.8) display protocols.

With the knowledge that it needs to use the new display protocols, PRMan now looks for a /display/dso/tiff entry. If one were present, it would give the pathname of the DSO. Since it's missing, PRMan instead substitutes the driver name tiff for the characters %s in the string on the /display/dsomapping line, creating d_tiff.so as the name of the driver DSO. It then searches the paths specified by /display/standarddsopath, and if not found there, /display/dsopath.

The renderer now accepts searchpaths for display drivers, just as it already did for shaders and textures.

The RIB syntax is:

where path is a colon separated list of directories. As with other searchpaths, the special symbols ? and @ refer to "the previous path" and "the standard path" respectively.

Multi-segment Motion Blur

Previous versions of PRMan handled motion-blur by linearly interpolating the position of primitives from shutter open to shutter close. In situations where an object is rotating rapidly, this approximation is often obviously incorrect.

PRMan 3.8 fixes this limitation by permitting a piecewise linear interpolation of positions within a single frame. The RIB file syntax is exactly as described in the RenderMan Specification. Each motion-block specifies a sequence of times, and there is one version of the transformation (or object specification) that corresponds to each time value. The shutter specifies the range of these times will appear in the frame, and the motion is piecewise linearly interpolated between the knots at the given times.

For example:

describes a ball that is moving around violently in 3-D.

As with previous versions of motion-blur, transformations and object deformations are both legal inside the motion block. There is an arbitrary limit of no more that 6 unique time values specified throughout in the RIB file as a whole. That is, you can use up to 6 time values in any motion-block, as long as it's always the same 6 times.

The shutter open and close times are not required to match any of the specified time values, and if they do not, the objects and transformations will be correctly clipped to the shutter's range. For example, the shutter in the above example could run from 0.1 to 0.9, and the "right thing" would happen. If the shutter extends outside the range specified in the motion block, two things happen. Transformations are clamped to their endpoints. In the example above, the ball is considered stationary at (0,10,0) prior to time 0.0, and stationary again at (0,0,0) after time 1.0. Geometry, on the other hand, is non-existent outside of the motion-block's time range. Therefore, one may have a geometry appear in the middle of a frame, or similarly vanish intraframe.

Rotations are not divided into segments automatically. Rotations that need more temporal resolution must be specified by the model (or the RIB generation program) as follows:

In the current implementation, shading of each segment of the object's motion is calculated independently, at the time value that represents the beginning of that segment. However, shading parameters can not yet be interpolated through time. Therefore, any shading differences that are due only to position will be visible on the various segments of the motion path (for example, specular highlight location). Note that shadows are evaluated only at shutter open time.

One-sided Primitives

Normally the renderer currently culls one-sided primitives that are backfacing. A primitive is considered backfacing if the primitive's surface normals all point more than 90 degrees away from the viewing vector. In PRMan version 3.7 and earlier, this culling was not guaranteed to occur. Primitives might not be culled even though they were truly backfacing, and no primitive was ever cut cleanly along the terminator. Thus, transparent one-sided objects may have shown inconsistent or ragged-edged results as parts, but not all, of the backfacing sections were culled. Moreover, there was a culling phase prior to shading that could have had the unexpected effect of culling backfacing geometry that a displacement shader would have subsequently moved into a front-facing orientation.

PRMan 3.8 modifies these behaviors. First, backface culling is guaranteed to occur and to be exact; no transparency artifacts as described above will occur.

Second, the threshhold for backface culling of one-sided primitives prior to shading can be adjusted with the new sides:backfacetolerance attribute. The backface culling tolerance angle is a floating-point number, measured in degrees, which specifies the angle that the primitive must exceed, beyond the “silhouette normal”, before it may be culled prior to shading. The default value is 0 degrees. For example:

	Attribute "sides" "backfacetolerance" [20]
will cause the renderer to not cull backfacing objects until their surface normals point more than 110 degrees away from the viewing vector. Note that this does not affect the fact that by the end of the rendering pipeline, backface culling is exact and occurs at 90 degrees.

Procedural Primitives

In older versions of PRMan, program and DSO names had to be absolute pathnames, and there was no way to specify a different executable depending on which machine-architecture the RIB file was being rendered on. In PRMan 3.8, the renderer will expand the string $ARCH or %ARCH in any procedural primitive program and DSO pathnames, converting it into a string that identifies the machine architecture.

The default architecture names are:

These names can be remapped into other names by placing a line in the rendermn.ini file, for example: These names can be completely overridden using the shell environment variable RMAN_ARCHITECTURE.

A significant bug that made procedural primitives significantly inefficient if they crossed the eye plane has been fixed. Now procedural primitives are never opened during the RIB parsing phase, and will never be called recursively due to eyesplits.

RiProcRunProgram used to require that its program ran in a loop, reading input “description” strings and emitting the results until the renderer signalled that there was no more input. It is now significantly more robust, and will handle programs that read exactly one input string, process it and immediately exit. Also, RiProcRunProgram will no longer hang or core dump if the specified program does not exist or cannot be executed.

RIB Archive Searchpath

The renderer now accepts searchpaths for RIB archive files, just as it already did for shaders and textures. This searchpath is used to expand RIB archive filenames when used in either RiReadArchive or RiProcedural("DelayedReadArchive", ...).

The RIB syntax is:

where path is a colon separated list of directories. As with other searchpaths, the special symbols ? and @ refer to "the previous path" and "the standard path" respectively.

The rendermn.ini file has two new values for archive searchpaths, /archivepath and /standardarchivepath, which both default to "." (just the current directory).

RGBAZ Output Images

The tiff output driver can now handle rgbaz images, by writing the Z data into a separate zfile. If you specify the following RiDisplay command:

This will generate two images, background.tif with the RGBA data in the normal TIFF file, and background.zfile with Z data in a zfile in the same directory. All of the other optional RiDisplay parameterlist values will be applied to the TIFF file in the normal way. There are no parameters to the zfile.

Control Over Printed Statistics

End of frame statistics are controlled by the RIB statement:

	Option "statistics" "endofframe" [level]
The value of level determines how much detail is printed: Level 1 is probably the most useful. The information printed at higher levels, particularly level 3 are for debugging errant renders and can be hard to interpret.

Eyesplits Attribute

The maximum number of times that a primitive may be split into order to resolve camera-plane crossing and ambiguous perspective issues (the "eyesplits" limit), is now an attribute. The existing eyesplits limit option will continue to exist, and will be used for any primitive that does not override that value with the new eyesplits limit attribute.

Option "limits" "eyesplits" [n]
Attribute "limits" "eyesplits" [n]

Objects

RenderMan objects, delimited by RiObjectBegin and RiObjectEnd, have always been extremely limited in that they could only define a flat, attributeless list of geometric primitives, all of the same type.

In PRMan 3.8, most, but not all, of these restrictions are removed, giving objects significantly more utility:

In-line Parameter Declarations

PRMan 3.8 supports a new syntax for parameter declarations. In the past, parameterlist variables needed to be declared in RiDeclare prior to their use. Now, parameters can also be declared `inline.' The syntax for the declaration is identical to the RiDeclare syntax, but the parameter declaration is not added to the global symbol table. Instead, the declaration takes effect for that one parameterlist value only. For example, the code

        Declare "roughness" "uniform float"
        Surface "plastic" "roughness" [0.3]
        Surface "benighted" "Kd" [0.5] "uniform color roughness" [0.1 0.3 1.0]
        Surface "plastic" "roughness" [0.1]
passes a color version of roughness only to the benighted surface.

Displacement Bound Matrix

The displacement-bound attribute is specified by stating a maximal radial displacement distance in a particular coordinate system. In 3.7 and prior releases, the coordinate system is specified by naming a predefined or user-defined coordinate system (as per RiCoordinateSystem).

In version 3.8, the coordinate system may be specified by supplying a transformation matrix. The parameterlist name for this version of the call is "transform", and the value is a single transformation matrix. The semantics of this transformation matrix is parallel to passing a transformation matrix to a shader and transforming a point through it. In other words,

	Attribute "displacementbound"
		"sphere" [2]
		"coordinatesystem" ["world"]
is to
	dispmag = sphereradius * ntransform("world", Nf);
as
	Attribute "displacementbound"
		"sphere" [2]
		"transform" [...mx...]
is to
	dispmag = sphereradius * ntransform(mx, Nf);

Dynamically Loaded User-defined Shadeops

RenderMan Shading Language has always had a rich library of built-in functions (sometimes called "shadeops"). This built-in function library included math operations (sin, sqrt, etc.), vector and matrix operations, coordinate transformations, etc. It has also always been possible to write user-defined functions in Shading Language itself. Improvements to function syntax and semantics and compiler robustness was specifically addressed by the new Shading Language compiler, nshader. However, defining functions in the SL itself has several limitations.

PRMan 3.8 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 Adding C Functions to Shading Language with DSOs.

Light Categories

PRMan 3.8 introduces support for “light categories”. Previously all light source shaders attached to an object were evaluated simultaneously whenever a shader requested light values by calling diffuse, for example, or in illuminance loops. There was no mechanism for executing a single light source shader at a time. PRMan 3.8 allows lights to be tagged with a set of category identifiers, and illuminance statements to request evaluation of only those shaders that match particular categories. Other light shaders will not be evaluated until their categories are requested.

Light shaders can specify the categories to which they belong by declaring a uniform string parameter named __category (this name has two underscores), whose value is a comma-separated list of categories into which the light shader falls. For example,

        lightsource uvglow (
		float intensity = 0.5;
		output varying color uvcolor = 0;
		uniform string __category = "uv,photonic,Tony") {

                solar(vector "shader" (0,0,1), 0) {
                        Cl = intensity;
                        uv = 1.0;
                }
        }
The value of this parameter may be a compile-time default, or may be specified in the RIB file, but may not be computed by the shader -- the parameter cannot be output.

Other shaders that have illuminance loops may specifically execute, or specifically exclude from execution, lights in any particular category. This is done with an optional string parameter to the illuminance block, which is matched against the categories of each light source. Only light sources that match will be run. If the string value starts with a hyphen, then any matched light sources will be excluded, and all other lights will be run. For example,

        surface foo ( ) {
                color uv = 0;
                illuminance("uv", P) {
                        lightsource("uvcolor", uv);
                }
                illuminance("-uv", P) {
                        Ci += Cl;
                }
        }

Matrix Bugs


In previous versions of PRMan, declaring a shader parameter to be of type matrix, and passing it from the RIB file never worked. Matrix data that was attached to primitives in their vertex variable list were fine, but the ones attached to the shader on the Surface line were bolluxed. This has been fixed in 3.8, and now matrix data works correctly on both.

PRMan had another major bug in the matrix constant construction shadeop. For example, lines of the form

        M = matrix "shader" 1;
generated the inverse of the matrix that was intended. That is to say, M was documented to be and was supposed to be the current-to-shader matrix, but the operator actually returned the inverse of this.

To fix the problem without removing functionality that old shaders may empirically depend on, a new keyword matrixinv has been introduced to have the functionality of the old, broken matrix, and matrix has been adjusted to return the correct forward matrix. N.B.: This change breaks old shaders that use matrix.

New Texture Filters

	shadow(..., "filter", "gaussian")
shadow() calls in the shading language can now specify a gaussian filter for the "percentage-closer" filtering in shadow maps. As with the box filter, increasing the filter width makes shadow edges blurrier, but increases the danger of speckling due to shadow map bias.

 

	texture(..., "filter", "disk")
        texture(..., "filter", "radial-bspline")
texture() calls in the shading language can now specify a disk filter or at radial-bspline filter in addition to the gaussian and box filters. The disk filter is 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. The radial-bspline filter is specifically designed for optimally filtering displacement textures.

On a related note, the "gaussian" texture filter, which used to be truncated at a fixed width, is now windowed using a Blackman-Harris window, so that it goes to zero at the edge of the window and is C1 continuous.

Shadow Map Bias

Previously shadow maps have always contained the minimum depth value calculated from all depth values within the current pixel. The user now has control over the function that computes the output depth value for each pixel. This is controlled by a new Hider option called "depthfilter". You can now select between the minimum, maximum, or average of the pixel depth values to output.

Examples using the jitter hider:

Hider "hidden" "jitter" [0] "depthfilter" "min"
Hider "hidden" "jitter" [0] "depthfilter" "max"
Hider "hidden" "jitter" [0] "depthfilter" "average"

In addition, there is one special version of the depth filter that works a bit differently. For each sample position, it calculates the depth as the midpoint between the object that is closest to the viewpoint and the second closest object. This requires a bit more time than the other techniques, but generates z values that may require less tweaking and biasing. This method was proposed by Andrew Woo of Alias Research in Graphics Gems III , page 338.

This method is specified by the Hider statement:

Hider "hidden" "jitter" [0] "depthfilter" "midpoint"

As an example, here are two shadow maps, the first generated normally, the second generated using the midpoint algorithm. Notice that the ground plane disappears entirely in the midpoint shadow map. In these pixels, there is only the ground plane visible, so it can't possibly shadow any other objects in the scene. This prevents any kind of bias errors for the ground plane; the shadow map would work properly even if the ground were displaced into a bumpy surface.

Depthfilter Minimum
 
Depthfilter Midpoint

Soft Shadows

PRMan 3.8 has an enhanced shadow shadeop supporting a new method of generating 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, 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:

 

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.

New Renderer-State Shadeops

In PRMan 3.8, the shading language adds four new shadeops that provide access to global rendering internal state. In each case, the function is prototypically like the shader variable access functions surface, lightsource, etc. Each function takes a string that is the name of a piece of global data, and a variable to contain the result. The functions return non-zero if the data exists and the variable is of the right type to contain the result, in which case the variable will be filled with the data requested. The functions return zero if any error prevents returning the requested data, including unrecognized requests, unobtainable data and variable type mismatches. Note that the request names are case-sensitive, and correspond exactly to the names of data specified in the RIB Binding of RenderMan. The data that is returned is as would be expected from inspection of the appropriate RenderMan Interface call.

attribute returns data that is part to the primitive's RenderMan Interface attribute state, either from individual RI calls that set attributes or from the RiAttribute call.

option returns data that is part of the image's RenderMan Interface global option state, either from individual RI calls that set options, or from the RiOption call.

textureinfo returns data that describes the format of a texture file.

rendererinfo returns information that describes the renderer itself.

Smooth Derivatives

PRMan 3.8 supports smooth differentials and derivatives in Shading Language. RenderMan's derivatives functions (Du(), Dv(), Deriv()) and surface differentials (du, dv) are fundamental to writing shaders that antialias well. In earlier versions of PRMan, surface differentials have not been continuous across the surface, but instead were uniform float values on an individual grid, and that changed discontinuously from one grid to the next. This could result in subtle filtering artifacts, particularly on large objects viewed in perspective. Starting with version 3.8, PRMan has a new way of computing differentials that is free from grid discontinuities, by using smoothly varying estimates of the optimal size of micropolygons, rather than their exact size. This allows higher-quality antialiasing of shaders. Further, the shading language area functions (texture(), Du(), filterstep(), etc.), that implicitly use these differentials when filtering, benefit immediately from smooth differentials, automatically removing many grid artifacts previously ascribed to these functions.

This automatic smooth derivative behavior can be turned off, reverting to the pre-3.8 behavior, on a shader-by-shader basis using the shader compiler's -nosd flag. The complementary flag -sd turns smooth derivatives on and is the default.

Arbitrary Output Variables

In most renderers, the user is limited to displaying a limited set of outputs (usually the color, the opacity and depth). The 3.8 release of PhotoRealistic Renderman, the user may export arbitrary information from shaders and write them out to separate files or framebuffers, all within a single rendering pass.

The RiDisplay call has been modified to allow for arbitrary specification of the output variable. Previously, RiDisplay statements have been

Display "name" "type" "mode"

where mode is some combination of rgb, a, and z. The mode may now be specified as any shader variable name which has been declared with RiDeclare. Additionally, certain external variables are also legal, namely

 
Name Meaning
P the XYZ coordinates of the surface point
N the normal at the surface point
Ng the geometric normal at the surface point
dPdu, dPdv the tangent vectors to the surface
s, t, u, v the texture coordinate
du, dv the stepsize in u and v
dPdtime the motion vector for the point P
Cs, Os default surface color and opacity
Ci, Oi computed surface color and opacity

The RiDisplay call has also been modified to support multiple simultaneous output files. To indicate that a display should be added to the current list of displays, the first character of its name should be a single ASCII plus sign ('+'). For example, the statements

	Display "foo.tif" "tiff" "rgb"
	Display "+goo.tif" "tiff" "N"

would create two separate output files, the first containing the normal rgb color channels, and the second containing the normals. If an additional Display statement was issued without a leading plus sign, then it resets all the displays and becomes the only active display. The first Display call (the one without a leading plus) must be a previously recognized Display statement: its mode must be a mix of rgb, a, and z. Each additional Display must not contain any of those fields.

If the output mode is not one of the special external variables, the shader must create it as an output variable. For example, the simple shader below:

surface
myplastic( float Ks=.5, Kd=.5, Ka=1, roughness=.1; color specularcolor=1;
	   output varying color foo = 0; output varying float goo = 0;)
{
    normal Nf;
    vector V;
    float invisible ;

    Nf = faceforward( normalize(N), I );
    V = -normalize(I);

    Oi = Os;
    foo = diffuse(Nf) ;
    goo = s ;
    invisible = t ;
    Ci = Os * ( Cs * (Ka*ambient() + Kd*diffuse(Nf)) +
	 	specularcolor * Ks * specular(Nf,V,roughness) );
}

the variables foo and goo may be displayed by in a display since they are defined as output variables by the shader. The variable invisible may not be displayed because it is not defined as an output variable. If a particular variable cannot be found in a shader, the display system merely writes a zero in its place. In the RIB stream, one must be careful to predeclare any shader output variables that are to be used for display prior to the call to RiDisplay.

Some limitations do exist:

More complete documentation, with some application ideas can be found in the application note Using Arbitrary Output Variables in PhotoRealistic Renderman (With Applications)

Miscellaneous Changes

NURBS and Bezier dicing has been rewritten, fixing many small cracks. In addition, a subtle bug in normal vector computation has been fixed.

RiCurve now splits curves by knot insertion.

The size of RiPoints is now specified with the "width" or "constantwidth" parameter rather than "radius". "width" lets you specify the width on a per-point basis; "constantwidth" gives a single width for all points in the "P" array.

There used to be a limit on the number of arguments to a shader. This has been removed.

The shader compiler understands several new options:

The texture subsystem can now read SGI rgb files. Also, txmake has always rescaled odd-sized images to power-of-two sizes. A significant bug that caused loss of precision in this rescaling has been eliminated.

The netrender command now ignores hosts that report having no slots available. The flag -h #host causes netrender to keep retrying host despite it having no slots. Also, -h host:n abbreviates repeating the -h host specification n times.

A nasty bug in netrender that caused failures when using RiCropWindow has been fixed.

The nrmping command now takes a -p flag that causes it to print the number of available slots.

The sho command now

Bug Fixes

The following bugs have been fixed in the 3.8C update release: