class_06

 


/*

The following makes a procedure that creates a 'tree', or at least a trunk and a few branches.
This is done using techniques that should be familiar to you, and using the 'turtle' commands
to draw

*/


The primitive tree



global proc tree(float $length,float $x,float $y,float $z,float $angle){

//create a turtle to use to draw a trunk
$tree = aa_turtle_newturtle("LINE");

//set its starting position
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
//set its initial orientation
aa_turtle_turn($tree,$angle,0);
//move to draw a line
aa_turtle_move($tree,$length);

//get the position of the end point of the line
$position = aa_turtle_getPosition($tree);

//create a branch at 45 degrees off the trunk
$tree2 = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree2,<<$position[0],$position[1],$position[2]>>);
aa_turtle_turn($tree2,($angle+45),0);
aa_turtle_move($tree2,$length);

//create a branch parallel with the trunk
$tree3 = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree3,<<$position[0],$position[1],$position[2]>>);
aa_turtle_turn($tree3,$angle,0);
aa_turtle_move($tree3,$length);

//create a branch at -45 degrees off the trunk
$tree4 = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree4,<<$position[0],$position[1],$position[2]>>);
aa_turtle_turn($tree4,($angle-45),0);
aa_turtle_move($tree4,$length);


}



/*

After you load the procedure, give it a try by running the following command
this command will create a tree with a trunk of 10 units at 0,0,0 with an initial
orientation of 0 degrees.

*/



tree(10,0,0,0,0);






/*

You can create a procedure with the same arguments as the one above, but using recursion.
By using a recursive procedure you can create branches, but each of the branches can also have branches, and
each of the branches' branches can have branches....etc. Recursive procedures are procedures that are
self-referential, meaning the procedure calls itself.

*/


A simple recursive tree



global proc tree(float $length,float $x,float $y,float $z,float $angle){


//create a turtle to use to draw a trunk
$tree = aa_turtle_newturtle("LINE");

//set its starting position
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
//set its initial orientation
aa_turtle_turn($tree,$angle,0);
//move to draw a line
aa_turtle_move($tree,$length);

//get the position
$position = aa_turtle_getPosition($tree);

//THIS IS THE RECURSIVE PART!!!

//if the lenght is greater than 1, call the 'tree' procedure to make branches
//it is important to have an 'if' statement surrounding your recursive calls, otherwise
//the recursion will never stop, like an infinite loop. Without the if statement the
//tree function would call itself, which in turn would call itself....ad infinitum.
if($length > 1){
//call the tree function again to create a branch. Cut the $lenght in half so each branch is smaller than the last
//also, change the angle so that the branch splits from the trunk
tree(($length/2),$position[0],$position[1],$position[2],($angle-45));
tree(($length/2),$position[0],$position[1],$position[2],($angle+45));
tree(($length/2),$position[0],$position[1],$position[2],$angle);
}



}

//try out your new procedure with some of these.


tree(10,0,0,0,0);

tree(10,0,0,0,40);

tree(20,0,0,0,0);





//You can now begin to refine your procedure so you have more control over the output of the tree.
//In this step we will add another variable to the procedure definition so that the angle between branch
//and trunk will be variable. We will call this angle the 'spread'.

//add another argument, $spread, to the end of the procedure definition



global proc tree(float $length,float $x,float $y,float $z,float $angle,float $spread){


//create a turtle to use to draw a trunk
$tree = aa_turtle_newturtle("LINE");
//set its starting position
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
//set its initial orientation
aa_turtle_turn($tree,$angle,0);
//move to draw a line
aa_turtle_move($tree,$length);

//get the position
$position = aa_turtle_getPosition($tree);


if($length > 1){
//use the same call to the tree procedure as before, but adjust the 'angle' by adding the 'spread'.
//also, don't forget to include the 'spread itself as the 6th argument.
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),$spread);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),$spread);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$spread);
}



}


//test it out


tree(10,0,0,0,0,11);
tree(20,0,0,0,0,20);
tree(20,0,0,0,0,120);





/*

To give a little more control over the morphology of your tree, you can add another variable, we'll call it
$drift. We will use this to have the angle of the branch change over each step of the growth. Each time the
tree branches we will add $drift to the $angle so the $angle at which the branches are oriented will slowly
'bend'. This is just oneexample of how you can start to have the algorithm for growth change for each step
of the growth/recursion.

*/


A tree with 'drift'



global proc tree(float $length,float $x,float $y,float $z,float $angle,float $spread,float $drift){


$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
aa_turtle_turn($tree,$angle,0);
aa_turtle_move($tree,$length);


$position = aa_turtle_getPosition($tree);
$angle = $angle + $drift;
if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$spread,$drift);
}



}


//give it a try

tree(20,0,0,0,0,78,19);
tree(10,0,0,0,0,11,10);




/*

So far we have been doing all of our 'trees' in the xz plane, to have it draw in three dimensions is easy, we
just need to have the 'turtle' command turn in the altitude as well as the azimuth. We can use the same angle
for altitude as we do for azimuth


*/



Starting into 3 dimensions



global proc tree(float $length,float $x,float $y,float $z,float $angle,float $spread,float $drift){


$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);

//add $angle as the altitude argument as well and your tree will 'grow' in 3 dimensions.
aa_turtle_turn($tree,$angle,$angle);
aa_turtle_move($tree,$length);


$position = aa_turtle_getPosition($tree);
$angle = $angle + $drift;
if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$spread,$drift);
}



}

//try it out
tree(20,0,0,0,0,78,19);





/*

We can improve our 3d tree growth by making the 'altitude' angle different than the $angle we are already using.
Also, we can have the tree branch in 4 directions off of each trunk (one for each of the possible combinations of
postive and negative altitude and azimuth). To have more branching we just need to add more calls to the 'tree'
procedure within itself

*/


A fully 3D tree



//add another argument, right after $angle, for $altitude
global proc tree(float $length,float $x,float $y,float $z,float $angle,float $altitude,float $spread,float $drift){


$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);

//use the new $altitude angle
aa_turtle_turn($tree,$angle,$altitude);
aa_turtle_move($tree,$length);


$position = aa_turtle_getPosition($tree);
$angle = $angle + $drift;

if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread),$spread,$drift);

//add some additional calls to the 'tree' procedure to have the tree branch in the negative as well as the
//positive altitude (multiply by -1 to go in the negative

tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$altitude,$spread,$drift);
}





}

tree(20,0,0,0,0,78,20,19);





/*

To add 'leaves' on the ends of all our branches we can add an 'else' clause to the procedure. Until now, if the $length
is greater than 1 the tree procedure would call itself, if it is less than one, it stopped. Now, add an 'else' clause so
that when $lenght is less than one (which is the end of a branch) the procedure will create a polyCube

*/


A tree with 'leaves'




global proc tree(float $length,float $x,float $y,float $z,float $angle,float $altitude,float $spread,float $drift){


$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
aa_turtle_turn($tree,$angle,$altitude);
aa_turtle_move($tree,$length);


$position = aa_turtle_getPosition($tree);
$angle = $angle + $drift;
if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$altitude,$spread,$drift);
}else{
//add an 'else'

//create a 'leaf'
polyCube;
move $position[0] $position[1] $position[2];
}





}


//test it out (this might take a minute)

tree(20,0,0,0,0,78,60,19);





/*

Recursive procedures are no different than any other procedures, they can all other procedures from within them. Instead
of making a 'polyCube' you can make a procedure called 'leaf' (that makes a cube) and put a call to the 'leaf' procedure
inside of the 'tree'.


*/



global proc leaf(float $x,float $y, float $z, float $scale){

polyCube;
scale $scale $scale $scale;
move $x $y $z;


}

global proc tree(float $length,float $x,float $y,float $z,float $angle,float $altitude,float $spread,float $drift){


$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
aa_turtle_turn($tree,$angle,$altitude);
aa_turtle_move($tree,$length);


$position = aa_turtle_getPosition($tree);
$angle = $angle + $drift;
if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$altitude,$spread,$drift);
}else{
//make a leaf
leaf($position[0],$position[1],$position[2],.3);
}





}

//give it a try
tree(20,0,0,0,0,78,60,19);





/*

As the tree 'grows' you can track its recursions, and use that to create and shape objects as it grows. To do this add an
argument called '$iteration' to your procedure. This is a value that will start at 0 and be incremented with each
step of the growth.

You can use the iteration to shape/scale objects as you place them. In this example I took the 'leaf' call and moved it so
that a leaf will be created at the end of each trunk as well as each branch. I made the scale of the leaf be the inverse
(1 divide by) of the iteration. What will happen is each iteration will have progressively smaller 'leaf' or block at
the end of it.

*/



Using the 'iterations'



//add an argument of 'iteration'
global proc tree(float $length,float $x,float $y,float $z,float $angle,float $altitude,float $spread,float $drift,float $iteration){

//increase the iteration
$iteration++;
//print it so that you can see the numbers increase
print($iteration + "-");

$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
aa_turtle_turn($tree,$angle,$altitude);
aa_turtle_move($tree,$length);


$position = aa_turtle_getPosition($tree);

//use the $iterations to make a different sized leaf
leaf($position[0],$position[1],$position[2],(1/$iterations));
$angle = $angle + $drift;
if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread),$spread,$drift,$iteration);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread),$spread,$drift,$iteration);
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread * -1),$spread,$drift,$iteration);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread * -1),$spread,$drift,$iteration);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$altitude,$spread,$drift,$iteration);
}





}

//try it out
tree(10,0,0,0,0,78,60,19,0);


/*

The results may not be what you expected, the iterations does not count every leaf, only every 'recursion'. In
our example the procedure calls itself as long as $length is greater than 1. If you use the example above,
tree(10,0,0,0,0,78,60,19,0);, the length starts as 10 and our tree procedure divides that by 2 with each recursion, so it
will have only 4 recursions until $lenght is less than 1.

*/


Using global variables






//try redefining the leaf so that the color is darker with each iteration.

global proc leaf(float $x,float $y, float $z, float $scale){

$leaf = `polyCube`;
scale $scale $scale $scale;
move $x $y $z;
aa_setColor($leaf[0],"lambert",0,$scale,0,.5);


}


tree(10,0,0,0,0,78,60,19,0);








/*

You can also keep track of each branch that is created so you have a overall count of branches. To do this you need
to use a new variable definition in MEL, a 'global' variable. So far all of the variables we have been using in MEL
procedures have been isolated to the scope of the procedure. This means, if you have the variable '$length' being
used inside of a procedure, it only has value inside of the procedure, if you refer to $length outside of the
procedure it will not be equal to anything. To keep a running count of how many branches we have we need to use
a variable that will transcend the boundaries of the procedure, this is called a 'global' variable. Global
variables have the same value inside and outside of a procedure. In our case we will make a variable called
'$counter' and define it as 'global'. This variable will be shared by every call to the 'tree' procedure and
can be incremented to keep track of our count of branches.

/*

//create a variable counter, outside of the procedure 'tree'
int $counter = 0;

global proc tree(float $length,float $x,float $y,float $z,float $angle,float $altitude,float $spread,float $drift){

//import the variable $counter as a global variable.
global int $counter;

//increment the counter
$counter++;
//print its value (plus a carriage return)

print($counter + "\\n");

$tree = aa_turtle_newturtle("LINE");
aa_turtle_setPosition($tree,<<$x,$y,$z>>);
aa_turtle_turn($tree,$angle,$altitude);
aa_turtle_move($tree,$length);

$position = aa_turtle_getPosition($tree);
$angle = $angle + $drift;

leaf($position[0],$position[1],$position[2],.1);

if($length > 1){
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle-$spread),($altitude-$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],($angle+$spread),($altitude+$spread * -1),$spread,$drift);
tree(($length/2),$position[0],$position[1],$position[2],$angle,$altitude,$spread,$drift);
}





}


/*

If we want, we can also redefine the 'leaf' procedure to make a text label that puts the $counter lable on each branch
instead of a cube. This can be done with the 'textCurves' command.

*/

//redefine a leaf

global proc leaf(float $x,float $y, float $z, float $scale){

global int $counter;

textCurves -ch 0 -f "Arial|h-08|w400|c0" -t $counter;
scale $scale $scale $scale;
rotate 90 0 0;
move $x $y $z;

}



//try it out

tree(10,0,0,0,0,78,60,19);







  • class_06