How To Render Quickly Using PhotoRealistic RenderMan
May, 1990 (Revised June, 2012)
PhotoRealistic RenderMan is designed and optimized for creating very realistic images of visually complex scenes. For this reason, many of its default parameter settings are set for generating very high quality output, usually at the expense of speed. This is not to say that it cannot be made to run fast. It can. However, you must explicitly set certain parameters to get that speed. This application note describes the speed knobs, and how to set them. Further information on the knobs described here, and the rest of the run-time options of PhotoRealistic RenderMan (including some examples of their use) can be found in the PhotoRealistic RenderMan User's Manual and in the PhotoRealistic RenderMan Tutorial (specifically, Chapter 17).
This application note deals only with the knobs which can be used to speed up the rendering of an existing RenderMan model description (usually in the form of a RIB file). It assumes that the basic structure of the model, such as the transformation hierarchy and the geometric primitives used, cannot be changed.
KILL THAT DEFAULT SHADING RATE
For reasons that are very obscure, the default value for the ShadingRate parameter is 0.25. This value is far too small. The very first thing to do to get your models rendering more quickly is to set this to 1.0, at least. We will examine ShadingRate in detail later, but stop here and do this before you go any farther.
Like many programs, PhotoRealistic RenderMan has parameter settings that allow the user some control over execution-time trade-offs. In PhotoRealistic RenderMan these trade-offs come in two varieties: speed versus memory consumption, and speed versus quality.
Speed versus memory consumption is a simple trade-off to understand. By allocating larger memory buffers to handle larger amounts of data at once, and by storing temporary results instead of recomputing them, overhead is reduced and overall speed is increased. However, many systems have fixed memory limits; and even systems with virtual memory suffer significant performance degradation once a certain memory size is reached. The default setting for the speed versus memory trade-offs were usually set to minimize memory consumption, since even now, most PC and workstation users have severe memory limitations. Minimizing memory consumption was seen as the best way to ensure that the largest number of models would go through the system without running out of memory. For a given scene, the parameters should be reset to the largest values possible without reaching the above mentioned limits.
Speed versus quality is a more difficult trade-off to quantify, because different users will require different minimum levels of image quality. It is up to the user to determine how many image artifacts are acceptable, based on how important the image is and in what forum it will be presented. As mentioned above, the speed versus quality trade-offs were set to very high quality settings in order to maximize the photorealism of the images. For a given scene, the parameters should be reset to the fastest values possible without introducing objectionable artifacts (where objectionable is obviously a subjective opinion on the part of the user).
The table below lists the various controls which the user can manipulate to affect the speed trade-offs in PhotoRealistic RenderMan.
FORMAT AND CROP WINDOWS
Perhaps the simplest thing you can do to make images compute faster is to generate smaller images by shrinking the Format. This may seem silly, but quite often when a quick test is necessary to answer certain questions like Are the lights on? or Is the camera pointed in the right direction? a small image is entirely sufficient. Similarly, half-resolution or quarter-resolution images can be used quite effectively (particularly on framebuffers with hardware zoom) to experiment with large-scale changes to a model. Remember, a 320x240 image renders in about 1/4 the time of a 640x480 image.
Even in more complex situations, questions like Does my color change on that one object look right? can be answered by just recomputing the small section of the image that contains the modification. This is done using CropWindow. Judicious use of small images and sub-images can significantly speed the iteration time of designing and then fine-tuning an image.
This is probably the second most critical factor in the speed performance of PhotoRealistic RenderMan (exceeded only by the resolution). This is due to two factors. First, it governs how often the shading language interpreter runs. Smaller numbers mean the shaders must be evaluated at more places on the surface of the primitives. Second, it governs how many polygons (micropolygons) are passed through the hidden-surface algorithm. Smaller numbers mean more micropolygons, requiring more hidden-surface evaluation and more memory to store temporary results. The end result of all this is that doubling the Shading Rate usually gets you nearly twice the rendering speed. Pretty good!
The default for shading rate is 0.25, which (as we mentioned before) is much smaller than is necessary for most images. A much more typical number for final rendering is 1.0 to 4.0, and test renderings can usually be done at 16.0 or even larger. What is the disadvantage? A shading rate that is too large tends to give blocky looking colors and excessive blur on textures. The blockiness can often be alleviated by turning on Gouraud shading with the ShadingInterpolation "smooth" call. As long as the color of an object changes slowly and smoothly across its surface, this will look fine. Only if the surface has drastic color changes, such as sharp-edged patterns in its textures, will these results be unsatisfactory. And an object with a shading rate of 16.0 and Gouraud shading will render much faster than an object with a shading rate of 1.0.
One of the most important things to remember about the Shading Rate and Shading Interpolation values is that they are Attributes. That is, they can be changed from one primitive to the next. So, if you have a finely patterned vase sitting in a room with flat white walls, the vase can have a small shading rate (like 1.0) to capture its detail while the walls can have a very large shading rate (like 64.0) to save time (with no visible problems). This is a very powerful technique that amounts to telling the renderer which objects to spend time getting right and which objects are boring and can be handled simply.
Pixel Sampling and Filtering
PhotoRealistic RenderMan has very extensive control over antialiasing parameters, and by default they are all turned on. For speed, these can be turned off, with the expected loss of image quality. PixelSamples controls the hidden-surface antialiasing (this is responsible for eliminating jaggies) and turning it down can gain as much as 50% in speed and memory (depending on some of the other parameters). PixelFilter controls filtering to smooth out other hard color transitions, but changing it has only a small effect on overall speed.
If antialiasing is turned completely off, it is possible that most of the power provided by the high-quality hidden-surface elimination subroutines will be wasted. In situations where no antialiasing is required, there are no transparent surfaces, no CSG and no blur, a more efficient hidden-surface elimination subroutine can be called upon to increase speed. This can be accessed by the Hider "zbuffer" call, which invokes the streamlined Z-buffer hidden-surface elimination subroutine instead of the standard ("hidden") stochastic sampler. This is particularly effective if the ShadingRate (see below) is large (e.g., 4.0 or greater), and has been known to save as much as 75% of the rendering time.
Bucket and Grid Sizes
PhotoRealistic RenderMan does not hold its entire Z-buffer in memory at once, but rather works on only small pieces of the buffer at a time to conserve memory. The size of this chunk of Z-buffer (a bucket) is determined by the Option "limits" "bucketsize" call. The larger the buckets are, the more efficient the shading and hidden-surface elimination algorithms are. However, the default for bucket size is very small in order to minimize the memory consumption. Setting this parameter much higher (e.g., 12x12 or even 20x20) is appropriate, keeping in mind that page thrashing must not be allowed to occur.
A related parameter is the maximum grid size, set by the Option "limits" "gridsize" call. A grid is a piece of geometry which is shaded all at the same time. The renderer decides how much of the geometry can be shaded at once based on the size and shape of the primitive and the shading rate. However, the maximum grid size parameter puts a limit on this. In order to get the most speed efficiency out of the shading language interpreter, large grids should be permitted. On the other hand, if the large grid doesn't all land in the current Z-buffer bucket (which happens quite often), it then has to be stored for future Z-buffering. This eats up memory. The smallest grid size limit that saves memory is one which forces grids to fit (more or less) into a single bucket (smaller limits don't help memory, but hurt performance). This value is around bucketsize/ShadingRate. For maximum efficiency, even bigger grids should be permitted, as long as memory holds out.
Texture Cache Memory
If the image has large numbers of textures, or has textures that must be accessed in many places throughout the image (e.g., shadow maps), it can be very advantageous to increase the maximum size limit of the texture cache. This is done through the Option "limits" "texturememory" call. By increasing this maximum cache size, more texture data will be stored in memory, resulting in fewer disk accesses and higher performance. Caution must be exercised, however, in systems with small amounts of real memory; this cache memory will not be available to the rest of the rendering system and could result in severe page thrashing if it is set too high. Texture cache memory is specified in units of Kbytes. A number which is 25% or so of the available real memory is probably a good compromise for images with large texture demands. Notice that it is not necessary to trim this value to zero for images that have no texture, since the cache buffers are not actually allocated unless they are used.
Some models have pieces of geometry that pass from the foreground through the near clipping plane and then far behind the camera: for example, floors or ceilings in a room model. These pieces of geometry cause problems for PhotoRealistic RenderMan, and can sometimes waste large amounts of time. Quite often the error message "Cannot split at camera plane" is issued when this occurs, and then PhotoRealistic RenderMan gives up on that primitive. The difficulty is that quite often the troublesome piece (or piece) of geometry turns out (after much effort) not to be in the picture after all. When this is happening, it is necessary to give PhotoRealistic RenderMan both a larger clipping region and a smaller threshold for giving up. This is done with Clipping to move the near clipping plane forward (away from the camera) and Option "limits" "eyesplits" to reduce the threshold. Clipping should be set as far forward as possible without clipping out any visible geometry (e.g., at least 1.0 in most scenes, usually even more). Eyesplits should be set large enough that no visible geometry is given up on, but small enough that all invisible geometry is given up on quickly (e.g., 5 often works). This is typically a trial-and-error process.
Here are a few other tricks you can try as appropriate to cut down the overall rendering time and limit memory usage. These don't buy very much, but if you are rendering the same image many times (such as during those fine-tuning marathons) every bit helps.
It is important to notice that fine details on an object that is heavily motion-blurred are simply not visible. Only broad bands of color will be seen in the final image. For this reason, it is advantageous to set a very large shading rate for fast-moving objects. Displacement maps are almost always inappropriate, for the same reasons. These will minimize the amount of useless work that PhotoRealistic RenderMan might do to compute very detailed surface shading, since that detail will be lost. It also cuts back the amount of memory required to maintain the object description over the large portion of the screen it influences.
A RIB file that has been converted to binary encoding will use about half the disk space, and will load into PhotoRealistic RenderMan in about half the time. This can be crucial when using very large polygonal models. This process can be done using the catrib program, or the modeler can request binary encoding when it is creating the file. Don't forget that RIB is not a binary or ASCII format. It is a binary and ASCII format. RIB files can have an arbitrary mixture of binary and ASCII encoding. Thus, the initial option setup can be in ASCII format for ease of manipulation, followed by a binary-encoded model description for speed.
If you are using displacement maps, take some time to make sure that the Attribute "displacementbound" value is set appropriately. This call allows you to specify both the maximum displacement and the space in which those units are given (e.g. object, shader, camera, etc.) It is important that this be set correctly, because PhotoRealistic RenderMan uses this value to calculate how much earlier than normal the object must be handled. If it is too large, the object will be shaded and processed far too soon in the rendering of the image, and will waste lots of memory as it sits around waiting to be used. On the other hand, if this number is smaller than the actual maximum displacement, slivers of the displaced object may disappear if they cross bucket boundaries.
For example, if the maximum amplitude of a bump that a certain displacement shader calculates is 3 units, without making any special effort to be in any particular space (i.e., it doesn't use the transform shader function, or anything), this will end up being 3 camera-space units. Then the appropriate displacementbound call is:
Attribute "displacementbound" "sphere"  "coordinatesystem" ["camera"]
Ray Tracing and RiCurves Primitives
To achieve the best performance when ray tracing against RiCurves primitives on scenes with millions of hairs, it is recommended that many hair or fur strands be packed into relatively few RiCurves primitives (e.g., 10,000 or more strands per RiCurves primitive), rather than rendering millions of RiCurves primitives that each are composed of just one or a few strands of hair.
Also, for best performance, it is important to declare any shader parameters that access primitive variables on curve geometry (for example, "hairId", "rootColor" or "tipColor") as varying (rather than uniform) shader parameters.
Especially for RiCurves primitives, it is important to trim the displacement bound setting as low as possible; for non-displaced hair, the displacement bound should be explicitly set to zero for best performance. E.g.,
Attribute "displacementbound" "sphere" 
Manually adjusting the decimation rate option and/or decimation rate attribute to artificially force the renderer to trace against a coarser representation of the geometry than it would normally choose (based on the ray differentials alone) can provide performance benefits for ray-traced hair (as well as other geometry types), provided that doing so does not introduce objectional artifacts or look differences.
Starting in 16.3, we added a new option to control the maximum hair length during the splitting stage (Option "dice" "maxhairlength" [integer]). In version 16.x, adjusting this option's value can significantly benefit hair ray tracing performance. However, as of version 17.0, the RiCurves primitive has been re-implemented in such a way that most of the performance benefits of this setting are inherently captured, and therefore this option, while still present, is expected to have less of an effect on performance. For details, please see the documentation on the "dice:maxhairlength" option.
Panels and Layers
Sometimes an image just requires too much memory. In these cases, it is often helpful to divide the image into subsections that render okay, and then putting the pieces back together after they are all finished.
It is possible to increase greatly the speed with which PhotoRealistic RenderMan generates images, if you take care to choose reasonable values for the knobs that control the speed-quality and speed-memory trade-offs.
- Limit the resolution of the output, particularly when you are testing or designing small sections of the image.
- Choose a reasonable shading rate for each object individually, using Gouraud shading with a large shading rate where appropriate. Don't use the default shading rate unless you absolutely know you have to.
- Limit antialiasing, but be sure to watch out for loss of image quality.
- Balance the memory parameters to suit both the memory configuration of your system and the image you are producing. The greatest of all the enemies of speed is paging.
The default for each of these knobs is set for enormously high quality, which is almost never necessary. By actively controlling even a couple of these knobs, PhotoRealistic RenderMan can give you only as much quality as you need, with a rendering time that is much more reasonable.
THE TABLE IN THIS APP NOTE IS MISSING.