Coalescing Jar (Mesh Query)

MEL give us the power to have access to every single information about objects; such as position of every vertex or vertex normals etc. We can store these information in arrays and modify them or use them to produce nice effects. I used these information to create a melting and coalescing effect on an object.

Defining Functions (Precedures)
 global proc getVertices(string $tnode, vector $data[])
 {
 int $count = size($data);
 int $num[] = `polyEvaluate -v $tnode`; 
 string  $shp[] = `listRelatives -shapes $tnode`;
 string  $shape = $shp[0];
 float   $pos[];
   
 for($n = 0; $n < $num[0]; $n++) {
     $vert = $shape + ".vtx[" + $n + "]";
     //$pos = `pointPosition -local $vert`;
     $pos = `pointPosition -local $vert`;
     $data[$count] = <<$pos[0], $pos[1], $pos[2]>>;
     $count++;
     }
 }
 					
 //---------------------------------------------------
 										
 global proc vector getAverageNormal(float $norms[]) 
 {
 float   $x = 0, $y = 0, $z = 0;
 int $numComps = size($norms);
 int $numNorms = $numComps/3;
   
 if($numNorms == 1)
     return <<$norms[0],$norms[1],$norms[2]>>;
 for($n = 0; $n < $numComps - 3; $n += 3) {
     $x += $norms[$n];
     $y += $norms[$n + 1];
     $z += $norms[$n + 2];
     }
 return <<$x/$numNorms, $y/$numNorms, $z/$numNorms >>;
 }
   
 //---------------------------------------------------
   
 global proc getNormals(string $tnode, vector $data[])
 {
 int $count = size($data);
 int $num[] = `polyEvaluate -v $tnode`; 
 string  $shp[] = `listRelatives -shapes $tnode`;
 string  $shape = $shp[0];
 float   $norms[];
 vector  $ave;
   
 for($n = 0; $n < $num[0]; $n++) {
     $vert = $shape + ".vtx[" + $n + "]";
     $norms = `polyNormalPerVertex -q -xyz $vert`;
     $ave = getAverageNormal($norms);
     $data[$count] = <<$ave.x, $ave.y, $ave.z>>;
     $count++;
     }
 }
 
I used three main functions for the query:

getVertices( string , vector array )
A void function which gets a node and passes its vertex positions by reference as an array.

getAverageNormal( float array )
A vector function which returns an average vector from an array of vectors.

getNormals( string , vector array )
Anothe void function which passes by reference the avarage vertex normals of a node.

You can see the codes of these three functions on the left.
Pre-Shape Scripts

Renderman has the ability to modify the informations of an object before the definition of its shape node with a script which is called pre-shape script. This is where the magic happens.

I wrote a script which queries the data of the vertices, finds the minimum and maxinum value of the Y components of the vertex positions then based on a user-defined value which I called melt moves down all the vertices. But if the vertecies are going to move below the minimum Y value it will prevent them and make them stop at that level.

For a more interesting effect it queries the normal data of vertecies and based on their relative height to the minimum Y, adds the X and Z values of their normal to their position. This causes the verticies to move "away" from the surface. I used Renderman Bloobies to create a implicit surface from the verticies of the object.

Click on the image to see the whole animation.


global proc meltRI()
  
{
  
// Get the name of the shape node
string $shapeNode = `rman ctxGetObject`;
  
// Get the name of the transform node
string $parents[] = `listRelatives -parent $shapeNode`;
string $tnode = $parents[0];
  
// The node may hava a number in its name that we can use to set the
// random number generator
int    $nodeNumber = `match "[0-9]+" $shapeNode`;    
if($nodeNumber != "") {
    seed(int($nodeNumber));
    }
  
string $attr;
$attr = `rmanGetAttrName "melt_radius"`;
float $rad = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "melt_visibility"`;
int $vis = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "melt_scale"`;
int $uniform = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "melt_jitter"`;
float $jitter = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "melt_melt"`;
float $melt = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "melt_meltHeight"`;
float $percent = `getAttr($shapeNode + "." + $attr)`;
  
$attr = `rmanGetAttrName "melt_scatter"`;
float $scatter = `getAttr($shapeNode + "." + $attr)`;
  
  
  
// main Script -----------------------
  
vector $verts[];
vector $norms[];
float $yArray[];
  
getVertices($tnode, $verts);
getNormals($tnode, $norms);
  
float $sx = `getAttr ($tnode + ".sx")`;
float $sy = `getAttr ($tnode + ".sy")`;
float $sz = `getAttr ($tnode + ".sz")`;
seed (1);
  
//finding the minimum and maximum y value
  
for($j = 0; $j < size($verts); $j++)
{
    vector $w = $verts[$j];
    $yArray[$j] = $w.y;
    
} //end $j loop
  
float $sortArray[];
$sortArray = sort ($yArray);
float $minY = $sortArray[0];
float $maxY = $sortArray[size($sortArray) - 1];
float $meltHeight = (abs($maxY-$minY) * $percent / 100) + $minY;
  
//------------------------------------
  
vector $myVerts[];
  
for($n = 0; $n < size($verts); $n++) 
{
    vector $v = $verts[$n];
    vector $norm = $norms[$n]/mag($norms[$n]);
    ;
    //vector $norm = `normalize ($norms[$n])`;
    
    float $jitterx;
    float $jittery;
    float $jitterz;
    float $yy;
    
    if(($v.y - $melt) < $minY)
    {
        $yy = $minY;
    }
    else
    {
        $yy = $v.y - $melt;
    }
    float $yDif;
    if ($yy < $meltHeight)
    {
        $yDif = $meltHeight * (1 - $yy/$meltHeight);
        $jitterx = $jitter * (rand (0.0 , 1.0)-0.5);
        $jittery = $jitter * (rand (0.0 , 1.0)-0.5);
        $jitterz = $jitter * (rand (0.0 , 1.0)-0.5);
    }
    else
    {
        $yDif = 0;
        $jitterx = 0;
        $jittery = 0;
        $jitterz = 0;
    }
  
    
    vector $myVertN = <<
                        ($v.x + pow($yDif,2) * $melt/100 * ($jitterx + $norm.x * $scatter)),
                        ($yy),
                        ($v.z + pow($yDif,2) * $melt/100 * ($jitterz + $norm.z * $scatter))
                        >>;
    
    $myVerts[$n] = $myVertN;
    
} // end $n loop
    
string $path = getenv("HOME");
$path += "/meshToBlobby2.rib";
meshToBlobbyAli($path, $rad, $myVerts);
RiReadArchive ($path);
    
    if(!$vis)
    {
        RiAttribute ("visibility" , "int camera" , 0);            //turns off visibility
        RiAttribute ("visibility" , "int transmission" , 0);    //turns off shaddows
        RiAttribute ("visibility" , "int camera" , 0);            //turns off occlusion
    }
}

Final Thoughts

This method could be used to scatter not only simple object, but very complex archives allover a surface. It has lots of potentials to change information of points on a mesh while rendering.