Introduction: Introduction to MEL Scripting in Maya: 3D Fractals

About: Reza is a computational designer & creative engineer. He uses code to express himself, and creates tools and libraries to help others create. He is the author of ofxUI, one of the most popular addons for openf…

Maya is a very powerful tool for creating 3D animations and motion graphics. You can model, texture, light, animate, and render within the same environment. Maya's visual interface is powerful and deep. It allows people to build very complex scenes and animations.

But sometimes, using Maya's visual interface to build complex models / objects / scenes / animations takes a lot of time. For example, performing repetitive tasks, such as creating 1000 cubes or importing 100s of curves, takes a lot of time and is very taxing. This is why you should care about MEL scripting.

Regardless of what you're doing in Maya, knowing a little bit of scripting will help you be more efficient and creative. Scripting refers to the activity of using Maya's command line interface or Script Editor to type in commands versus using Maya's visual interface to perform actions and operations.

Learning how to use Maya's Script Editor is pretty fun and easy. The Script Editor's log echoes every command performed in Maya. Thus, you can easily look up the command for doing something by simply using Maya's visual interface to perform the command and then checking the console.

In this instructable, you'll be learning how to use MEL (Maya Embedded Language) Script in Maya to create a 3D fractal. You'll need a copy of Maya 2015 or earlier and some courage. Lets Go!

Side note! If you're interested in the rendering of these fractals and their aesthetic check out my instructable on Ambient Occlusion Rendering in Maya

Step 1: Open the Script Editor

Maya's command line interface is located on the bottom of its interface. Click on the icon located in the bottom right corner of the interface. If everything worked then you should see the Script Editor window. If that didn't work, another way to open the Script Editor is by using the menus: Window -> General Editors -> Script Editor.

Step 2: Hello World & Hello Cube

The first thing we are going to do is log or print "Hello World" to the Script Console. Make sure you're in MEL mode, and type in:

print "Hello World";

Then select the text and press control & enter. This will execute your command! Now you should see "Hello World" logged in the Script Console. Now lets breakdown what we just typed.

"print" is a command (aka function) that Maya understands. "Hello World" is the input string that we'd like the print command to echo in the console.

Okay so I can see that you're not impressed...well lets do something visual and way more awesome. Lets create a polygon cube using MEL. You might be wonder what is the command for cube? Well, just make a cube using Maya's visual interface (Create -> Polygon Primitives -> Cube). Now check out the console (shown in the third image). The line that does all the magic is:

polyCube -ch on -o on -cuv 4 ;

So go ahead and delete the cube you just made and copy and paste this line into the editor. Press control & enter and now you'll see a cube in the main perspective view. Sweet. Lets take a closer look at the command that produced the cube. The command starts with polyCube, this is what tells Maya we are creating a polygon cube instead of a polygon sphere or nurbs cone. The rest of the line sets flags (aka parameters) of the command. The way flags / parameters are specified are in the following format:

-parameterName value

The first parameter set in the line above is the ch parameter (ch is short for construction history) and the input value is "on". The MEL Command Reference has a comprehensive list of flags and their short and long names. Here is a link to the polyCube Command Reference.

For a complete list of commands check out MEL Command Reference (Help -> MEL Command Reference).

Step 3: MEL Syntax and Wonkiness

Okay, now lets talk about scripting and programming. This instructable isn't about teaching programming concepts, but rather using them within Maya to do awesome things. There are many places online where you can learn how to program (Check out Processing.org). Here I'll explain a couple scripting / programming things that are specific to Maya and MEL.

In MEL, variable names must always be prefixed by the "$" character. Here are examples of valid variable names:

int $a = 0;
float $b = 0.0;
string $c = "Hello World";

Arrays are declared like so:

int $d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
string $e[] = {"This", "is", "an", "array", "of", "strings"};

Maya sometimes has problems dealing with order of operations. Thus I like to enclose all operations in parenthesizes to make sure that Maya doesn't throw an error and/or complain that it's confused.

When using a command or specifying a flag where I am combining two or more variables, I always do something like this:

print ($c + $b);

What this will do is combine the string Hello World with the floating point number 0.0 (Result: Hello World0). If you excluded the parenthesis, then Maya will throw an error like:

// Error: Line 1.10: Syntax error //

To declare a function or method, MEL uses the proc keyword. Here is an example of a function in MEL:

proc printNumbers( int $count )
{    
	for ($i = 1; $i <= $count; $i++ )
	{
		print -r $size;
	}
}

Step 4: Selecting Objects With MEL

Selection is how we specify what object will be operated on. Typically, we select something by clicking on the object(s) we are interested in and then move or rotate or deform it to our liking.

Since we'll be scripting, we need to be able select items without clicking them. Luck for us, Maya gives all objects created default names if no specific name is specified. We can query Maya for objects that have a certain name or a prefix in their name.

Go ahead and make a couple cubes in your scene using Maya's visual interface. Now open the Outliner (shown in the first photo). Here you'll see the cube objects you've just made. All the cubes' names are prefixed by "pCube" and then a number. To select a cube with MEL use the "select" command like so:

select pCube1;

Great, but what if we wanted to select all the cubes? This is a bit more complex, but doable! First we have to somehow list all the objects in the scene and filter the selection to only include objects that are prefixed with pCube. We can use a * (aka wildcard) character to specify that we want to select all objects with a certain prefix.

So to list the objects in the scene with a prefix of "pCube" use the ls command:

string $cubes[] = `ls "pCube*"`; 

One thing to note is that we had surrounded the ls -l "pCube*" command by the ` character. This is very important, this basically tells Maya to convert / pipe the result of the commend into a string array.

Here we store the selection in a variable called cubes! Then we run the select command to select all the cubes:

select $cubes;

If everything when according to plan, you should see all your cubes selected (shown in the second photo).

Step 5: Understanding Fractals & Recursion

Here is a little snippet about fractals:

A fractal is a natural phenomenon or a mathematical set that exhibits a repeating pattern that displays at every scale. - Wikipedia

Fractals are great fun because they are beautiful, simple to understand and easy to generate using recursion. What is recursion? Recursion commonly refers to a process, or method that invokes itself within its execution. Meaning, this process calls itself. Confused? Yeah me too. Its a difficult to explain and understand in words. So imagine we've drawn a large empty square. We can design a process that draws four squares within that the larger square. The input to this process is a square, and the output is four smaller squares. If we were to apply the process again to the smaller squares within the process, then this process would be considered recursive.

The best way to understand this is to write a recursive function! So lets do that. Lets write a function in Maya that contains an algorithm (set of instructions) that will create a fractal! Here is the algorithm in plain english:

  1. Make a cube,
  2. Create six smaller cubes based on the original cube's size
  3. Move the smaller cubes so they are on the faces of original cube
  4. Repeat steps 1-4 on each one of the smaller cubes

Step 6: MEL Script

Now we'll write a recursive function that implements the fractal algorithm aforementioned. There are many ways of implementing this, but I'm going to show the easiest to understand (I hope)!

First, declare the function generateFractal, it takes a couple input parameters, a vector, float and an int.

proc generateFractal(vector $center, float $size, int $recursionLevel)
{

We have to write a check to see what recursion level we are at. This recursion level refers how deep we are within the process. When we create the first cube we are level 0, and then when the second set of cubes (children) are made, then we are at level 1, etc. For our purposes we want to specify a maximum recursion depth and decrement that number until we reach -1, only then will the function stop.

	$recursionLevel -= 1;
    	if($recursionLevel < 0)
    	{
        	return;
    	}

The next line will create a polyCube with a width, height, and depth of $size, which is one of the input parameters of the generateFractal function. We'll see how this is set in the code in a bit.

    	polyCube -ch on -o on -w $size -h $size -d $size -cuv 4 ;                

Then we move the cube into position. You might be thinking, oh wait, don't we have to select the cube first? Nope! By default Maya selected the last object created in the scene. This is handy.

    	move -r ($center.x) ($center.y) ($center.z) ;  

Now we'll calculate the next cube(s) size and how far offset it will be from the cube we just made (aka its parent). The next cube will be half the size of its parent, and will be offset by a quarter its parent's size and half of its own size. If that doesn't make sense, don't worry. Once we start executing this function to generate fractals you can play with these numbers and see how they affect the fractal's aesthetic.

    	float $nextSize = $size/2.0;
    	float $offset = $size/4.0 + $nextSize/2.0; 

Okay, we have to calculate center positions for the new cubes we are going to create. We already calculated the offset so the new positions are equal to the previous center, plus an offset in the appropriate direction.

    	vector $right = <<($center.x + $offset), $center.y, $center.z>>; 
    	vector $left = <<($center.x - $offset), $center.y, $center.z>>; 
    
    	vector $front = <<$center.x, ($center.y + $offset), $center.z>>; 
    	vector $back = <<$center.x, ($center.y - $offset), $center.z>>;
    
    	vector $top = <<$center.x, $center.y, ($center.z + $offset)>>; 
    	vector $bottom = <<$center.x, $center.y, ($center.z - $offset)>>;  

Finally we call the generateFractal function within itself! Woohoo recursion :) Notice that we pass the function the new positions for the centers, size, and recursion level!

	generateFractal($right, $nextSize, $recursionLevel); 
    	generateFractal($left, $nextSize, $recursionLevel); 
    	generateFractal($front, $nextSize, $recursionLevel); 
    	generateFractal($back, $nextSize, $recursionLevel); 
	generateFractal($top, $nextSize, $recursionLevel); 
    	generateFractal($bottom, $nextSize, $recursionLevel); 
}

While building and testing this function, you'll probably end up with tons of cubes in your scene. Then Maya will slow down and eventually crash. Thus before we generate our fractal, we'll query Maya for any objects with the prefix pCube and delete them. This will give us a clean scene.

string $cubes[] = `ls "pCube*"`; 
select $cubes; 
delete;

Now we are going to setup the initial parameters that we'll pass to our generateFractal function! We'll center our first cube at (0,0,0) and start with a size of 100 units, and we'll go 6 levels (actually 7 counting zero) deep.

vector $startPt = <<0,0,0>>; 
float $startSize = 100.0;
int $startRecursionLevel = 6.0; 

Then we'll call the function! Maya will hang out for a second and process what you've just told it to do. Maya might freeze for a second or ten. Don't worry, thats perfectly normal. I've found that 6 is the highest level I can achieve on my machine before I confuse Maya and cause it to crash! Calling this function is like "taking the red pill"... I hope it blows your mind:

generateFractal($startPt, $startSize, $startRecursionLevel);

Step 7: Further Exploration

This is just the tip of the iceberg! You can do so much more with MEL Scripting. I've only shown .01% of whats possible. There are some excellent resources online and books that cover topics that allow you to create super complex scene and forms that are out of this world. Here are a couple books and useful links:

http://www.lulu.com/shop/nicholas-pisca/ysyt/paper...
http://help.autodesk.com/cloudhelp/2015/ENU/Maya-T...
http://nccastaff.bournemouth.ac.uk/jmacey/RobTheBl...
http://www.nickpisca.com/BLAST/index.php?title=Cat...
http://cgkit.sourceforge.net/maya_tutorials/intro/
http://www.nerfsafetysquid.com/melTutorials.htm
http://area.autodesk.com/tutorials/mel_scripting_i...