This application note provides a quick introduction to the RenderMan Interface. It is intended primarily for readers who are already familiar with computer graphics and rendering. For a more thorough introduction, please consult The RenderMan Companion [1], by Steve Upstill.
The RenderMan interface is designed to be a standard interface between modeling programs and high-quality rendering programs. As such, it has provisions for the specification of 3-D scene descriptions that include: hidden surfaces, spatial filtering, dithering, motion blur, depth of field, flat and curved surfaces, objects, constructive solid geometry, and programmable shading to express lighting conditions, shadows, and surface appearances, with sophisticated control over color, texture, and reflectivity. The design of the interface emphasizes the ability to convey, compactly and efficiently, the information required to produce rendered images that resemble actual photographs.
What follows is a very general overview of the RenderMan Interface that introduces the interface routines and terminology. It concludes with a brief description of how certain concepts that are common to 3-D graphics are handled in the interface.
The RenderMan Interface was proposed by Pixar in May, 1988, as a standard interface between modelers and high-quality renderers. To date, it is the only proposed rendering interface standard that includes provisions for all the features in a scene description required to synthesize photorealistic images.
At the time of its introduction, the RenderMan Interface was defined in terms of a C language binding, a set of 96 C procedures that provides a complete rendering interface. Since then, a bytestream protocol has also been defined and incorporated into the interface specification. This protocol is known as the RenderMan Interface Bytestream (RIB), and it not only allows a scene description to be stored as an ASCII or binary coded file but also provides a means for transport over a network.
For the sake of simplicity, the interface will be presented here in its C language form. The conversion to RIB is quite straightforward, and a full description of it can be found in The RenderMan Interface, Version 3.1 [2].
The RenderMan Interface describes a scene as a sequence of geometric primitives. This sequence specifies all the objects in a scene in terms of the variety of flat and curved surfaces that RenderMan supports. To control the positioning and shading of these objects, the RenderMan Interface maintains a graphics state, which is primarily just a current setting for each of a large number of parameters associated with the rendering of an object in a scene.
The graphics state consists of options, attributes, and the interface mode. Options are the rendering parameters that affect how an entire scene will be rendered, while attributes are the parameters that can differ from object to object in a scene. The interface mode constrains and controls the context of allowed RenderMan procedure calls, and it also maintains the graphics state stack. This stack allows various parts of the graphics state to be saved and reinstated at will.
To control the graphics state, there are procedures in the interface that change the current mode, options, and attributes. These routines are classified here as mode-changing procedures, option-changing procedures, and attribute-changing procedures. The interface also includes a set of geometric primitive procedures that describe the actual geometry in a scene.
The interface starts up with default option and attribute values, which are defined in the interface specification. Calling a RenderMan option- or attribute-changing procedure sets the values of certain related options or attributes in the graphics state.
A scene is begun by calling the mode-changing routine RiWorldBegin(), and its options are set from the option values in the current graphics state. These values then become frozen, and it is forbidden to use any option-changing procedures until the scene's description is finished.
In the scene, attributes are still free to change. Each piece of the scene's geometry is described by calling a RenderMan geometric primitive procedure; a given primitive gets its attributes from the current graphics state at the time it is passed through the interface.
There are now 95 basic RenderMan routines, and they all have names of the form RiSomething(). They can be classified quite cleanly into the following categories:
There are 17 procedures in the RenderMan interface to place geometric primitives in a scene. They support polygons, bilinear and bicubic patches, non-uniform rational B-spline patches, quadric surfaces, and retained objects.
There are 16 procedures for changing modes, which sort out into eight begin-end pairs. Three of the pairs are for basic renderer and scene control, and three others control special modes of the interface for retained object, CSG, and motion blur specification. Though most of these six pairs also affect the attribute stack, the remaining two exist solely for additional stack control. The Procedures List on the next page lists the names of these procedures, separated by category, along with a brief description of each one. (Consult The RenderMan Companion for full descriptions with arguments.)
There are 19 procedures for changing options. Each one sets a closely related set of option parameters in the graphics state, and the majority of them control either the effects that arise from the camera model or the display processing that occurs in the renderer.
There are 34 procedures for changing attributes, and each one alters a related set of attribute parameters in the graphics state. As attribute parameters pertain to operations that occur on each primitive, they tend to affect either a primitive's geometry and positioning in space or its lighting, shading and the opacity of its surfaces. Included as a geometric attribute is the current transformation, which defines the current coordinate system for all point values. Because of the special importance of this attribute, there are 8 procedures to manipulate the current transformation matrix, one to concatenate nonlinear transformations into the current transformation, and one to attach a name to a coordinate system.
Finally, there are 9 miscellaneous routines to produce texture map files from image files and perform various bookkeeping tasks.
Among the option- and attribute-changing procedures, you may notice that several are used to specify shaders. One of the most powerful features of the RenderMan Interface is its ability to apply user-defined shaders in the rendering process. Traditionally, a shader describes the intensity of light that a given point on a surface will reflect toward the camera. However, in RenderMan, the notion of a shader is much more general.
Included with the RenderMan Interface is a specification of the RenderMan Shading Language. This language has a syntax similar to C's, and it enables the user to control several key operations in the rendering process. Aside from surface shaders, which do things traditionally associated with "shading," there are seven other classes of shaders. Here is a list of the eight shader classes, along with a brief description of the rendering computation described by each one:
surface | The way a surface reflects and transmits light. |
light | Light emitted by a light source. |
atmosphere | Attenuation of camera-bound light through space. |
volume | Attenuation of light through a volume in space. |
imager | Re-mapping of image color values before display. |
displacement | Geometric displacement of points on a surface. |
deformation | Geometric transformation of a surface. |
projection | Geometric mapping from camera to screen space. |
RenderMan starts up with a well-defined default shader for each of these classes, and the interface also provides a set of standard shaders that are suitable for many purposes. For beginners, the most important shader classes to consider are surface and light.
From the point of view of RenderMan Interface procedure calls, a shader is just the name of a compiled shading language file that exists in a known place. However, shaders also have parameters that can be set through the interface when the shader is brought into the graphics state. To handle this capability, certain RenderMan procedures take a list of arguments known as a parameterlist. Each parameter has a default value that is given in the shader, so it only needs to be in the parameterlist if it is to have a value other than its default. The parameterlist always begins after the last procedure-specific argument, and it consists of an optional paired list of arguments followed by the terminating token argument RI_NULL.
The paired arguments in the parameterlist each contain a token followed by a pointer to an array of values. The token is just the string for the name of the parameter, and the values in the array are the values that get assigned to the parameter. Since there are both point and color type variables defined in the Shading Language, it is possible for a parameter to have more than one floating-point value associated with it. For this reason, the rendering interface must know the type of every parameter appearing in the parameterlist. The names and types of parameters that appear in the standard shaders are already known to the interface. However, nonstandard parameters must be declared with the RiDeclare() procedure before they can be used in a parameterlist. Altering a shader's parameters affects the shader's presence in the graphics state, but it does not affect the shader itself. Therefore, every invocation of a given shader starts with the default parameter values and alters them according to the parameterlist in the call.
The 10 routines that invoke shaders are not the only RenderMan procedures that use parameterlists. RenderMan geometric primitive routines use them to define a variety of surface parameters in addition to position and shape, and RenderMan texture routines use them to specify optional texture parameters. There are also a few other routines that are designed to take extended sets of parameters using parameterlists. In total, 32 of the procedures that we have seen so far use parameterlists.
Since the length of a parameterlist is not always known at compile-time, RenderMan also provides a varargs form for each procedure that uses a parameterlist. These routines have names of the form RiSomethingV(), and each does the same thing as its RiSomething() counterpart, taking a fixed number of pointers to variable-length argument arrays instead of a variable-length parameterlist.
Before leaving this introduction, it is worth noting how the RenderMan 3-D graphics environment works. In particular, it is important to know how RenderMan handles coordinate systems, transformations, camera positioning, and light sources. Mentioned here are the primary graphics conventions in RenderMan that are likely to differ from other 3-D environments. Consult The RenderMan Companion for more details.
The natural RenderMan coordinate system is a left-handed one in which the x axis points to the right, the y axis points up, and the z axis points into the screen. For any geometric primitive in a scene, RenderMan keeps track of several coordinate systems, including "object", "shader", "world", "camera", "screen", and "raster" spaces. In addition, any coordinate system can be named with the RiCoordinateSystem() procedure. The interface starts up in camera space.
Before RiWorldBegin() has been called, transformations are used to position the camera by defining world space (see below). After RiWorldBegin(), they set up the coordinate systems into which objects and shaders are placed. Shaders have coordinate systems associated with them in the same way that objects do. By interspersing RenderMan transformation and stack routines between geometric primitive routines, it is possible to control how object space is defined for each object in the scene. The same is true for shader space, based upon where the call that invokes each attribute shader is made.
RenderMan applies given transformations onto objects in reverse sequence. This means that the last transformation concatenated onto the current transformation before an object is defined is the first one that will be applied to the object.
In RenderMan, the camera is not specified as a separate object. Instead, transformation routines are called before RiWorldBegin() to define the mapping from world space to camera space. This process is conceptually the same as having a camera that is fixed at the origin, looking down the z axis, and transforming the world, as though it were an object, until it is in proper view.
RenderMan places point light sources into the scene as shaders. The positioning of a light source is set through parameters to the light shader associated with the light, and each light is included in the scene with a call to RiLightSource(). Since any point values passed to a light shader are interpreted as being in the current coordinate system, it is also possible to use transformations to control light source positioning.
Now that you are familiar with the RenderMan Interface, you can either go on and read The RenderMan Companion, or refer to The RenderMan Interface, Version 3.1, for more information. If you own Developer's RenderMan, you will find that the documentation contains a tutorial, with on-line examples, that is designed to accompany The RenderMan Companion. These are all excellent ways to learn more about RenderMan.
However, if you prefer to learn through hands-on experience, you may wish to consult the other RenderMan application notes. These notes provide good tips and example programs, and they are especially useful if you are using PhotoRealistic RenderMan, as they cover many implementation-specific considerations that are not covered elsewhere.
[1] Upstill, Steve, "The RenderMan Companion: A Programmer's Guide to Realistic Computer Graphics," Addison-Wesley, 1990.
[2] The RenderMan Interface Specification, V3.1, September 1989, Pixar.
Polygons: | |
RiPolygon() | Simple, convex, planar polygon |
RiGeneralPolygon() | General planar polygon, holes optional |
RiPointsPolygons() | Many simple polygons from given points |
RiPointsGeneralPolygons() | Many general polygons from given point |
Patches: | |
RiPatch() | Bilinear or bicubic patch |
RiPatchMesh() | Mesh of bilinear or bicubic patches |
RiNuPatch() | Non-uniform rational B-spline patch |
Quadrics: | |
RiSphere() | Complete or partial sphere |
RiCone() | Complete or partial conic surface |
RiCylinder() | Complete or partial cylindrical surface |
RiHyperboloid() | Complete or partial hyperbolic surface |
RiParaboloid() | Complete or partial parabolic surface |
RiDisk() | Complete or partial disk |
RiTorus() | Complete or partial torus |
Other: | |
RiProcedural() | Procedural geometry specification |
RiGeometry() | Any other primitives not covered above |
RiObjectInstance() | Retained geometric object |
Basic: | |
RiBegin() | Start the interface |
RiEnd() | End the interface and clean up |
RiFrameBegin() | Begin a new frame and save options |
RiFrameEnd() | End the frame and restore options |
RiWorldBegin() | Start the scene and freeze options |
RiWorldEnd() | End the scene and unlock options |
Special: | |
RiObjectBegin() | Start retained object description |
RiObjectEnd() | End retained object description |
RiSolidBegin() | Start CSG solid description |
RiSolidEnd() | End CSG solid description |
RiMotionBegin() | Start motion description |
RiMotionEnd() | End motion description |
Stack: | |
RiAttributeBegin() | Push all attributes onto stack |
RiAttributeEnd() | Pop all attributes from stack |
RiTransformBegin() | Push current transformation onto stack |
RiTransformEnd() | Pop current transformation from stack |
Camera: | |
RiFormat() | Pixel resolution of full output image |
RiFrameAspectRatio() | Resolution constrained to aspect ratio |
RiScreenWindow() | Screen-to-raster-space mapping |
RiCropWindow() | Portion of the full image to render |
RiProjection() | Camera-to-screen-space mapping shader |
RiClipping() | Distance to near and far clipping planes |
RiDepthOfField() | Parameters to simulate depth of field |
RiShutter() | Motion blur shutter open and close times |
Display: | |
RiPixelVariance() | Tolerance for adaptive sampling |
RiPixelSamples() | Effective pixel sampling rate |
RiPixelFilter() | Type of filter to use on samples |
RiExposure() | Scene-to-image exposure parameters |
RiImager() | Image-to-image re-mapping shader |
RiQuantize() | Image float-to-int mapping parameters |
RiDisplay() | Image filename and display parameters |
Other: | |
RiHider() | Type of hider and its parameters |
RiColorSamples() | Number of components in a color value |
RiRelativeDetail() | Relative detail level of entire scene |
RiOption() | Any other parameters not covered above |
Shading: | |
RiColor() | Surface color |
RiOpacity() | Surface opacity |
RiTextureCoordinates() | Surface extent in texture space |
RiLightSource() | Light source positions and shaders |
RiAreaLightSource() | Area light source extents and shaders |
RiIlluminate() | Active light sources |
RiSurface() | Surface visible intensity shader |
RiAtmosphere() | Atmospheric attenuation shader |
RiInterior() | Interior volumetric attenuation shader |
RiExterior() | Exterior volumetric attenuation shader |
RiShadingRate() | Raster area per shading computation |
RiShadingInterpolation() | Type of interpolation on shading values |
RiMatte() | Flag to render objects as matte holes |
Geometry: | |
RiBound() | Bounding box for geometric primitives |
RiDetail() | Level of detail at which to render |
RiDetailRange() | Range of detail assigned to geometry |
RiGeometricApproximation() | Tolerance of geometric approximations |
RiBasis() | Basis matrix for bicubic patches |
RiTrimCurve() | Trim curves for NURBS patches |
RiOrientation() | Handedness of geometric primitives |
RiReverseOrientation() | Handedness of geometric primitives |
RiSides() | Number of sides to geometric primitives |
RiIdentity() | Current transformation matrix |
RiTransform() | Current transformation matrix |
RiConcatTransform() | Current transformation matrix |
RiPerspective() | Current transformation matrix |
RiTranslate() | Current transformation matrix |
RiRotate() | Current transformation matrix |
RiScale() | Current transformation matrix |
RiSkew() | Current transformation matrix |
RiDeformation() | Current nonlinear transformation shaders |
RiDisplacement() | Surface displacement shader |
RiCoordinateSystem() | Name of current coordinate system |
RiCoordSysTransform() | Current transformation matrix |
Other: | |
RiAttribute() | Any other parameters not covered above |
Texture: | |
RiMakeBump() | Make bump map from image file |
RiMakeCubeFaceEnvironment() | Make environment map from 6 images |
RiMakeLatLongEnvironment() | Make environment map from one image |
RiMakeShadow() | Make shadow map from z file |
RiMakeTexture() | Make texture map from image file |
Bookkeeping: | |
RiErrorHandler() | Set error handler |
RiDeclare() | Declare a non-standard shader parameter |
RiTransformPoints() | Transform points from space to space |
RiArchiveRecord() | Send archival comments to RIB stream |
Pixar Animation Studios
|