RenderMan: Dynamic Secondary Geometry


 The procedural techniques presented in this project use Pixar's custom MEL procedures (part of RenderMan for Maya) to create secondary geometry at "render-time". Using the Pixar procedures, rmanGetAttrName() and rmanAddAttr(), a Mel script can conveniently create the widgets described by a .rman script and automatically add them to an "Extra RenderMan Attributes" panel. At render-time a second Mel script can easily query the widgets and use their values with one or more RiMel procedures to produce a final image. 

 

Breakdown


 
 
 

Creating the Interface:

The interface is created through the rman and UI Scripts.

 

How The Interface Works: Offset From Mesh Origin

This offsets the RIB Archive object off of the base object.

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

UI SettingsAlign To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 1.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 1.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

 

How The Interface Works: Use Normals For Orientation

This aligns the RIB archive object to align to the "Normal" orientation of the vertices of the base object.

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

UI Settings:Align To Normal: No Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: No
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

 

How The Interface Works: Min/Max Radius

This adjusts the Min and Max radius of the RIB Archive objects. 

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10

Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.20 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.20

Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

 

How The Interface Works: Number of Objects (Leaves)

This decreases the amount of, or density, RIB Archive objects on the vertices of the base object.

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 15.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 15.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

 

How The Interface Works: Random Y Rotation

This randomly rotates the RIB Archive objects in the Y direction. 

UI Settings: Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:


Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 1.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 1.00

 

How The Interface Works: Scattering Distance

This scatters the RIB Archive objects off the base object. 

UI Settings: Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 0.00 Random Y Rotate: 0.00

UI Settings:


Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 0.00
Random Y Rotate: 0.00

UI Settings:Align To Normal: Yes Min Radius: 0.10 Max Radius: 0.10 Offset: 0.00 Number of Objects: 1.00 Scatter Distance: 1.00 Random Y Rotate: 0.00

UI Settings:

Align To Normal: Yes
Min Radius: 0.10
Max Radius: 0.10
Offset: 0.00
Number of Objects: 1.00
Scatter Distance: 1.00
Random Y Rotate: 0.00

RMan File:

# maya/projects/RfM_mel/Scatter.rman file rman "-version 1" {

Declare param {string scatter_path} {

label "Rib Archive"
description "Leave empty if you wish to use spheres."
subtype file
range {*.rib}
}


Declare param {float scatter_offset} {

label "Offset from Mesh Origin"
subtype slider
range {0 10}
description "Enables archives to zoom in and out of the mesh."
}


Declare param {int scatter_normals} {

label "Use Normals for Orientation"
description "Aligns an archives Y axis to the mesh normal."
subtype switch
}


Declare param {float scatter_minR} {

label "Min Radius"
subtype slider
range {0.001 5}
description "Min Radius of the vertex spheres."
}


Declare param {float scatter_maxR} {

label "Max Radius"
subtype slider
range {0.001 15}
description "Max Radius of the vertex spheres."
}


Declare param {int scatter_num} {

label "Number Of Leaves"
subtype slider
range {1 100 1}
description "Number of spheres or archives per vertex."
}


Declare param {float scatter_yrot} {

label "Random Y Rotation"
subtype slider
range {0 360}
description "Randomized axial rotation of each archive."
}


Declare param {float scatter_scatterR} {

label "Scattering Distance"
subtype slider
range {0 10}
description "Radial scattering of spheres or archives."
}

}


UI.mel File

// Generated by Cutter v7.7.2 at 1:43:31 on the 2.8.2017.
// The source document on which this mel script is based is,
// "/home/kvenem20/mount/stuhome/maya/projects/RfM_mel/scatter.rman"
// Cutter software by Malcolm Kesson (all rights reserved).
//
// Post Transform User Interface (UI) Mel Script
//
global proc scatterUI()
{
string $selected[] = `ls -sl`;
int $i;

for( $i=0; $i < size($selected); $i++ );


{
string $attr = `rmanGetAttrName "postTransformScript"`;
string $transformName = $selected[$i];

// "Connect" to the mel script that calls
// Pixar's custom Ri mel procedures.
rmanAddAttr $transformName $attr "scatterRI";

$attr = `rmanGetAttrName "scatter_path"`;
rmanAddAttr $transformName $attr "";

$attr = `rmanGetAttrName "scatter_offset"`;
rmanAddAttr $transformName $attr "";

$attr = `rmanGetAttrName "scatter_normals"`;
rmanAddAttr $transformName $attr "0";

$attr = `rmanGetAttrName "scatter_minR"`;
rmanAddAttr $transformName $attr "";

$attr = `rmanGetAttrName "scatter_maxR"`;
rmanAddAttr $transformName $attr "";

$attr = `rmanGetAttrName "scatter_num"`;
rmanAddAttr $transformName $attr "";

$attr = `rmanGetAttrName "scatter_yrot"`;
rmanAddAttr $transformName $attr "";

$attr = `rmanGetAttrName "scatter_scatterR"`;
rmanAddAttr $transformName $attr "";

}


}

RI.mel File

// Generated by Cutter v7.7.2 at 1:43:45 on the 2.8.2017.
// The source document on which this mel script is based is,
//
"/home/kvenem20/mount/stuhome/maya/projects/RfM_mel/scatter.rman"
// Cutter software by Malcolm Kesson (all rights reserved).
//
// Post Transform Mel Script
//
global proc scatterRI() {
// Get the name of the transform node
string $tformNode = `rman ctxGetObject`;


// The node may hava a number in its name that we can use to set the random number generator
int $nodeNumber = `match "[0-9]+" $tformNode`;
if($nodeNumber != "") {

seed(int($nodeNumber));{
}{


// Bounding box is only relevant if the transform node is not a
group. string $children[] = `listRelatives -children $tformNode`;
string $shapeNode = $children[0];
float $bb_width = -1, $bb_height = -1, $bb_depth = -1;
if(size($children) == 1) {

$bb_width = `getAttr ($shapeNode + ".boundingBoxSizeX")`;
$bb_height = `getAttr ($shapeNode + ".boundingBoxSizeY")`;
$bb_depth = `getAttr ($shapeNode + ".boundingBoxSizeZ")`;
}


string $attr;
$attr = `rmanGetAttrName "scatter_path"`;
string $scatter_path = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_offset"`;
float $scatter_offset = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_normals"`;
int $scatter_normals = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_minR"`;
float $scatter_minR = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_maxR"`;
float $scatter_maxR = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_num"`;
int $scatter_num = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_yrot"`;
float $scatter_yrot = `getAttr($tformNode + "." + $attr)`;

$attr = `rmanGetAttrName "scatter_scatterR"`;
float $scatter_scatterR = `getAttr($tformNode + "." + $attr)`;

// Use of Pixar's custom RenderMan Studio procedures begins here.

// To use the shader of a "Custom Shading Group that can be
// assigned to the transform node of your geometry.
RiArchiveRecord("structure", "RLF Inject SurfaceShading");

vector $verts[];
getVertices($tformNode, $verts);

vector $norms[];
getNormals($tformNode, $norms);
if(size($verts) == 0 || size($norms) == 0)

return;


int $n;
int $vertexCount = 0;

vector $vert, $norm;
float $rot[], $x, $y, $z, $yangle;

for($n = 0; $n < size($verts); ($n = $n + $scatter_num)) {

//Randomize size of objects
float $size = rand($scatter_minR, $scatter_maxR);
//Create Scatter
float $scatterx = rand(-$scatter_scatterR, $scatter_scatterR);
float $scattery = rand(-$scatter_scatterR,
$scatter_scatterR);
float $scatterz = rand(-$scatter_scatterR,
$scatter_scatterR);

$x = $vert.x;
$y = $vert.y;
$z = $vert.z;

// Apply position offset
$x += $vert.x * $scatter_offset;
$y += $vert.y * $scatter_offset;
$z += $vert.z * $scatter_offset;



RiAttributeBegin();
RiTranslate($x, $y, $z);
RiTranslate($scatterx, $scattery, $scatterz);
// Alignment to the mesh formal
if($scatter_normals) {
$norm = $norms[$n];
$rot = aimY($norm);
RiRotate($rot[1], 0,0,1);
RiRotate($rot[0], 1,0,0);
}
// Random Y Rotation
if($scatter_yrot > 0) {
$yangle = rand(-$scatter_yrot, $scatter_yrot);
RiRotate($yangle, 0, 1, 0);
}
// the randomized scaling
RiScale($size, $size, $size);
if(size($scatter_path) == 0) {
RiRotate(-90,1,0,0);
RiArchiveRecord("comment", "\nCone .2 0.05 360");
}
else
{
RiRotate($rot[0]+$rot[1], 0,1,0);
float $tint = float($vertexCount)/size($verts);
RiAttribute("user", "float tint", $tint);
RiReadArchive($scatter_path);
}
RiAttributeEnd();
}
}


// A utility to create a rib path for an archive to be saved
// in the project directories "data" folder.
global proc string getArchivePath(string $nodename) {

string $projpath = `workspace -q -rootDirectory`;
string $datapath = $projpath + "data/";
string $scenename = `file -q -sceneName -shortName`;
int $frame = `currentTime -q`;
string $fstr = "0" + $frame;
if($frame < 10)
$fstr = "000" + $frame;
else if($frame < 100)
$fstr = "00" + $frame;
$ribpath = $datapath + $nodename + "." + $fstr + ".rib";
return $ribpath;
}