Extending Maya with MEL and C++

for Animation Art and Technology, spring 2012

Usefull links

MEL guide (Click User Guide > General > MEL and Expressions.)
MEL command reference
C++ API guide and reference
Troubleshooting for compile time tribulations (Look under section 3.)

MEL scripts

You can enter single MEL commands in the MEL box in the lower left of the main Maya window. The output of the command will show up in the black box in the lower right. You can also use MEL in the Script Editor (Window > General Editors > Script Editor). In the Script Editor, you can enter multi-line scripts in the bottom panel and see the output in the top panel. To execute what you've typed in the bottom panel, press Ctrl+Enter. Your code will disappear from the editor when you execute it; press Ctrl+z to get it back. (Ctrl+z in this context doesn't undo anything, it just retrieves past commands.)

Since Maya's GUI is built with MEL, and pushing GUI buttons just executes MEL commands, there is a MEL command to do pretty much anything you can do in the GUI. In fact, if you use the GUI when the Script Editor is open, you can see the corresponding MEL commands appear in the output pane. You can use this feature to find the proper MEL command to accomplish any particular task.

Take this example script I wrote which produces a pyramid of Sierpinski triangles. Notice that this script is a single global procedure definition. You can paste this script directly into the script editor and execute it to define the sierpinski global procedure, which you can then run by executing something like:

sierpinski(0,0,0, 10,10,10, 5);

If you have a script you want to keep using the next time you run Maya, save it in a file with the .mel extension and keep the file in Maya's scripts path. You can find the current script path with the command:

getenv("MAYA_SCRIPT_PATH");

You can add directories to the script path in the Documents\maya\2012-x64\Maya.env file. For example, I have a script, C:\Users\ppm\SandBox\sierpinski.mel. I add the line:

MAYA_SCRIPT_PATH=C:\Users\ppm\SandBox

to the Maya.env file. To run any script in the script path, use the source command. So after changing my Maya.env file and restarting Maya, I execute:

source sierpinski.mel;
sierpinski(0,0,0, 10,10,10, 5);

Animation Expressions

Go to Window > Animation Editors > Expression Editor. Create a Polygon Sphere in the 3D view, which will be named pSphere1 be default. When the sphere is selected, it will appear under Objects in the Expression Editor. Select pSphere1 in the Expression Editor, type this:

pSphere1.rotateZ = 45;

into the Expression pane near the bottom, and click the Create button. Notice that the sphere is now rotated, and if you open the Channel Box/Layer Editor, the sphere's Rotate Z field is highlighted in purple.

We can also define relationships between objects. Create a Polygon Cone, which will by default be named pCone1. Select the sphere and select its rotateZ attribute in the Expression Editor to bring up the previous expression. Replace that expression with this:

pSphere1.rotateZ = pCone1.translateY * 10;

and click the Edit button. Now move the cone up and down and see the sphere rotating.

Finally, we can make attributes time-dependent. Try each of these expressions:

pSphere1.rotateZ = time * 100;
pSphere1.rotateZ = frame * 10;
pSphere1.rotateZ = sin(frame / 3) * 50;

Hello World in C++ using Visual Studio 2010

Maya plugins on Windows are normal dlls, except that they have the .mll extension. We can create a plugin that supplies a new MEL command by writing a class which inherits from MPxCommand and implements the doIt, initializePlugin, and uninitializePlugin functions.

Open Visual Studio and create a new project with File > New > Project... and pick Empty Project. By default, this project will target 32-bit. But we have 64-bit Maya. So go to Build > Configuration Manager... and in the cell under the Platform column, click on the drop-down arrow, select <New...>, and create an x64 build configuration. Make sure that the new x64 configuration is selected from the drop-down menu at the top of this window.

Now, go to View > Property Manager to make the Property Manager appear on the left of the main window. In the Property Manager, click the arrow next to your project to show the build configurations. There should be the default Debug | Win32 and Release | Win32 configurations, as well as the Debug | x64 and Release | x64 configurations we just created. You can remove the Win32 configurations (right click > Remove); they will note be needed.

In the Property Manager, select both x64 configurations. With both selected, right click on one of them and select Properties to open the Property Pages window. In this window, set the following settings:

General > Target Extension .mll
General > Configuration Type Dynamic Library (.dll)
VC++ Directories > Include Directories C:\Program Files\Autodesk\Maya2012\include
VC++ Directories > Library Directories C:\Program Files\Autodesk\Maya2012\lib
C/C++ > Preprocessor > Preprocessos Definitions REQUIRE_IOSTREAM;_BOOL
Linker > Command Line /export:initializePlugin /export:uninitializePlugin

In order to link libraries, we must not only set Include Directories but also name the individual .lib files in Linker > Input > Additional Dependencies. To begin with, link Foundation.lib and OpenMaya.lib. You will need to link more files as you need them. If you are the type of person who solves many problems with a hammer, and who probably supports the death penalty, you may prefer to simply paste in this list of all the libraries.

Now that the project is set up, add these hello.cpp and hello.h files to your project. Build your project by pressing F7. If Posidon smiles upon you, it will build without issues, and you will find a .mll file in your project folder under x64\Debug. If you get build errors, pray to Posidon or check here under section 3, where some kind soul has compiled a list of possible problems and fixes.

Open Maya and go to Window > Settings/Preferences > Plug-in Manager. Click Browse at the bottom of the Plug-in Manager window and find your .mll file. If Posidon continues to smile, your plugin will show up under the Other Registered Plugins section of this window. You can see the vendor and version strings from hello.cpp by clicking the green i button. You can now run your new MEL command:

helloWorld;

Adding a shelf button for helloWorld

Perhaps you'd like a GUI button for the new command. Go to Window > Settings/Preferences > Shelf Editor. Here you can change the menus of icons above the main 3D view. Select the shelf named General in the menu on the left of the Shelf Editor, then click the New Shelf button above this menu. Name the new shelf "FebruaryThird" to commemorate The Day the Music Died. After shedding a tear and humming "American Pie", click the New Item button under the Shelf Contents section. With the new item selected, click the Command tab and replace

print("User defined macro");
with
helloWorld;
Notice that there is now a tab in the main Maya window called "FebruaryThird", containing a button with a default Maya logo. Clicking it will execute your new command.

Moving objects with your mind

mind.cpp and mind.h implement a plugin providing a translate-like command which moves all selected objects. Try building it like the "hello world" plugin. Once loaded into Maya, the command syntax is:

crazymindpowers -x 3 -y 4 -z 5;

to, for example, move the selection 3, 4, and 5 units in the x, y, and z directions.

mind.cpp illustrates a few important functions. The first is parsing arguments. Notice that Maya functions either return or accept by reference an MStatus object, which is MS::kSuccess on success. On failure, MStatus::error() returns false.

After parsing arguments, we declare a instances of MDagPath and MFnTransform. The latter is an example of a function set; an object with a toolbox of functions to operate on some other type of object. A function set object is set either in the constructor or later with setObject() to operate on a specific object. As we loop through the selected objects, we use MFnTransform::setObject(), and then use MFnTransform::translateBy() to actually translate the selected object.

Finally notice that we grab each selected object as an MDagPath. Data and manipulations to data in Maya are stored in the DAG. The DAG has shape nodes, which store geometry, and transform nodes, which store transformations and parental relationships. A shape can connect directly to several transformations, representing instances of the shape in space.