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