Prev | Next

Dynamic Read Archives

To get started, let's open the Maya scene,
(Where are the tutorial files?) 

This tutorial demonstrates how to make a utility which allows an arbitrary RIB archive sequence to be referenced in a maya scene. The hope is that this is a useful utility which also illuminates several aspects of how RenderMan for Maya can be extended. First, we'll generate a sequence of RIB archives. Then through mel scripting we'll attach the sequence to a cube, which will serve as a standin for the geometry in the archive.


Open the scene called The file contains a teapot that walks in place.

world_ref” has been implemented to embody a reference world coordinate system that's safe within archives for Maya projections, bumps, etc.


Create a poly cube. Scale and translate it to enclose the original teapot. Then select Modify->Freeze Transformations; look in the Freeze Transformations options box to make sure translate, scale, and rotate are enabled. When we're done, the cube will serve as the teapot's standin bounding box, and when you render, the teapot will appear in the place of the box. During rendering, the teapot will be loaded into memory just in time whenever the bounding box of the cube is encountered.

At this point, you could template the teapot hierarchy and group it under the cube transform to allow for visualizing the teapot, or just delete it. We also need to prevent the cube from appearing in renders. This can be done by templating the cube shape node, or if you prefer to be able to manipulate the cube like regular geometry, the shading group should be disconnected from the cube shape.

Next, in order to tell RenderMan for Maya that it should load the teapot archive we need to add a few new attributes to the cube's transform node.


Let's put three new settings on our cube transform node that will allow us to control the archive name and sequence number.

RenderMan for Maya takes the approach of allowing extra attributes to be added to nodes, and they appear in the Attribute Editor under a section called Extra RenderMan Attributes. In order for our new attributes to appear under that section, we need to let RenderMan for Maya know about them by declaring them in its initialization file. RfM puts all of its declarations in files with a .rman extension. Let's put the following in a file called rfm_dra.rman

	rman "-version 1" {
    	Declare param {string draFile} {
			label "Rib Archive"
			description "The rib archive file, which may be the first in a sequence."
			subtype file
			range {*.rib}
    	Declare param {int draUseSequenceNumber} {
			label "Use Sequence Number"
			description "Indicates that the Rib Archive file should be interpreted as a sequence"
			subtype masterswitch
			range {draSequenceNumber}
    	Declare param {int draSequenceNumber} {
			label "Sequence Number"
			description "The sequence number can be an expression."

Put the file wherever you want to keep it, and then we'll tell RfM to load it during initialization. Open your RenderMan_for_Maya.ini file and add the following, replacing the path with the l ocation you chose.

	set myscripts "/path/to/my/scripts"
	LoadExtension rman [file join $myscripts rfm_dra.rman]

Next, some MEL scripting…


We need to add the three new settings to the standin cube, along with one other setting that RfM already knows about. That one is called Post Transfom MEL and it serves as an entry point for executing an arbitrary MEL script at the time that an object is rendered.

Here's a MEL script which adds our new settings to selected objects. You can put it in a file called rmanAddDelayedReadArchiveAttrs.mel and install it with your MEL scripts. Add a button to one of your shelves that invokes the script.

	global proc rmanAddDelayedReadArchiveAttrs() 
	    string $selected[] = `ls -sl`;
    	    int $i, $j;
    	    for( $i=0; $i < size($selected); $i++ ) {
		// Generates a maya attr name, given a setting name as declared
		// in RfM's ini files.
		string $attr = `rmanGetAttrName "postTransformScript"`;
		rmanAddAttr $selected[$i] $attr "rmanOutputDelayedReadArchive";
		$attr = `rmanGetAttrName "draFile"`;
		rmanAddAttr $selected[$i] $attr "";
		$attr = `rmanGetAttrName "draUseSequenceNumber"`;
		rmanAddAttr $selected[$i] $attr "";
		$attr = `rmanGetAttrName "draSequenceNumber"`;
		rmanAddAttr $selected[$i] $attr "";
		// Create a default expression which sets the sequence number
		// to the current frame number.
		expression -s ($selected[$i] + "." + $attr + "=frame")
		    -o $selected[$i] -ae 1 -uc all;


Select the cube, and invoke the rmanAddDelayedReadArchiveAttrs script. Look at the shape node tab in the Attribute Editor. You should see four attributes under the Extra RenderMan Attributes section.

Start by pointing the RIB Archive attribute at one of the rib archives we exported earlier. Click on the folder icon next to the atrribute to bring up the file browser. Pick one of the rib files you exported.

Check the Use Sequence Number parameter. This will tell the script to substitute the frame number in the file name.

Right-Click on the "Sequence Number" setting, and select "edit expression". Our script above created an expression which sets the sequence number to correspond to the current frame. Since 60 frames represent one cycle of the walk, let's loop it. Change it to:




Notice the preShapeScript setting is filled in with a MEL command called rmanOutputDelayedReadArchive. That's the script that is executed right before RfM goes to render the cube. We want it to magically make a RenderMan Interface call like:

	RiProcedural "DelayedReadArchive" ribfilename-with-correct-sequence-number bounding-box-of-cube

RfM has handily defined RiProcedural as a MEL command, so our MEL script can compute the appropriate RIB file name, given the current sequence number, and query the bounding box of the cube. Here's the script. (You should put it in a file called rmanOutputDelayedReadArchive.mel, and install with your MEL scripts.

	proc string replaceFrameNumber( string $str, int $f)
	    string $newStr;
	    string $buf[];
	    tokenize( $str, ".", $buf );
	    int $i, $j;
	    for( $i=0; $i < size($buf); $i++ ) {
			// find substring that's a number
			if( `match "[0-9]+" $buf[$i]` == $buf[$i] ) { 
			    string $fstr = $f;
			    string $pad = "";
	    		// pad with zeros
	    		for( $j=size($fstr); $j < size($buf[$i]); $j++ ) {
					$pad += "0";
	    		$fstr = $pad + $fstr;
	    		$newStr += $fstr;
			} else {
	    		$newStr += $buf[$i];
			if( $i < size($buf)-1 ) {
			    $newStr += ".";
    	return $newStr;

	global proc rmanOutputDelayedReadArchive()
    	// Find the object context within which this script is being called.
    	string $object = `rman ctxGetObject`;

    	// Get the value of the draFile attr.
    	string $attr = `rmanGetAttrName "draFile"`;
    	string $drafile = `getAttr ($object + "." + $attr)`;

    	// Check whether the file should be treated as a sequence
    	$attr = `rmanGetAttrName "draUseSequenceNumber"`;
    	int $doSeq = `getAttr ($object + "." + $attr)`;

    	if( $doSeq ) {
			// Replace the frame number in the file name with the current frame.
			$attr = `rmanGetAttrName "draSequenceNumber"`;
			int $seqNum = `getAttr ($object + "." + $attr)`;
			$drafile = `replaceFrameNumber $drafile $seqNum`;
    	// Get the bounding box from the maya shape node, which we'll assume 
    	// encompasses the RIB archive.  RenderMan wants the bbox to be in 
    	// centimeters in object space.
    	string $curUnit = `currentUnit -q -linear`;
    	currentUnit -linear "cm";  // temporarily change to centimeters
    	float $bbSize[3] = `getAttr ($object + ".boundingBoxSize")`;
    	float $bbMin[3], $bboxMax[3];
    	$bbMin[0] = -$bbSize[0]/2;
    	$bbMin[1] = -$bbSize[1]/2;
    	$bbMin[2] = -$bbSize[2]/2;
    	$bbMax[0] = $bbSize[0]/2;
    	$bbMax[1] = $bbSize[1]/2;
    	$bbMax[2] = $bbSize[2]/2;
    	currentUnit -linear $curUnit;

    	RiProcedural "DelayedReadArchive" $drafile $bbMin[0] $bbMax[0] $bbMin[1] $bbMax[1] $bbMin[2] $bbMax[2];

 7 — RENDER!

Finally, template or delete the original teapot, and render. Try instancing the cube, you can make an army of lockstep teapots.


In the first step, the teapot archive sequence was created by selecting the top node of the hierarchy, and all the teapot pieces went into one archive per frame. If you repeat that step with motion blur enabled in the RenderMan Globals, motion blocks will automatically be written into the archives. Each animated transform or shape in the teapot hierarchy is sampled two times and placed inside a motion block. Note that transforms may be sampled up to six (6!) times if they have an extra motionSamples attribute. We want the motion blocks to live inside the archive because DynamicReadArchives can't be placed inside motion blocks (although this is allowed for regular ReadArchive calls). You still do need to enable motion blur in the globals in order for motion blocks in the archive to have any effect.

Prev | Next



Pixar Animation Studios
Copyright© Pixar. All rights reserved.
Pixar® and RenderMan® are registered trademarks of Pixar.
All other trademarks are the properties of their respective holders.