Section 1 provides a brief overview of the basic ingredients needed to use the software and attempts to clear up any confusion about the relationship between the RenderMan Interface and all of the different file types and utilities present in PhotoRealistic RenderMan.
Section 2 describes the level of conformance of PhotoRealistic RenderMan to the RenderMan Interface Version 3.1 Specification.
Section 3 describes how to run PhotoRealistic RenderMan, including the preparation of input files.
Section 4 covers the RenderMan Interface options and attributes that are specific to PhotoRealistic RenderMan, as well as other RenderMan Interface extensions implemented in it.
Section 5 describes the features and limitations of the Shading Language as it applies to PhotoRealistic RenderMan.
Section 6 discusses some helpful hints to get you started.
Section 7 discusses how to directly link the renderer to your application.
Finally, in Section 8 there are a few pointers
as to where to go from here.
A scene description is usually supplied to PhotoRealistic RenderMan in a file. This file is created by a modeling system that makes calls to the interface routines specified in the RenderMan Interface. The format of this file is defined by the RenderMan Interface Bytestream protocol, RIB, and can be a mix of ASCII and binary data.
The files and utilities described below, are defined in the Reference Documentation portion of this manual. Refer to that portion of the manual for further details and information.
Because there are two forms of RenderMan, there are also two ways to use PhotoRealistic RenderMan. The renderer can be linked directly into a C program, or it can be run from the command line and given a RIB stream as input. One advantage of the latter method is that it supports a client-server system model, making it easier to distribute rendering among machines. Furthermore, RIB streams can be stored in files, which facilitate rendering at later times or on different systems.
If PhotoRealistic RenderMan is to be run as a separate program, the user must have some way to create a RIB stream. Though it is possible to do this directly (with an editor, for example), we recommend using the RIB client library by linking your program with librib.a. This library links into a C program the same way the rendering library does, but instead of performing the rendering at run-time, it creates a file containing the RIB stream produced by the RenderMan calls in the program.
If, on the other hand, you wish to use the direct rendering capability, link your program with libprman.a. This is necessary if your program relies on two-way communication with the renderer. Note, however, that this produces large executable files.
When the renderer runs, it sends output pixels to a display server, which contains a display device driver for the particular hardware device or file which should receive the pixels. Beginning in version 3.8, display servers can be in the form of dynamically-linked libraries, or DSOs. If you want to use a non-standard frame buffer or image file format, you will have to write and install your own display driver. See the Display Driver Guide for further information.
If you have, through the RenderMan Interface, set the renderer to output to an rgb or rgba image file, the default display driver will output a TIFF file. As with RIB files, there is no naming convention, but we recommend using .tif as a suffix. The renderer also knows how to display images in other file formats, and on the standard color framebuffer for each type of machine.
During rendering, the renderer must be able to find a .slo file for every shader that is used. There is a PhotoRealistic RenderMan dependent RiOption called searchpath that tells the renderer where to look for shader object files. See Section 4.1.11 for details. Configuration files can also control the shader search path. See Section 3.8 for details.
Texture files are created with the utility txmake, which takes image files or zfiles as input. There are various command line options to txmake that specify the type of input and the type of texture file to be created (see Section 3.3 for details). In general, a shadow map is produced from a zfile, a texture map is produced from a TIFF file, and an environment map is produced from either one or six TIFF files, depending on the environment type. Zfiles are produced by the renderer, but input TIFF files can either be produced by the renderer or brought in from some other software (such as a digitizer). Texture files contain a great deal of information and can easily become very large. However texture files are created using various data compression schemes to keep the files from getting too large. The size of the file depends on the data in the input image. Don't be surprised if you use up large amounts of disk space when you try to use txmake on a large image.
There are also RenderMan calls that create texture maps from inside the prman renderer, which is equivalent to calling txmake. Modeling programs which compute and create texture maps on the fly may wish to use these calls, but it is often more appropriate to create texture maps prior to running renderer.
Though there is no enforced naming convention for the different types of texture files, we recommend .tex, .env, and .shd for texture, environment, and shadow maps respectively. If you need to get information about a texture file, there is a command line utility called txinfo that prints out the type, size, and other useful information about a texture file.
Optional capabilities are those features specified in the document that are not required to be supported in all implementations of compatible renderers. The subroutines which would normally implement the interface to these capabilities must exist, but need not do anything. The level of support of an optional capability by a specific renderer implementation can be divided into three categories: fully implemented, in which the renderer supplies the features in all of their generality; incompletely implemented, in which the renderer supports a subset of the feature, but has certain restrictions on the parameter values which can be handled correctly; and unimplemented, in which the renderer has no support for the feature. The RenderMan Interface Version 3.1 document specifies what the default action of a renderer should be if unimplemented capabilities are requested.
The following capabilities correspond to those discussed in Section 1 of the RenderMan Interface Version 3.1 specification (pages 5 and 6).
For example:
Shutter [0.0 1.0]
...
MotionBegin [0.0 0.25 0.75 1.0]
Translate 0.0 10.0 0.0
Translate 10.0 0.0 0.0
Translate 0.0 0.0 20.0
Translate 0.0 0.0 0.0
MotionEnd
Sphere 1 -1 1 360
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:
Shutter [0.0 1.0]
...
MotionBegin [0.0 0.25 0.50 0.75 1.0]
Rotate 0.0 0.0 1.0 0.0
Rotate 10.0 0.0 1.0 0.0
Rotate 20.0 0.0 1.0 0.0
Rotate 30.0 0.0 1.0 0.0
Rotate 40.0 0.0 1.0 0.0
MotionEnd
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. Users should be aware that large amounts of blur can significantly increase both rendering time and memory usage, and should refer to Section 6.5 for usage notes.
PhotoRealistic RenderMan supports compressed RIB files, in either binary or ascii forms. See Section 4.1.12 for details on controlling the format of RIB files.
One tool that can be useful in dealing with RIB files is the program catrib. Catrib can be used to convert between binary and ASCII formats, and as a means of transmitting RIB data to a rendering server. For example, if the file binary.rib contains binary RIB data, then the following will create an ASCII version of this data in the file ascii.rib:
catrib -ascii binary.rib > ascii.ribBy default the output generated by catrib is sent to the standard output. Thus the following might be used to compare the ASCII output to a previously created file:
catrib -ascii binary.rib | diff - oldascii.ribThe format of the output generated by catrib can be specified as binary or ASCII by using the -binary and -ascii options, respectively. Alternatively the environment variable RIFORMAT can be set to "binary" or "ascii". Beware, however, that this environment variable is also used by the client RIB library that applications use to generate RIB data. Thus setting this environment variable may also affect the operation of your modeling system.
Each shader must be compiled before it can be used by PhotoRealistic RenderMan in the rendering process. This is done with the shader program. For example, to compile the constant shader into a shading file suitable for use by PhotoRealistic RenderMan the following command would be used:
shader constant.slEach shader must be compiled into a separate file and the file that holds the compiled object must have a name that corresponds to the name of the enclosed shader. For example, the file constant.slo holds the shader named constant. A file named foo.sl might contain the shader surface marble. Its corresponding output file (created by the compiler) would be marble.slo and not foo.slo. This file naming convention is automatically enforced by the shader compiler; you need only be aware of this if you have source files whose names do not match the name of the enclosed shader.
The standard shaders defined in the RenderMan Interface specification are located in the directory /usr/local/prman/lib/shaders. (See Table 1.) PhotoRealistic RenderMan automatically searches this directory to find shaders that are referenced in a scene description. Any user-defined shaders must be referenced either through absolute path names (i.e., path names with a leading slash) or by using the PhotoRealistic RenderMan-specific searchpath option. See Section 3.8 and Section 4.1.11 for details about search paths.
| Shader | Description | |
|---|---|---|
| ambientlight | ambient light source | |
| constant | constant-color surface without light effects | |
| distantlight | light source at infinity | |
| defaultsurface | the default surface shader | |
| depthcue | depth cueing atmosphere shader | |
| fog | foggy atmosphere shader | |
| matte | purely diffuse color surface | |
| metal | shiny metallic surface | |
| null | general null shader | |
| plastic | plastic-like surface | |
| spotlight | conical light source with exponential fall-off |
txmake wood.tif wood.texA manual page for this program is provided in the PhotoRealistic RenderMan Reference Documentation section of this volume. This is a useful alternative to the RiMakeTexture routine. In either case, texture files must be created before they are used.
The source picture files that txmake and RiMakeTexture use to create texture maps can be in TIFF, Alias or Pixar's picio format. Source images for texture maps or environment maps can be any resolution; however, the texture making process causes these files to be resized into various other resolutions for fast filtered access, each being some even power of two resolution in both width and height. The user has some control of this filtering process with the -resize option of txmake (or equivalently, the resize parameter of RiMakeTexture). By default, the file is first resized up to the next highest power of two resolution in each direction, using a high-quality Catmull-Rom filter. Other possibilities include resize down to the next lower power of two resolution, and round the resolution to the closest power of two. In all three cases, information about the original image aspect ratio is retained within the file so that the texture is not stretched when it is applied to simple surfaces. (The behavior of previous releases of PhotoRealistic RenderMan to fill images with black pixels, rather than resize them, can be requested with resize value of none.)
Source images for shadow depth maps must be power of two resolution, as this resizing functionality is not implemented for shadow depth maps. If the source depth files do not have an even power of two resolution, the shadow maps will not produce correct shadows.
Texture file names should either be given as absolute path names or through the PhotoRealistic RenderMan-specific searchpath option. See Section 3.8 and Section 4.1.11 for details about search paths.
PhotoRealistic RenderMan provides two utility programs (in addition to txmake) to manipulate texture files. Manual pages for these programs are provided in the PhotoRealistic RenderMan Reference Documentation. The programs are: sho, used to display texture images using the PhotoRealistic RenderMan display server, and txinfo, used to print descriptive information about a texture file.
render model.ribIt is often convenient to store options, camera specification and the world block in separate files. The render script can be given multiple file names and it will process them in the order given:
render options.rib camera.rib world.rib
RiDisplay("filename", "driver", ...);
Where driver is the name of the display driver. The driver may or
may not use the filename argument. When output is directed to a
file, the name of the file is the name specified in the RiDisplay
command. If the file name is not an absolute path name, the file is created
in the directory in which rendering is performed.
RGBA, RGB, or single channel (R) pixels can be generated with the precision selected by the appropriate RiQuantize request. For example, to output 8-bit RGB data in a file named foo.tif:
RiQuantize(RI_RGBA, 255, 0, 255, .5);
RiDisplay("foo.tif", RI_FILE, RI_RGB, RI_NULL);
Beginning in version 3.8, the users are not limited to displaying rgba or z but can arrange to have arbitrary variables displayed from shading calculations. For instance, to display the shader variable N, one can issue the Display call:
RiDisplay("+filename", "driver", "N", ...);
The ASCII plus sign indicates that this display is in addition to the normal display. The mode is set to N, indicating the normal is to be output. The mode may in fact be any external variable, or any variable defined as an output variable by a shader. If a shader does not define such a variable, the default value of zero is output.
The RiQuantize call has also been extended. By default, all extra output variables are unquantized, and sent to the display system as floats. If we wished to quantize the normals listed above, we could say:
RiDisplay("+normal.tif", RI_FILE, "N", RI_NULL);
RiQuantize("N", 255, 0, 255, .5);
which would quantize all normals to the range 0 to 255.
More complete documentation, with some application ideas can be found in the application note Using Arbitrary Output Variables in PhotoRealistic Renderman With Applications
Other drivers may be written and/or installed by users. See the Display Driver Guide for details. See Section 4.1.10 for more options that can be specified with RiDisplay.
The initial configuration file is rendermn.ini in the directory /usr/local/prman/etc (or ${RMANTREE}/etc, if the RMANTREE environment variable is set, see below). After the initial configuration file has been scanned, additional configuration files will be scanned and the default values set therein will override any values set in the initial configuration file. Additional configuration files are searched for as rendermn.ini in both the directory defined by the environment HOME and in the current directory, in that order. (The file in the HOME directory can optionally have a leading "." to make it a hidden file.)
The configuration file format is a set of lines containing strings. The first string on the line is the name of the default and the rest of the line specify its default value. Environment variables may be referenced inside the configuration file using the following special syntax:
${environment-variable-name}
Undefined environment variables default to the empty string, except for
${RMANTREE} which defaults to /usr/local/prman. Lines beginning
with a # are ignored. The following is a list of the defaults that can
be set in configuration files which are relevant to PhotoRealistic RenderMan.
Other programs, such as Vector RenderMan
and the various display drivers also read defaults from this file, and
those defaults are documented in the Reference Documentation.
RiOption("searchpath", "shader", (RtPointer)&spath, RI_NULL);
except that the configuration file changes the search path before any shaders
(including defaultsurface) are loaded. See Section
4.1.11 for details of the path format.
RiOption("searchpath", "texture", (RtPointer)&tpath, RI_NULL);
See Section 4.1.11 for details of the path format.
RiOption("limits", "bucketsize", (RtPointer)&bs, RI_NULL);
See Section 4.1.2 for more details.
RiOption("limits", "gridsize", (RtPointer)&gs, RI_NULL);
See Section 4.1.3 for more details.
RiOption("limits", "texturememory", (RtPointer)&tm, RI_NULL);
See Section 4.1.4 for more details.
| /displaytype/file | tiff | |
| /display/tiff | internal | |
| /display/tiff/compression | lzw | |
| /display/tiff/xres | 640 | |
| /display/tiff/yres | 480 | |
| /display/tiff/par | 1 | |
| /errorpath | ${RMANTREE}/etc/messages | |
| /dspyserver | ${RMANTREE}/etc/dspyserver | |
| /licensefile | ${RMANTREE}/etc/license.dat | |
| /standardshaderpath | ${RMANTREE}/lib/shaders | |
| /standardtexturepath | ${RMANTREE}/lib/textures | |
| /shaderpath | .:@ | |
| /texturepath | .:@ | |
| /prman/bucketsize | 12 12 | |
| /prman/gridsize | 56 | |
| /prman/texturememory | 8 | |
| /prman/shadingrate | 1 |
| RIB | Defaults | |
|---|---|---|
| Imager "name" | - none - | |
| Option "limits" "bucketsize" [a b] | [16 16] | |
| Option "limits" "gridsize" [n] | [256] | |
| Option "limits" "texturememory" [n] | [2048] | |
| Option "limits" "zthreshold" [x x x] | [1.0 1.0 1.0] | |
| Option "limits" "othreshold" [x x x] | [0.996 0.996 0.996] | |
| Option "limits" "extremedisplacement" [n] | [0] (disabled) | |
| Option "limits" "eyesplits" [n] | [10] | |
| Option "shadow" "bias" [x] | [0.225] | |
| Hider "hidden" "jitter" [flag] | [1] | |
| Hider "pdisc" [flag] | [0] | |
| Display name,type,mode "merge" [flag] | [0] | |
| Display name,type,mode "origin" [a b] | [0 0] | |
| Display name,type,mode "resolution" ["s"] | - none - | |
| Display name,type,mode "resolutionunit" [n m] | - none - | |
| Display name,"TIFF",mode "compression" ["s"] | ["lzw"] | |
| Option "searchpath" "shader" ["s"] | [".:/usr/local/prman/lib/shaders"] | |
| Option "searchpath" "texture" ["s"] | [".:/usr/local/prman/lib/textures"] | |
| Option "searchpath" "vfxmaster" ["s"] | [".:/usr/local/prman/look/masters"] | |
| Option "searchpath" "vfxinstance" ["s"] | [".:/usr/local/prman/look/instances"] | |
| Option "searchpath" "display" ["s"] | [".:/usr/local/prman/etc"] | |
| Option "searchpath" "archive" ["s"] | ["."] | |
| Option "searchpath" "procedural" ["s"] | ["."] | |
| Option "searchpath" "servershader" ["s"] | [".:/usr/local/prman/lib/shaders"] | |
| Option "searchpath" "servertexture" ["s"] | [".:/usr/local/prman/lib/textures"] | |
| Option "searchpath" "servervfxmaster" ["s"] | [".:/usr/local/prman/look/masters"] | |
| Option "searchpath" "servervfxinstance" ["s"] | [".:/usr/local/prman/look/instances"] | |
| Option "searchpath" "serverdisplay" ["s"] | [".:/usr/local/prman/etc"] | |
| Option "searchpath" "serverarchive" ["s"] | ["."] | |
| Option "rib" "format" ["s"] | ["ascii"] | |
| Attribute "dice" "binary" [flag] | [0] | |
| Attribute "displacementbound" "sphere" [x] | [0.0] | |
| "coordinatesystem" ["s"] | ["object"] | |
| Attribute "identifier" "name" ["s"] | - none - | |
| Attribute "trimcurve" "sense" ["s"] | ["inside"] | |
| GeometricApproximation "motionfactor" [v] | [0.0] | |
| Option "texture" "enable gaussian" [v] | [1.0] | |
| Option "texture" "enable lerp" [v] | [1.0] | |
| Attribute "derivatives" "centered" ["x"] | [1.0] | |
| Attribute "stitch" "enable" ["x"] | [1.0] |
RiImager("clamptoalpha", RI_NULL);
RtColor bg = {0.4, 0.4, 1.0};
RiImager("background", "background", (RtPointer)bg, RI_NULL);
RtInt bs[2] = {12, 12};
RiOption("limits", "bucketsize", (RtPointer)bs, RI_NULL);
RtInt gs = 36;
RiOption("limits", "gridsize", (RtPointer)&gs, RI_NULL);
RtInt tm = 8192;
RiOption("limits", "texturememory", (RtPointer)&tm, RI_NULL);
RtColor thres = {0.30, 0.30, 0.30};
RtOption("limits", "zthreshold", (RtPointer)thres, RI_NULL);
RtColor thres = {0.995, 0.995, 0.995};
RtOption("limits", "othreshold", (RtPointer)thres, RI_NULL);
The opacity threshold is {0.996, 0.996, 0.996} by default.
Extreme displacement encountered (WARNING)is generated. The maximum permissible displacement before the special procedure is invoked is measured in vertical scanlines. If this value is increased, larger displacements are permitted to use memory rather than incur the additional computation. If this value is decreased, memory usage is minimized even for less severe displacements. The default for this value is 32 scanlines, and can be changed with the following option:
RtInt ed = 24;
RiOption("limits", "extremedisplacement", (RtPointer)&ed, RI_NULL);
R56001 Primitive "<unnamed>" will not split at camera plane (WARNING)is generated. The failure detection threshold defaults to 10, but can be changed (usually to some smaller number in an attempt to reduce time and memory usage) with the following option:
RtInt es = 5;
RiOption("limits", "eyesplits", (RtPointer)&es, RI_NULL);
Beginning in release 3.8, it is possible to set the eyesplits to different
values for different objects by using the eyesplits Attribute.
RtInt es = 5;
RiAttribute("limits", "eyesplits", (RtPointer)&es, RI_NULL);
RtFloat bias0 = 0.35;
RtOption("shadow", "bias", (RtPointer)&bias, RI_NULL);
Note that this bias value can be overridden by a parameterlist value supplied
in the shadow
call of the shader.
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"
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. For more details, see the Application Note on soft shadows.
The first, jitter, enables/disables stochastic sampling. Stochastic sampling should be enabled whenever motion blur or depth-of-field is being used, and in general improves the quality of antialiasing at a small cost in speed. For best results, the jitter option should be disabled when rendering shadow map values. This option is enabled by default, but can be disabled by:
RtInt flag = 0;
RiHider("hidden", "jitter", (RtPointer)&flag, RI_NULL);
The second, pdisc, enables/disables an alternate stochastic sampling
scheme. This scheme often works better than the usual jitter option,
with some limitations. The first limitation that the number of samples
across a bucket (bucketsize x or y times pixel samples x or y) should be
a power of two or at least a multiple of a high power of two. If this is
not followed, the image quality can be greatly reduced. Some combinations
of bucketsize/pixel samples will not work at all and will produce an error
message. If this happens, either modify the bucketsize/pixel samples or
use the jitter option instead. The second limitation is that pdisc
does not work properly when using parallelism in network rendering. This
option is disabled by default, but can be enabled by:
RtInt flag = 1;
RiHider("hidden", "pdisc", (RtPointer)&flag, RI_NULL);
The origin of the output window on a frame buffer device can be set using the display origin option. For example, to place the origin of the output window at the point (512,384):
RtInt o[2] = {512, 384};
RiDisplay("name", "framebuffer", "rgba",
"origin", (RtPointer)o, RI_NULL);
Frame buffers can be configured to merge the generated image over
an existing image with the display merge option:
RtInt flag = 1;
RiDisplay("name", "framebuffer", "rgba",
"merge", (RtPointer)&flag, RI_NULL);
The merge option works only if the selected display driver supports it.
Some file formats (e.g., TIFF, Postscript) support the concept of device resolution, meaning how many pixels appear per physical unit of measure (e.g., dots per inch). Two display options provide a way to document these values into files generated by PhotoRealistic RenderMan. A string specifying the physical unit of resolution can be set with the resolutionunit option. A pair of integers specifying the number of pixels per resolution unit in width and height can be set with the resolution option. For example, to set the resolution at 72 dpi:
RtString ru[1] = "inch";
RtInt r[2] = {72, 72};
RiDisplay("name", "TIFF", "rgba",
"resolution", (RtPointer)r,
"resolutionunit", (RtPointer)ru, RI_NULL);
Currently, the TIFF file driver considers both resolutionunit,
which must be "inch" or "centimeter", and both resolution
values. The PICT and Postscript drivers only consider the first resolution
value, as images in these formats must have the same value in both directions,
and implicitly assume inches as the resolution unit.
The TIFF driver also accepts an option to set the compression type, which may be "lzw" (the default), "packbits", "zip", "pixarlog", or "none":
RtString cmp[1] = "none";
RiDisplay("name", "TIFF", "rgba",
"compression", (RtPointer)cmp, RI_NULL );
Custom display drivers may also accept other display options, but they
must be declared with RiDeclare before RiDisplay can
accept them and pass them through to the custom driver.
Special formatting can be done on the filename parameter to RiDisplay. The "#" character is recognized as a special lead-in character in file names. The action taken depends on the character after the "#".
RiFrameBegin(15);
RiDisplay("test#f.#d", "tiff", ...);
Produces the file name: "test015.tiff".
RtString tpath[] = { ".:/usr/me/ri/images" },
spath[] = { ".::/usr/me/ri" },
dpath[] = { ".::/usr/me/ri/dspy" };
RiOption("searchpath", "shader", (RtPointer)spath,
"texture", (RtPointer)tpath,
"vfxmaster", (RtPointer)spath,
"vfxinstance", (RtPointer)spath,
"archive", (RtPointer)spath,
"display", (RtPointer)dpath,
"procedural", (RtPointer)spath,
RI_NULL);
The valid search paths are:
RtString servspath[] = { ".:/usr/serverstuff/shaders:@" },
locspath[] = { ".:/usr/localstuff/shaders:@" };
RiOption("searchpath", "servershader", (RtPointer)servspath,
"shader", (RtPointer)locspath,
RI_NULL);
RtFloat off = 0.0;
RiOption("texture", "enable gaussian", (RtPointer)&off,
"enable lerp", (RtPointer)&off,
RI_NULL);
RtString format[1] = {"ascii"};
RiOption("rib", "format", (RtPointer)format, RI_NULL);
or binary output by:
RtString format[1] = {"binary"};
RiOption("rib", "format", (RtPointer)format, RI_NULL);
The RiBegin call can be used to specify a specific RIB output
file, as in:
RiBegin("foo.rib");
If RiBegin is not used to specify a file name, and RISERVER
is not defined (see Section 3.8), the standard
output will be used.
The compression format is derived from the freely available libzip.a library and is compatible with the GNU compression program gzip. You can tell the RIB client library to output compressed RIB by calling RiOption before the call to RiBegin:
RtString str = "gzip";
RiOption("rib", "compression", &str, RI_NULL);
Or by setting the environment variable RICOMPRESSION to gzip:
setenv RICOMPRESSION gzip
End of frame statistics are controlled by the RIB statement:
Option "statistics" "endofframe" [level]The value of level determines how much detail is printed:
RtInt flag = 1;
RiAttribute("dice", "binary", (RtPointer)&flag, RI_NULL);
The coordinate system identified can be:
RtString c[1] = "world";
RtFloat d = 3.5;
RiAttribute("displacementbound", "coordinatesystem", (RtPointer)c,
"sphere", (RtPointer)&d, RI_NULL);
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);
RtString name[1] = { "Gigi" };
RiAttribute("identifier", "name", (RtPointer)name, RI_NULL);
All defined primitives will have this name until the graphics stack is popped (with RiAttributeEnd) or another such RiAttribute call is made. The error message in the example in Section 4.1.7 would then contain a reference to a specific primitive name instead of the mysterious <unnamed>.
RtString sense[1] = "outside";
RiAttribute("trimcurve", "sense", (RtPointer) sense, RI_NULL);
The Pixar Looks example program in the /usr/local/prman/examples
directory uses this technique.
RiGeometricApproximation("motionfactor", (RtFloat) 1.0);
will cause the renderer to check the length of the motion blur on the screen
for all motion blurred objects and if the distance is large, raise the
effective shading rate value of the blurred objects. Since the objects
will be blurred across the screen, fine shading detail would be lost anyway.
This can save large amounts of processing if many objects in the scene
have large blurs. A motionfactor factor value of 0.0
will turn this feature off. Values greater than 1.0 will cause
motion blurred objects to have their effective shading rate raised even
higher. According to the RenderMan Interface Version 3.1 Specification
RiGeometricApproximation specifies an attribute and as such, motionfactor
should be scoped within the current RiAttributeBegin-RiAttributeEnd
block. In the current implementation, motionfactor is not properly
scoped as an attribute, hence it should always be specified outside of
the RiWorldBegin-RiWorldEnd block.
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.
Starting in PRMan 3.9, derivatives and normals are calculated using a new technique which will eliminate or reduce several shading artifacts.
The new technique will change surface normals slightly, and may give bumpy surfaces a softer appearance.
Note: These changes only take effect when smooth shading is enabled (via ShadingInterpolation "smooth"). When constant shading is used (the default setting), derivatives and normals are unchanged from previous releases. Smooth shading and centered derivatives are highly recommended in order to minimize rendering artifacts.
If desired, centered derivatives can be turned off as follows:
Attribute "derivatives" "centered" [0]
Starting in PRMan 3.9, the renderer automatically prevents cracks within single primitives, even when large displacements are used. This feature has been implemented for all surface types except polygons and implicits. It is controlled by the following attribute (turned on by default):
Attribute "stitch" "enable" [1]
Cracks may still occur between separate primitives (for example, between two adjacent bicubic patches). As in previous releases, such cracks may be reduced by turning on binary dicing:
Attribute "dice" "binary" [1]
The declaration storage class vertex, described in the Specification as only available in the RIB binding, is available in the C binding as well. This means that the parameter lists of geometric primitives can contain arbitrary user-parameters of storage class vertex (the Specification mentions only the geometric position parameters "P", "Pw" and "Pz" as being of storage class vertex). Such parameters will have the same number of values on any primitive as the vertex position parameters. Such parameters appear to the Shading Language in the same declaration class as varying shader parameters, however, their values will be interpolated using the same basis as the position parameter of the primitive is interpolated with (whereas normal varying parameters are bilinearly interpolated in parametric space).
A new declaration storage class constant has been defined, and requires exactly one data value for each RI primitive. In some sense, it is "more uniform than uniform". For example, a patch mesh of m x n patches requires mn data values for a uniform variable, but requires only a single data value for a constant variable.
The list of valid declaration types has been extended to include vector, normal and hpoint. As with geometric parameters of type point, parameters of these types are specified in object space and are transformed by the current transformation matrix. However, just as mathematical points, homogeneous points, direction vectors and normal vectors each transform slightly differently, so the declared type indicates which version of the vector-matrix transformation should be used. In addition, point, vector and normal parameters each contain three floating point numbers per entry, whereas hpoint (homogeneous point) parameters contain four floating point numbers per entry. The predefined position variable "Pw" is now correctly described as a vertex hpoint, and the predefined varible "N" as a varying normal.
The list of valid declaration types has been extended to include a new matrix type, which consists of 16 float values. The use of the matrix type in Shading Language is explained in the Shading Language Extensions Document.
The number of varying and uniform variables on an RiNuPatch has now officially been deemed to be computed as if the NuPatch is a nonperiodic uniform B-spline mesh, rather than a single B-spline patch. The method of computation is as follows. An RiNuPatch is defined to have (1+nu-uorder) segments in the u parametric direction, and (1+nv-vorder) segments in the v parametric direction. An RiNuPatch is defined to have one uniform value per segment and one varying value per segment corner. The number of uniform variables is therefore nusegments*nvsegments, and the number of varying variables is therefore (nusegments+1)*(nvsegments+1). This results in redundant parameter values corresponding to repeated knot values, for instance when the knot vector indicates the RiNuPatch is in Bezier form, however the benefit of the flexibility far outweighs any burden due to the redundancy.
RiCoordSysTransform("coordinatesystem");
or in RIB:
CoordSysTransform "coordinatesystem"will set the current transformation matrix to be the matrix for coordinatesystem. coordinatesystem can be the name of a user defined coordinate system named using the RiCoordinateSystem call, or it can be one of the predefined coordinate systems: "raster", "NDC", "screen", "camera", "world", "object". Note that:
RiReadArchive("filename", callbackfunc,
parameterlist);
or in RIB:
ReadArchive "filename"will read the named filename. Each RIB command in the archive will be parsed and executed exactly as if it had been called by the application program directly, or been in-line in the calling RIB file, as the case may be. This is essentially a RIB-file include mechanism.
In the C version, the second parameter is a callback function which will be called for any RIB user data record or structure comment which is found in the file. This routine has the same prototype as RiArchiveRecord, and allows the application routine to notice user data records and then execute special behavior based on them as the file is being read into the renderer.
Note that this is a new RenderMan Interface call not described by the
RenderMan Interface Version 3.1 Specification.
Like many other routines which read files, RiReadArchive can
utilize a search path to find the file to be read. The search paths for
archive reads is specified by the option
where path is a colon separated list of directories.Option "searchpath" "archive" ["path"]
RiCurves( RtToken type, RtInt ncurves, RtInt nvertices[], RtToken wrap, parameterlist );
RiCurvesV( RtToken type, RtInt ncurves, RtInt nvertices[], RtToken
wrap,
RtInt n, RtToken tokens[], RtPointer parms[] );
The interpolation method given by type can be either "linear" or "cubic" (note: not "bilinear" or "bicubic"). Cubic curves interpolate using the v basis matrix and step size set by RiBasis. The u parameter changes across the width of the curve, while the v parameter changes across the length of the curve (i.e. the direction specified by the control vertices).
Curves may wrap around in the v direction, depending on whether wrap is "periodic" or "nonperiodic". Curves which wrap close upon themselves at the ends and the first control points will be automatically repeated. As many as three control points may be repeated, depending on the basis matrix of the curve.
parameterlist is a list of token-value pairs where each token is one of the geometric primitive variables or a variable that has been defined with RiDeclare. The parameter list must include at least position ("P" or "Pw") information. The width along the curve may be specified with either a special "width" parameter which is a varying float argument, or a "constantwidth" parameter which is a constant float (one value for the entire RiCurves). Widths are specified in object space units of the curve. If no "width" vector or "constantwidth" value is given, the default width is 1.0 units in object space.
Since an RiCurve generates a flat ribbon, but the control vertices only specify the direction of the "spine", the rotation of the flat ribbon about the spine is ambiguous. If no normals ("varying normal N") are specified in the parameter list, the ribbon will rotate so that it is as perpendicular to the view plane as possible. This is a good way to simulate a thin tube, since the silhouette of the ribbon will match that of the tube. However, if "N" values are supplied, the normals will be used to guide the ribbon so that it stays perpenticular to the supplied normals, thus allowing user-controlled rotation of the ribbon. To summarize, if you supply "N" values, you will get something like grass, and if you do not supply "N" values, you will get something like hair.
The number of data items required for constant, uniform, varying, or vertex parameters for curves is as follows:
Curves "linear" [5] "nonperiodic" "P" [0 0 0 3 4 5 -1 -.5 1 2 .5 1 1 0 -1 ] "constantwidth" [0.075]
RiPoints( RtInt npoints, parameterlist );
RiPointsV( RtInt npoints, RtInt n, RtToken tokens[], RtPointer parms[] );
Draws npoints number of points. Each point is treated independently. This means a point is shaded only once and does not have access to derivative information. The size, in object space, of a point can be specified in the parameter list by using the primitive variable width. width is defined as a varying float and requires one value for each point. If width is not specified in the parameter list then it will default to 1.0 for a particle size of 1.0 units in object space. If all the points are of the same size, the user may specify the variable constantwidth, which is defined as type uniform float to supply a single width value for all points.
When using the Points primitive, keep in mind that it is meant to be used for small particles, one or two pixels in size. Certain simplifying assumptions have been made to optimize rendering for particles of this size.
RIB BINDING
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.
The "smoothtriangles" tag (available in 3.9) specifies that a special subdivision rule be applied to all triangular faces; this rule was empirically determined to make triangles subdivide more smoothly. However, it was recently shown that this rule breaks the nice property that two separate meshes can be joined seamlessly by overlapping their boundaries; i.e. when there are triangles at either boundary, it is impossible to join the meshes seamlessly. The tag introduced is meant to overstep the problem by allowing the user to turn off the offending subdivision rule. The tag has 1 integer argument (1 to turn on the rule, 0 to turn it off) and 0 floating-point arguments.
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.
RIB BINDING
SEE ALSO
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:
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.
PRMan 3.9 has support for free-form self-blending implicit-function surfaces in the style of Jim Blinn's blobby molecules, Nishimura et al.'s Metaballs and Wyvill, McPheeters and Wyvill's soft objects. Blobby surfaces may be composed of spherical and sausage-like line-segment primitives with extremely flexible control over blending. The surface type also provides for repulsion to avoid intersection with irregular ground planes, represented by prman-produced Z-files.
Blobbies may be shaded much like ordinary parametric primitives, with the caveat that they have no u and v parameters. Nevertheless, they may be given vertex values, by attaching scalar values or reference coordinate fields to primitive sub-objects that will be blended appropriately by prman. Motion-blur, depth-of-field and all of prman's other advanced sampling features also work as expected.
In the Renderman C binding, blobby implicits are specified by:
void RiBlobby(
RtInt nleaf,
RtInt ncode, RtInt code[],
RtInt nflt, RtFloat flt[],
RtInt nstr, RtString str[],
...);
The code array is a sequence of machine language-like instructions describing the object's primitive blob fields and the operations that combine them. Floating point parameters of the primitive fields are stored in the floats array. File names of the z-files of repellers are in the strings array. The integer nleaf is the number of primitive blobs in object, also the number of items in each varying or vertex parameter.
Each instruction has a numeric opcode followed by a number of operands. Instructions specifying primitive fields start at 1000. They are:
| Opcode | Operands | Operation |
|---|---|---|
| 1000 | float | constant |
| 1001 | float | ellipsoid |
| 1002 | float | segment blob |
| 1003 | string, float | repelling ground plane |
For all four of these operators, the operands are indices into the appropriate arrays.
There are several more opcodes that compute composite fields by combining the results of previous instructions in various ways. Every instruction in the code array has a number, starting with zero for the first instruction, that when used as an operand refers to its result. The combining opcodes are:
| Opcode | Operands | Operation |
|---|---|---|
| 0 | count, ... | add |
| 1 | count, ... | multiply |
| 2 | count, ... | maximum |
| 3 | count, ... | minimum |
| 4 | dividend, divisor | divide |
| 5 | subtrahend, minuend | subtract |
| 6 | negand | negate |
| 7 | idempotentate | identity |
Add, multiply, maximum and minimum all take variable numbers of arguments. The first argument is the number of operands, and the rest are indices of results computed by previous instructions. The identity operator does nothing useful, and is only included for the convenience of programs that automatically generate Renderman input.
RIB BINDING
SEE ALSO
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.
texture(), environment(), bump(), shadow(), Deriv(), Du(), Dv(), area(), calculatenormal()These functions depend on comparing various values at more than one point on the surface. The conditional partitions 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.
Functions are expanded inline by the compiler during compilation. If a function is changed, all shaders using it must be recompiled in order to use the new function. Recursive functions are not permitted.
Function parameters are passed by reference, not by value. As a result, if a function modifies a parameter, that modificiation will be reflected in the caller's variables.
Multiple return statements are not supported. User-defined functions should have only a single return statement.
Internally, the Shading Language compiler generates unique name for function parameters by concatenating the function and paramete names. This name thus generated is subject to a 32 character limitation. Care should be taken to ensure that the combined length of function and parameter names does not exceed this character limit.
The specular function itself is not exactly the same as that which appears in the RenderMan Interface Version 3.1 Specification. Instead, it has been implemented as a function which is much more like that described by Blinn, and by Cook and Torrance, in Siggraph papers in 1978 and 1981. This function has much better performance at near-grazing and off-axis reflection than the documented function.
The amount of time required to render is roughly dependent on the number of pixels covered by geometry in the image. Therefore, another way to reduce the time required to render an image is to reduce its size. This is achieved using the RiFormat command. It takes as two of its arguments the x and y resolutions of the desired image. Rendering a 256x256 image will take approximately one quarter the time required to compute a 512x512 equivalent.
Reducing the sub-pixel sampling rate will also speed up the rendering of an image. Antialiasing is performed by supersampling the image and then filtering to produce the final pixel. One can effectively turn off antialiasing by reducing the sampling rate to one sample per pixel. This is achieved by calling the RiPixelSamples command with both xsamples and ysamples set to 1. (When setting RiPixelSamples to one sample per pixel, the results will look very noisy if the "hidden" hider is used without the jitter option disabled.)
PhotoRealistic RenderMan contains an alternative hider that uses a z-buffer algorithm instead of the default stochastic algorithm. It does not handle transparency, motion blur, anti-aliasing, or depth of field. However, it does run faster, especially if the shading rate has been set to a large value. This hider may be specified by:
RiHider("zbuffer", RI_NULL);
The processing of patches and patchmeshes is somewhat more efficient than the processing of polygons and pointspolygons. For this reason, we recommend representing quadrilaterals as bilinear patches whenever possible.
Because shading rate is an attribute, it can differ from object to object in a scene. There are times when this property can be used to speed up rendering without detracting from the image quality. If an object is flat and uniformly shaded, or if it is extremely motion-blurred, it will not suffer from a high shading rate. For example, if a uniform patch is being used in a scene as a background, it can have a large shading rate on it. In this case, rendering will speed up significantly because the patch covers a large percentage of the pixels in the image. Using motionfactor will adaptively raise the shading rate for moving objects, which can greatly improve rendering speed. See Section 4.2.5 for more details.
In general, for a fixed shading rate, the computational complexity of a shader will determine the rendering time for an object. Environment maps are slower than texture maps, which are in turn slower than simple procedural shaders.
Rendering time is not directly affected by distances between objects or locations of objects in the scene, except as this positioning affects the sizes of the objects in the image. Portions of an object which extend beyond the boundaries of the viewing pyramid will have a relatively small effect on the rendering time. However, if an object crosses both the eye (camera) plane and the near clipping plane, it may require recursive splitting (see Section 4.1.7) and therefore slow down the renderer.
Setting RiSides to 1 will make the renderer discard primitives that face awayfrom the camera before they are shaded. This can speed up renderingsignificantly because only about half the shading calculations are performed. However, if the objects are defined with the wrong orientation (normals pointinginward instead of outward), the wrong half of the primitives will be culled andthe image will contain only the back halves of objects. This can be corrected byusing the attribute RiReverseOrientation on primitives with this orientation problem.
It is possible to control, to a certain degree, the amount of memory PhotoRealistic RenderMan uses. This is particularly important for systems that have limited physical memory. Such systems will either show a sharp degradation in performance or PhotoRealistic RenderMan will not complete its rendering when it surpasses the physical memory available. The most effective means of controlling memory usage is to modify the bucketsize and gridsize options and to use crop windows to render the image in small sections. See Section 4.1.2, Section 4.1.3, and Section 6.6 for a discussion of these options.
Another way of reducing memory usage is to increase the value passed to RiShadingRate. This has limited utility in that it typically degrades the quality of the image. However, it is very useful when one is performing motion blur. Motion blur can dramatically increase memory usage. Degrading the quality of the blurred objects by increasing the shading rate is usually quite acceptable since the details of the blurred objects are rather difficult to see anyway. This will both reduce memory usage and increase performance.
Using motionfactor and extremedisplacement can often save memory when motion blur or displacements are in use. See Section 4.2.5 and Section 4.1.6 for more details.
For the renderer to compute with the most accurate floating-point depth values, always set the near and far clipping planes to bound the scene as tightly as possible. This will reduce the range of z values that need to be represented. Otherwise, cracking and other numerical artifacts may appear.
A motion-picture camera does not have its shutter open at all times. The shutter is closed to control the exposure and to allow the film to be advanced from frame to frame. Similarly, when using motion blur with PhotoRealistic RenderMan, one should not specify that the shutter is open at all times. If one did, it would produce very smooth motion, but the moving objects would look very fuzzy. Instead, the shutter should be open for no longer than 50% of the time. This is achieved by not having the min argument to RiShutter for the current frame be equal to the max argument for the previous frame.
The simplest solution is to render the image at a lower resolution and resize it up to the desired output resolution using the tiffsize utility. This is easy to do, but the resulting image quality will not be as good as that of an image rendered at the full size.
Another technique that is quite useful is to use the RiCropWindow procedure to break the image into manageable pieces. By rendering only one piece of the image at a time, all of the system's resources are brought to bear on a smaller problem. Once all of the pieces are rendered, they need to be put together to make the full-sized image. If your frame buffer is large enough, you can just render the pieces into the frame buffer and save the resulting image as a single file. Otherwise, you can use the tiffjoin utility to combine several TIFF image files into one large, single TIFF image file.
The last technique that we will recommend is the image compositing method. This method requires the use of an image compositing utility, such as tiffcomp. If your scene geometry can be broken into sections that occur at different, non-overlapping depths, you can render each of these parts of the scene separately, using the full resolution for each one. This gives you several images that can be composited together to form the final image. If you are using this method, you need to render each component image with an alpha channel so that compositing can be done correctly.
The shadow depth map is generated by rendering the scene from the point of view of the light with the following display specification:
RiDisplay("filename.shd", "shadow", RI_Z, RI_NULL);
Notice that this specifies the shadow display driver instead of
the default file driver. The only file drivers distributed with PhotoRealistic
RenderMan that accepts depth data are the shadow
driver and the zfile driver.
This may change in the future, at which time the default file driver may
be used.
It is important to remember that shadow depth maps can not be generated at arbitrary resolution. The resolution (height and width) of a shadow depth map must be powers of two (e.g., 1024 x 1024, or 512 x 256). In addition, shadow depth maps should be generated with the following image options:
RtInt off = 0;
RiPixelSamples(1, 1);
RiPixelFilter(RiBoxFilter, 1.0, 1.0);
RiHider("hidden", "jitter", (RtPointer)&off);
The trickiest part of producing the shadow depth map is setting up the
camera to have the same view as the light. Light shaders typically have
from and to parameters to specify their position and
aim point. The following subroutine will generate an appropriate camera
transformation from these parameters (this subroutine is a modification
of the subroutine PlaceCamera specified on page 142 of The
RenderMan Companion):
#include <ri.h>
#include <math.h>
#define PI 3.14159265359
void PutCamera(RtPoint from, RtPoint to)
{
RtPoint direction;
float xzlen, yzlen, yrot, xrot;
direction[0] = to[0] - from[0];
direction[1] = to[1] - from[1];
direction[2] = to[2] - from[2];
if (direction[0]==0 && direction[1]==0 && direction[2]==0)
return;
RiIdentity();
xzlen = sqrt(direction[0]*direction[0] + direction[2]*direction[2]);
if (xzlen == 0)
yrot = (direction[1] < 0.0)? 180.0 : 0.0;
else
yrot = 180.0*acos(direction[2]/xzlen)/PI;
yzlen = sqrt(direction[1]*direction[1] + xzlen*xzlen);
xrot = 180.0*acos(xzlen/yzlen)/PI;
if (direction[1] > 0.0)
RiRotate(xrot, 1.0, 0.0, 0.0);
else
RiRotate(-xrot, 1.0, 0.0, 0.0);
if (direction[0] > 0.0)
RiRotate(-yrot, 0.0, 1.0, 0.0);
else
RiRotate(yrot, 0.0, 1.0, 0.0);
RiTranslate(-from[0], -from[1], -from[2]);
}
If one is generating the shadow depth map for a distant light, i.e. a light
with parallel rays, the shadow depth map should be generated with an orthographic
projection. This is specified by:
RiProjection("orthographic", RI_NULL);
If one is generating the shadow depth map for a spotlight or pointlight,
the shadow depth map should be generated with a perspective projection,
i.e.:
RiProjection("perspective", RI_NULL);
In both cases the field of view must be sufficient to enclose all the geometry
that will cast shadows and, in order to preserve the greatest precision
in the shadow map, this field of view should be the minimal one to contain
this geometry. The field of view is controlled by RiScreenWindow
and, for perspective projections, the RI_FOV parameter to RiProjection.
Pointlights present a difficult problem in that they may cast shadows in a 360-degree field of view. Such a field of view cannot be specified with RenderMan for producing the shadow depth map. There are two approaches to overcoming this problem. First, if the geometry is such that shadows are only cast in a sufficiently narrow field of view, a pointlight may be treated in the same manner as spotlights. Any geometry that falls outside the view of the shadow depth map will be treated as if it were fully illuminated by the pointlight. The other approach is to generate a set of shadow depth maps that view the geometry from the light but in different directions. This is similar to the approach taken for environment maps. A special light shader, shadowpoint, has been written that selects among the set of shadow maps depending on the direction to the point being shaded.
Since PhotoRealistic RenderMan only needs to generate depth information when producing the shadow depth map, it is not necessary to include surface shaders and lights. This will improve the performance of generating the shadow depth map as will removing all geometry that doesn't cast a shadow. Of course, one should not include a light shader that references the shadow map being generated.
An alternative to generating a shadow depth map file directly using the "shadow" display driver is to generate a simple depth file using the "zfile" display driver. A zfile must be turned into a shadow map by using either a call to RiMakeShadow or the stand-alone utility txmake. This method still requires that the height and width of the shadow texture (and hence the zfile) be powers of two.
The shadow map can then be accessed in subsequent frames by using a light-source shader that contains a call to the shadow shader subroutine. Notice that shadow returns the amount of shadow at a point in space rather than the amount of light. Therefore, light shaders typically multiply the light intensity by 1-shadow(...). The following is an example of a distant light shader that uses a shadow map:
light
distshad(
float intensity=1;
color lightcolor=1;
point from = point "camera" (0, 0, 0);
point to = point "camera" (0, 0, 1);
string shadowname="";
)
{
solar( to - from, 0.0 ) {
Cl = intensity * lightcolor;
Cl *= 1 - shadow(shadowname, Ps);
}
}
The library containing the renderer is: /usr/local/prman/prman/lib/libprman.a
Many of the example programs from The RenderMan Companion can be found in the directory In this directory, there is a sub-directory for each included chapter. Each of these contains example programs and a makefile. To compile and render all the the examples, make the target pics in this directory.
The PhotoRealistic RenderMan Tutorial
is a walk-through of all these examples, and describes the details of what
was involved to create working example programs from the listings in The
RenderMan Companion.