C Helper Applications

The C language has a strong and useful application to the 3D community in the creation of so-called "Helper Apps", C executables which can be called and run by the MTOR renderer. This addignment introduced the C language, and provided us the ability to update our previous palm generator and add extras like varying width, color, and normals. The ultimate goal (in a quarter with 10 weeks perhaps) would be to integrate the MEL script and the C app to work together, the MEL as a proxy preview, the Helper App as the actual render information

   


#include <stdio.h>
void add(float *ptr)
{
*ptr=2+3;
}

void main ()
{
float n = 1.0;
float answer = 0.0;
printf("The value of answer is %f\n",answer);
add(&answer);
printf("Dereferencing the pointer we have %f\n",answer);

}

 

 

#include <stdio.h>
void main (int argv, char **argc)
{
printf("You typed %d items\n",argv);
printf("The first item is %s/n", argc[0]);
printf("The first char of the first item is %c/n", argc[0][0]);
printf("Thank heavens its Thursday\n");
}


Two sample C scripts we wrote to learn the syntax of the language. Most importantly, the concept of pointers (passing the memeroy address of a variable rather than its numeric value) was introduced



#include <stdio.h>

void main ()
{
char buffer[256];
float detail, radius, depth, height;
int num;

while (gets(buffer))

{
sscanf(buffer,"%f %d %f %f %f", &detail, &num, &radius, &depth, &height);
int n;
for(n = 0; n < num; n++)
{
printf("Translate 0 %f 0\n", radius/4);
printf("Sphere %f %f %f 360\n", radius, depth, height);
}
printf("%c", '\377');
fflush(stdout);
}

}

The first genuine progress towards writing a Help App, getting information entered by the user (STDIN). This is extremely useful because MTOR relies on these kind of print statements shown to receive information from the Help App at render time.

 

// These reproduce the data types found in MEL
typedef struct {
float x, y, z;
} vector;

float srandBetween(unsigned seed, float min, float max);
float randBetween(float min, float max);
vector subtract(vector a, vector b);
vector add(vector a, vector b);
vector scalar(vector a, float s);
float flerp(float a, float b, float pct);

 

 

#include "library.h"
#include <stdlib.h>
#include <math.h>
#include <stdio.h>

float srandBetween(unsigned seed, float min, float max)
{
srand(seed);
return (float)rand()/RAND_MAX * (max - min) + min;
}
//_____________________________________________________

float randBetween(float min, float max)
{
return (float)rand()/RAND_MAX * (max - min) + min;
}

//_____________________________________________________
vector subtract(vector a, vector b)
{
static vector out;
out.x = a.x - b.x;
out.y = a.y - b.y;
out.z = a.z - b.z;
return out;
}
//_____________________________________________________
vector add(vector a, vector b)
{
static vector out;
out.x = a.x + b.x;
out.y = a.y + b.y;
out.z = a.z + b.z;
return out;
}
//_____________________________________________________
vector scalar(vector a, float s)
{
a.x *= s;
a.y *= s;
a.z *= s;
return a;
}

//_____________________________________________________
float flerp(float a, float b, float pct)
{
return (1.0 - pct) * a + pct * b;
}



Before getting "Hot and Heavy" into the visual aspect of scripting we wrote a small library of predefined functions to include when writing our later code. C has no knowledge of MEL's so called vector variable (a floating point array of 3 values) so we defined this variable using typedef . We also wrote several small functions for adding subtracting and multiplying vectors to save time as well. Another flaw in C is that the rand function returns an integer between 0 and RAND_MAX, a *very* large number. To combat this we created our own version, randBetween, which allows us to specify a range for the random numbers and can return floats. FInally, I wrote the srandbetween to be able to seed the randbetween generator to receive predicatable results. This was essential in order to animate the plams and have them render consistenly every frame (more on this below)...



  The first test of a simple helper app was to use a bounding box in maya as a template for generating many spheres within it. Because the C app send the information to the renderer in memory (the instructions are never stored as or part of a .rib file) the render time, even for tens of thousands of spheres, is very fast.  

/*
The Ribbox code would be the following line:

Procedural \"RunProgram\" \[\"H:/vsfx705/C/spheres/spheres\" \"100 .05 2 2 2\"\] \[-1 1 -1 1 -1 1\]
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "H:/vsfx705/C/lib/library.h"

void main ()
{
char buffer[256];
float detail, radius, width, depth, height;
int num;

while (gets(buffer))

{
//Get the data from prman
sscanf(buffer,"%f %d %f %f %f %f", &detail, &num, &radius, &width, &height, &depth);

int n;
for(n = 0; n < num; n++)
{
//get a random location within the bounding box
float x = randBetween(-width/2,width/2);
float y = randBetween(-height/2,height/2);
float z = randBetween(-depth/2,depth/2);
//create a randomly translated sphere
printf("AttributeBegin\n");
printf("Translate %f %f %f\n", x,y,z);
printf("Sphere %f %f %f 360\n", radius, -radius, radius);
printf("AttributeEnd\n");

}
//tell prman we're done
printf("%c", '\377');
fflush(stdout);
}

}

 

 

 


/*

Procedural \"RunProgram\" \[\"H:/vsfx705/C/spheres/spheres\" \"100 .05 2 2 2\"\] \[-1 1 -1 1 -1 1\]
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "H:/vsfx705/C/lib/library.h"

void normalize(float pnt[3], float radius)
{
float length = (sqrt((pnt[0] * pnt[0]) +
(pnt[1] * pnt[1]) +
(pnt[2] * pnt[2])))/radius;
pnt[0] /= length;
pnt[1] /= length;
pnt[2] /= length;
}

void main ()
{
char buffer[256];
float detail, radius, width, depth, height;
int num;

while (gets(buffer))

{
//Get the data from prman
sscanf(buffer,"%f %d %f %f %f %f", &detail, &num, &radius, &width, &height, &depth);

int n;
float coordinates[3];
for(n = 0; n < num; n++)
{
//get a random location within the bounding box
coordinates[0] = randBetween(-width/2,width/2);
coordinates[1] = randBetween(-height/2,height/2);
coordinates[2] = randBetween(-depth/2,depth/2);
//create a randomly translated sphere
normalize(coordinates, ((width/2+height/2+depth/2)/3));

printf("AttributeBegin\n");
printf("Translate %f %f %f\n", coordinates[0],coordinates[1],coordinates[2]);
printf("Sphere %f %f %f 360\n", radius, -radius, radius);
printf("AttributeEnd\n");

}
//tell prman we're done
printf("%c", '\377');
fflush(stdout);
}

}

  By normalizing the vector formed by the origin and each of these randomly generated points, the spheres can be constrained to form a spherical mass.    

 

Rather than generating spheres for all of the random points, generating points allows the oppertunity to futher manipulate attrubites such as color...plus they render even faster becuase they are simply point values the MTOR adds a "width" to.

/*
Procedural \"RunProgram\" \[\"H:/vsfx705/C/spheres/spheres\" \"100 .05 2 2 2\"\] \[-1 1 -1 1 -1 1\]
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "H:/vsfx705/C/lib/library.h"

void normalize(float pnt[3], float radius)
{
float length = (sqrt((pnt[0] * pnt[0]) +
(pnt[1] * pnt[1]) +
(pnt[2] * pnt[2])))/radius;
pnt[0] /= length;
pnt[1] /= length;
pnt[2] /= length;
}

void main ()
{
char buffer[256];
float detail, radius, width, depth, height;
int num;

while (gets(buffer))

{
//Get the data from prman
sscanf(buffer,"%f %d %f %f %f %f", &detail, &num, &radius, &width, &height, &depth);

int n;
float coordinates[3];
printf("Points \"P\" [");

for(n = 0; n < num; n++)
{
//get a random location within the bounding box
coordinates[0] = randBetween(-width/2,width/2);
coordinates[1] = randBetween(-height/2,height/2);
coordinates[2] = randBetween(-depth/2,depth/2);
//create a randomly translated point to render
normalize(coordinates, ((width/2+height/2+depth/2)/3));


printf("%f %f %f\n", coordinates[0],coordinates[1],coordinates[2]);
}

printf ("] \"constantwidth\" [%f]\n", radius);
printf("\"Cs\" [");
for(n = 0; n < num; n++)
{
//get a random color value
coordinates[0] = randBetween(0,1);
coordinates[1] = randBetween(0,1);
coordinates[2] = randBetween(0,1);


//add a randomly generated color to the rib statemnet;
printf("%f %f %f\n", coordinates[0],coordinates[1],coordinates[2]);
}

printf("] \n");

//tell prman we're done
printf("%c", '\377');
fflush(stdout);
}

}

       

 


 
/*Procedural \"RunProgram\" \[\"H:/vsfx705/C/spheres/spheres\" \"100 .05 2 2 2\"\] \[-1 1 -1 1 -1 1\]
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "H:/vsfx705/C/lib/library.h"

void normalize(float pnt[3], float radius)
{
float length = (sqrt((pnt[0] * pnt[0]) +
(pnt[1] * pnt[1]) +
(pnt[2] * pnt[2])))/radius;
pnt[0] /= length;
pnt[1] /= length;
pnt[2] /= length;
}

void main ()
{
char buffer[256];
float detail, radius, width, depth, height;
int num;

while (gets(buffer))

{
//Get the data from prman
sscanf(buffer,"%f %d %f %f %f %f", &detail, &num, &radius, &width, &height, &depth);

int n;
float coordinates[3];
printf("Points \"P\" [");
float colorBasis[num][3];
for(n = 0; n < num; n++)
{
//get a random location within the bounding box
coordinates[0] = randBetween(-width/2,width/2);
coordinates[1] = randBetween(-height/2,height/2);
coordinates[2] = randBetween(-depth/2,depth/2);
//create a randomly translated point to render
normalize(coordinates, ((width/2+height/2+depth/2)/3));
//get a random color value based off the random position
colorBasis[n][0]=coordinates[0];
colorBasis[n][1]=coordinates[1];
colorBasis[n][2]=coordinates[2];

printf("%f %f %f\n", coordinates[0],coordinates[1],coordinates[2]);
}

printf ("] \"constantwidth\" [%f]\n", radius);
printf("\"Cs\" [");
for(n = 0; n < num; n++)
{

//add a randomly generated color to the rib statemnet;
printf("%f %f %f\n", colorBasis[n][0],colorBasis[n][1],colorBasis[n][2]);
}

printf("] \n");

//tell prman we're done
printf("%c", '\377');
fflush(stdout);
}

}

  Everything up to now has been based off of point rendering work done by our professor, Malcolm Kesson. I found the random point colors unappealing, so I thought it might be interesting to try to base the point's color off of it's world space position. The code to do this is shown at right...rather than assign a totally random color, an array of three floating point number elements (essentially a matrix of a user specified number of rows with 3 columns, the RGB values). These values were stored in the first loop when position was determined, then later repeated in the color statement. I made the mistake of thinking the values had to be made to conform to a 0 to 1 range, resulting in the first image above. By allowing them to retain the full numeric randomness inherent in their coordinates a natural spectrum is created (bottom).  

 


  Points, of course, are flat so I tried the render with the original box configurationto see some depth.  

 


/*
Procedural \"RunProgram\" \[\"H:/vsfx705/C/spheres/spheres\" \"100 .05 2 2 2\"\] \[-1 1 -1 1 -1 1\]
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "H:/vsfx705/C/lib/library.h"

void normalize(float pnt[3], float radius)
{
float length = (sqrt((pnt[0] * pnt[0]) +
(pnt[1] * pnt[1]) +
(pnt[2] * pnt[2])))/radius;
pnt[0] /= length;
pnt[1] /= length;
pnt[2] /= length;
}

void main ()
{
char buffer[256];
float detail, radius, width, depth, height;
int num;

while (gets(buffer))

{
//Get the data from prman
sscanf(buffer,"%f %d %f %f %f %f", &detail, &num, &radius, &width, &height, &depth);

int n;
float coordinates[3];
printf("Points \"P\" [");
float colorBasis[num][3];
for(n = 0; n < num; n++)
{
//get a random location within the bounding box
coordinates[0] = randBetween(-width/2,width/2);
coordinates[1] = randBetween(-height/2,height/2);
coordinates[2] = randBetween(-depth/2,depth/2);

//create a randomly translated point to render
normalize(coordinates, 1); //turn on for a sphere, off for a box

// the following section scatters the particles in a flat disk shape
/* float randomRadius = randBetween(0, ((width/2+height/2+depth/2)/3));
coordinates[0] *= randomRadius;

coordinates[2] *= randomRadius;
coordinates[1] = (coordinates[2]+coordinates[0])/2;
*/
// the following section scatters the particles in a cone shape
/* float randomRadius = randBetween(0, ((width/2+height/2+depth/2)/3));
coordinates[0] *= randomRadius;
coordinates[1] += randomRadius;
coordinates[2] *= randomRadius;
*/

// the following section scatters the particles in a cylinder shape
float randomRadius = randBetween(0, ((width/2+height/2+depth/2)/3));

coordinates[1] += randomRadius;


//get a random color value based off the random position
colorBasis[n][0]= randBetween(0,1);
//colorBasis[n][0]=coordinates[0]+.2;
colorBasis[n][1]=randBetween(0,1);
// colorBasis[n][1]=coordinates[1]+.2;
colorBasis[n][2]=randBetween(0,1);
// colorBasis[n][2]=coordinates[2]+.2;

printf("%f %f %f\n", coordinates[0],coordinates[1],coordinates[2]);
}

printf ("] \"constantwidth\" [%f]\n", radius);
printf("\"Cs\" [");
for(n = 0; n < num; n++)
{

//add a randomly generated color to the rib statemnet;
printf("%f %f %f\n", colorBasis[n][0],colorBasis[n][1],colorBasis[n][2]);
}

printf("] \n");

//tell prman we're done
printf("%c", '\377');
fflush(stdout);
}

}

 

The Full implementation of the point generator. Depending on which part are commented out, the code at right can produce a cube, sphere, cone, flat disk or cylinder shape full of points. These can be randomly colored, or colored by using world space coordinates

(roll over each image to compare).

 

 



#include <stdio.h>
#include <stdlib.h>
#include "H:/vsfx705/C/lib/library.h"

char* transformation(void);
void blobby(int n);
float randBetween(float min, float max);

char* transformation(void)
{
char transform[] = { "1 0 0 0 0 1 0 0 0 0 1 0 " };

static char out[256];
float x = randBetween(-0.5, 0.5);
float y = randBetween(-0.5, 0.5);
float z = randBetween(-0.5, 0.5);

sprintf(out, "%s %1.3f %1.3f %1.3f 1\n", transform, x, y, z);
return out;
}

void blobby(int num)
{
char ellipsoid_ID[] = "1001 ";
int n, index = 0, add_ID = 0, blob_count = num;

printf("TransformBegin\n");
printf("Blobby %d [\n", num);

// begin the code block
for(n = 0; n < num; n++, index+=16)
printf("%s %d\n", ellipsoid_ID, index);
// end the code block

// define the blobby operator and indices of
// the blobs forming a set ie. group
printf("%d %d ", add_ID, blob_count);
for(n = 0; n < num; n++)
printf("%d ", n);
printf("]\n");
// end of the operator block

// begin the transforms block
printf("[\n");
for(n = 0; n < num; n++)
printf("%s\n", transformation());
printf("]\n");
// end of the transforms block

// begin the depth map block
printf("[ \"\" ]\n");
// end of depth map block
printf("TransformEnd\n");
}

void main()
{
float detail;
int frame, num;
char buffer[256];

while(gets(buffer))
{
sscanf(buffer, "%f %d %d", &detail, &frame, &num);
srand(frame);
blobby(num);
printf("%c", '\377');
fflush(stdout);
}
}

  Just for FUN I also did A brief excercise in creating MTOR blobbie surfaces using C. All of these tutorials are under Malcolm Kesson's CG References and Tutorials. URL: http://sfdm.ca.scad.edu/vsfx/faculty/malcolm/tutorials/index.html    

 


int $n;
for($n = 0; $n < 30; $n++)
{
string $Cube[] = `polyCube`;
string $nextCube = $Cube[0];
//translate, move pivot to base, scale
move 0 .5 0;
xform -os -piv 0 -0.5 0;
scale 2 2 2;


//freeze transforms
makeIdentity -apply true -t 1 -r 1 -s 1;

//add attributes the tclbox can use
addAttr -ln leafCount -at long -min 1 -max 150 -dv (rand(10, 50)) -k true $nextCube;

addAttr -ln leafCv -at long -min 4 -max 13 -dv 37 -k true $nextCube;

addAttr -ln leafBase -at double -min .01 -max 1 -dv .1 -k true $nextCube;

addAttr -ln leafTip -at double -min .005 -max .5 -dv .005 -k true $nextCube;

addAttr -ln leafColor -at double3 -k true $nextCube;

addAttr -ln red -at double -min 0 -max 1 -dv (rand(0.05, 0.3)) -parent leafColor -k true $nextCube;

addAttr -ln green -at double -min 0 -max 1 -dv (rand(0.3, 0.6)) -parent leafColor -k true $nextCube;

addAttr -ln blue -at double -min 0 -max 1 -dv (rand(0, 0.1)) -parent leafColor -k true $nextCube;

addAttr -ln leafX -at double -min .01 -max 10 -dv (rand(.5,2.5)) -k true $nextCube;

addAttr -ln leafY -at double -min .01 -max 10 -dv (rand(.5,2.5)) -k true $nextCube;

addAttr -ln leafDroop -at double -min -5 -max 5 -dv (rand(1, 10)) -k true $nextCube;

move (rand(-10, 10)) 0 (rand(-10, 10));
}
 

Enough of that, our next task was to begin to transfer the Code from our original MEL script generator (Click here to see that Page). This would have been a nightmarishly long process except for two things: we created variables in C to mimic those in MEL such as a typedef for vector, and we had a highly intellignet and ridiculously motivated professor who helped and/or personally did much of the transition to C for us.

 

We decided to base the palm generator off of a poly cube proxy object that could serve as a bounding box in conjunction with a ribbox combined with a tcl box to call the external App we were writing. A mel script was created to generate cubes with attributes created for them. This would allow the user to control a variety of the parameters of the appearance of a rendered palm.

 

 

 

When rendered to show the palm (with opacity left in the box to shown its relationship) an error is apparent because the palm gorws outside it's bounding box. We worked to fix minor issues like this throught the project.

 

The code needed to interface MAYA and MTOR with our external Application is shown at right. The highlights are referencing the attributes we created for each cube in the tcl box and using this to drive the palm's creation. We had already built randomness into the MEL script to generate variations in multiple palms. The ribbox adds a skewing animation to simulate a wind effect and is explained later. The external TCL file return to the renderer the RunProgram command that starts the external C app. The above plant was a very early test of this fairly complex system.

 
#####################################
#TCLbox Code:
source H:/vsfx705/C/palmetta1/palmetta.tcl

set node [getTransformNode $OBJPATH]
set seed [getseed $node]
set leafCount [mattr "$node.leafCount" $F]
set leafCv [mattr "$node.leafCv" $F]
set leafBase [mattr "$node.leafBase" $F]
set leafTip [mattr "$node.leafTip" $F]
set red [mattr "$node.leafColor.red" $F]
set green [mattr "$node.leafColor.green" $F]
set blue [mattr "$node.leafColor.blue" $F]
set leafX [mattr "$node.leafX" $F]
set leafY [mattr "$node.leafY" $F]
set leafDroop [mattr "$node.leafDroop" $F]

set ribstring [getRibString $seed $leafCount $leafCv $leafBase $leafTip $red $green $blue $leafX $leafY $leafDroop]

###################################
#RIBBOX code:
Skew [expr [expr 45.0 * [expr noise($pct)]] * sin([ expr [expr [mattr "$node.tx" $f] + $pct ] / 3])] 0 1 0 1 0 0
Skew [expr [expr 30.0 * [expr noise($pct)]] * sin([ expr [expr [mattr "$node.tz" $f] + $pct ] / 3])] 0 1 0 0 0 1
Surface \"plastic\" \"Kd\" 1
#leafRed is $red
$ribstring
Opacity 0 0 0

##################################
#PALMETTA.tcl

proc getseed {geoname} {
regsub -all {[^0-9]} $geoname "" out
return $out
}
proc getTransformNode { mayapath } {
set item [split $mayapath |]
return [lindex $item 1]

}
proc getRibString {seed leafCount leafCv leafBase leafTip red green blue leafX leafY leafDroop} {
set path "\"H:/vsfx705/C/palmetta1/palmetta\""
set data "\"$seed $leafCount $leafCv $leafBase $leafTip $red $green $blue $leafX $leafY $leafDroop\""
set bounds "\[-1 1 0 2 -1 1\]"
return "Procedural \"RunProgram\" \[$path $data\] $bounds"
}

#puts [getRibString 55]

 

 

   


 
#include <stdio.h>
       #include "plant.h"              
int main()
         {
         char buffer[512];
         int n;
         vector end;
         PlantDB db;
while(gets(buffer))
   {
   // 12 inputs, therefore, RIB must provide 11 values
   sscanf(buffer, "%f %d %d %d %f %f %f %f %f %f %f %f", 
          &db.pixels, &db.seed, &db.leafCount, &db.leafCv, 
          &db.leafBase, &db.leafTip,
          &db.leafRGB.x, &db.leafRGB.y, &db.leafRGB.z, 
          &db.leafX, &db.leafY,
          &db.leafDroop);
   // Generate a single leaf
   end.x = srandBetween(db.seed,0, db.leafX);
   end.y = db.leafY;
   end.z = 0.0;
   for(n = 0; n < db.leafCount; n++)
   {
   printf("TransformBegin\n");
   printf("Rotate %f 0 1 0\n", randBetween(0,360));
   leaf(db, end);
   printf("TransformEnd\n");
   }
   printf("%c", '\377');
   fflush(stdout);
   }
   return 0;
   }
 
  A render without randomness of color and normals..... The code at right represents the main help app function (the actual executable, which can be understood as a bridge or doorway between our MTOR coding, and the external C file). It takes the data originally collected from the cube by the TCLBOx that is then picked up by the Ribbox and sent to the TCL file. This TCL code sets up several supporting functions to collect the data in Maya. It has among these a function called getRibString which then calls the C file while passing the user data in. IT IS VERY IMPORTANT to note the srandBetween() function call when initializing end.x This is a function I wrote that can seed the rand() function which allows the plants to be animated. If random end points for the leaves weer calculated each time the leaves will be different every frame. This allows the same set of random end points to be generated per plant every frame.    


 
// Declarations of functions implemented in
// plant.c
#include "H:/vsfx705/C/lib/library.h"

typedef struct {
float pixels;
unsigned seed;
int leafCount;
int leafCv;
float leafBase,
leafTip;
vector leafRGB;
float leafX, leafY;
float leafDroop;
}PlantDB;

void leaf(PlantDB plant, vector end);
vector* subdivide(unsigned seed, int num, vector B, vector E, float falloff);

 

#include "plant.h"
#include <stdio.h>
#include <math.h>

void leaf(PlantDB plant, vector end)
{
int n, segments = (plant.leafCv - 1)/3 + 1;

// Generate some xyz's using our subdivide routine
vector begin = {0,0,0};
vector *cv = subdivide(plant.seed,plant.leafCv, begin, end, plant.leafDroop);

/* "open" the Curves statement */
printf("Curves \"cubic\" [%d] \"nonperiodic\" \"P\" [", plant.leafCv);

/* add the list of cv's */
for(n = 0; n < plant.leafCv; n++)
printf("%f %f %f ", cv[n].x, cv[n].y, cv[n].z);

/* varying widths */
printf("] \"width\" [");
for(n = 0; n < segments; n++)
printf("%f ", flerp(plant.leafBase, plant.leafTip, (float)n/(segments - 1)));
printf("] \n");

/* add the list of colors */
printf("\"Cs\" [");
for(n = 0; n < segments - 1; n++)
printf("%f %f %f ", randBetween(plant.leafRGB.x, 1),
randBetween(plant.leafRGB.y, 1),
randBetween(plant.leafRGB.z,plant.leafRGB.z*2));
printf("1 1 1]\n"); // white leaf tip

printf("\"N\" [");
for(n = 0; n < segments; n++)
printf("%f %f %f ", randBetween(0,1),
randBetween(0,1),
randBetween(0,1));
printf("]\n");
}

//_____________________________________________________
vector* subdivide(unsigned seed, int num, vector B, vector E, float falloff)
{
vector end = subtract(E, B);
static vector pnt[256];
vector temp;
float u, variation = randBetween(0.5,1);
int n;

for(n = 0; n < num; n++)
{
u = (float) n/num;

temp = scalar(add(end, B), u);
temp.y = temp.y - (temp.y * pow(u, falloff) * variation);
pnt[n] = temp;
}
return pnt;
}

 
  A fully randomized plant, ready for animation (if possilble). The core function of the palm generator takes data about color thickness size, etc and uses it to calculate, draw, apply thickness, and render the curves. Specifically, the function takes in the detail of each plant based on screen size, a random seed number based on the name of each poly cube, the numbner of cvs for each curve, the number of leaves, the width of base and tip, the primary colors for the leaves (randomness adde within the script) the x and y scale of the plant, and finally the amount of droop, or gravity, it experiences. The program then constructs a rib statement MTOR can understand and execute, one piece at a time. Mike figured our how to set, then randomize the normals, resulting in an interesting twisting effect on the leaves. This also locks the leaves into postion, allowing the camera to rotate around them, as shown by the animation below (COURTESY OF MIKE CABRERA) :    


     

 

 

We put MTOR to the test by using the MEL script to create a thousand random boxes with an 10X10 gird space. This is the scene as it appears in Maya....

     


  And this is the rendered image. Here the randomness can really be appreciated. The next goal was to animated them slightly by using the Skew command in the RIBBOX, this proved difficult because the leaves used to be generated completely randomly every frame. The seed fixed this and the results is the animation shown below:  

 

 

 

 

 

 


 

The final product of this labor is a short animation where the skew finally works to give some gentle sway to the plants. Nothing amazing, but a confident start towards further animation.

 

I definately want to explore further poential in randomizing and animating the palm plants. I also would like to further integrate it with the original MEL script I wrote to create additional functionality. The goal would be to have a UI that could feed into the helper app, making the code as user friendly as possible.