RfM
Sample RiMel Scripts III
Particles & Procedural "RunProgram"


return to main index



Introduction

This tutorial demonstrates the use of a procedural primitive, or helper app as they are often called, to generate an arbitary number of points in order to enhance the appearance of a particle simulation - figures 1 and 2.



Figure 1
83 particles in Maya


Figure 2
415,000 points generated by the procedural primitive


Three scripts (listings 1, 2 and 3) implement the addPoints interface shown in below.



Figure 3


The python script shown in listing 4 implements the procedural primitive. It imports a module called pnoise. The python script for the module can be found in listing 1 of the tutorial,
    Noise: Perlin Improved Noise

Copies of listings 1, 2 and 3 should be saved in the readers RfM_mel directory. The two python scripts addPoints.py and pnoise.py should be saved in the RfM_python directory.


Applying the Procedural Primitive
  1. Create a particle emitter.
  2. Select a few particles.
  3. Enter "addPointsUI();" in the script window.
  4. Select the shape tab of the particles.
  5. Adjust the sliders of the interface and render the scene.


Listing 1 (addPointsUI.rman)


rman "-version 1" {
Declare param {int ap_num} {
    label "Number"
    subtype slider
    range {10 100000 10}
    description "Number of extra particles."
    }
Declare param {float ap_dia} {
    label "Diameter"
    subtype slider
    range {0 1 .001}
    description "Width of each particle."
    }
Declare param {float ap_noisiness} {
    label "Noisiness"
    subtype slider
    range {0.5 20 0.1}
    description "Controls the pattern of extra points."
    }
Declare param {float ap_dist} {
    label "Distribution"
    subtype slider
    range {0.1 10 .01}
    description "Expands and contracts the extra points."
    }
Declare param {string ap_script} {
    label "Script"
    description "Name of the back-end python procedural primitive."
    subtype file
    range {*.py}
    }
}


Listing 2 (addPointsUI.mel)


global proc addPointsUI() 
{
string $selected[] = `ls -sl`;
int $i, $j;
  
for($i=0; $i < size($selected); $i++) {
    string $shp[] = `listRelatives -shapes $selected[$i]`;
    string $shapeName = $shp[0];
    string $attr = `rmanGetAttrName "preShapeScript"`;
  
    rmanAddAttr $shapeName $attr "addPointsRI";
        
    $attr = `rmanGetAttrName "ap_num"`;
    rmanAddAttr $shapeName $attr "1000";
  
    $attr = `rmanGetAttrName "ap_dia"`;
    rmanAddAttr $shapeName $attr "0.01";
  
    $attr = `rmanGetAttrName "ap_noisiness"`;
    rmanAddAttr $shapeName $attr "3";
  
    $attr = `rmanGetAttrName "ap_dist"`;
    rmanAddAttr $shapeName $attr "1.0";
  
    $attr = `rmanGetAttrName "ap_script"`;
    // NOTE: 
    // the path to the python script will require editing
    string $default = "/Users/mkesson/Documents/maya/projects/RfM_python/";
    
    rmanAddAttr $shapeName $attr ($default + "addPoints.py");
    }
}


Listing 3 (addPointsRI.mel)


global proc addPointsRI()
{
// Get the name of the shape node
string $shapeNode = `rman ctxGetObject`;
  
// Get the name of the transform node
string $parents[] = `listRelatives -parent $shapeNode`;
string $tformNode = $parents[0];
string $attr;
  
$attr = `rmanGetAttrName "ap_num"`;
int $ap_num = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "ap_dia"`;
float $ap_dia = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "ap_noisiness"`;
float $ap_freq = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "ap_dist"`;
float $ap_dist = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "ap_script"`;
string $ap_script = `getAttr($shapeNode + "." + $attr)`;
string $inputs = $ap_num + " " + $ap_dia + " " + $ap_freq + " " + $ap_dist + " ";
  
int     $num = `particle -q -ct $tformNode`; 
print("Number of particles is " + $num + "\n");
// Query the particle positions
for($n = 0; $n < $num; $n++) {
    $part = $tformNode + ".pt[" + $n + "]";
    $pos = `getParticleAttr -at position $part`;
    seed($n);
    RiTransformBegin();
        RiTranslate($pos[0], $pos[1], $pos[2]);
        $angle = rand(-180.0, 180.0);
        RiRotate($angle, rand(-1.0, 1.0), rand(-1.0, 1.0), rand(-1.0, 1.0));
        // On Linux and MacOSX use "/usr/bin/python " instead of "python "
        RiProcedural("RunProgram","python " + $ap_script,
                     -$ap_dist,$ap_dist,
                     -$ap_dist,$ap_dist,
                     -$ap_dist,$ap_dist,
                     $inputs + $n);
    RiTransformEnd();
    }
RiAttribute "visibility" "int camera" 0;
}


Listing 4 (addPoints.py)


import sys, random, math
from pnoise import pnoise
  
inputs = sys.stdin.readline()
  
while inputs:
    items = inputs.split()
    pixels = float(items[0])
    num = int(items[1])
    dia = float(items[2])
    freq = float(items[3])
    size = float(items[4])
    sed = int(items[5])
    
    random.seed(sed)
    print 'Points "P" ['
    for n in range(num):
        x = random.random() * freq * random.uniform(0.8, 1.3)
        y = random.random() * freq * random.uniform(0.8, 1.3)
        z = random.random() * freq * random.uniform(0.8, 1.3)
  
        x = pnoise(x,y,z) * size
        y = pnoise(y,x,z) * size 
        z = pnoise(z,x,y) * size         
        print '%1.3f %1.3f %1.3f' % (x,y,z)
    print '] "constantwidth" [%1.3f]' % dia    
    sys.stdout.write('\377')
    sys.stdout.flush()
    
    inputs = sys.stdin.readline()





© 2002- Malcolm Kesson. All rights reserved.