Dynamic Read Archives |
To get started, let's open the Maya scene, teapot_anim.ma.
(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.
1 GENERATING RIB ARCHIVES |
Open the scene called teapot_anim.ma. The file contains a teapot that walks in place.
- Load the RenderMan For Maya plugin.
- In the outliner, select the node called teapot_solo:tea.
- From the File menu select the options dialog of Export Selection and switch the file type to RIB_Archive.
- Scroll down to the file type specific options, enable Multiple Frames, and type in a starting and ending frame. Frames 1 through 60 cover about one cycle of the walk.
- Also enable the Export Shaders checkbox.
- Click the Export Selection button and browse to a folder where you want to stash the sequence, and type a name, like "teapot". The frame and rib extension will automatically be appended.
world_ref has been implemented to embody a reference world coordinate system that's safe within archives for Maya projections, bumps, etc.
2 CREATE A STANDIN |
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.
3 NEW SETTINGS |
Let's put three new settings on our cube transform node that will allow us to control the archive name and sequence number.
- draFile A file browser control that lets us pick a rib archive file.
- draUseSequenceNumber A checkbox that indicates that the archive file should be treated as a sequence.
- draSequenceNumber A number that will be driven by an expression that indicates the current frame of the sequence.
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
4 ADDING SETTINGS TO THE STANDIN |
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; } }
5 LOOP THE SEQUENCE |
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:
pCubeShape1.rman__param___draSequenceNumber=frame%60Now
6 THE DELAYED READ ARCHIVE SCRIPT |
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-cubeRfM 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.
8 WHAT ABOUT MOTION BLUR? |
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.
Pixar Animation Studios
|