MEL How-To #95 | ||||||||||||||||
| ||||||||||||||||
Introduction To MELYou only have to use Maya for a few minutes to become acquainted with MEL, the embedded scripting language Maya uses. Every function Maya performs is echoed in a MEL command whether it be a simple selection, adjusting Soft Body weights or programming a complex shader network. You’ll soon realize that it is necessary to delve deep into this integral system to harness Maya’s power. Note: This article was originally written in November 1998. Maya has changed a lot since then, and I apologize for any information appearing below that is now out-of-date. I accept any comments or questions to: maya@ewertb.com Working with MEL ScriptsYou will no doubt want to write your own MEL scripts and functions as your Maya projects progress. Many MEL authors have generously made their scripts available for download from the internet. To take advantage of these new scripts you must install them properly so Maya can make them available in your working environment. MEL scripts are normally installed in the ‘scripts’ directory in your Maya home directory. Under IRIX this is:
/usr/people/<username>/maya/scripts/
Under NT this is: <drive>:\aw\<username>\maya\scripts\ Maya does not scan any subdirectories within this folder. It is possible to specify additional directories for storing MEL scripts by setting the To write effective MEL scripts it is important to know how they are handled within Maya. The first time you enter a MEL command Maya scans your script directories for a script file that matches the name of the command. For example, if you enter ‘ global proc showOnlySelected() { // MEL commands for this script go here } All of the above criteria are necessary for Maya to be able to execute the command. After the script is loaded Maya will remember it and run it from memory. If you make any changes to the script after it has been loaded you will have to tell Maya to re-read the file from disk using the ‘ source showOnlySelected; You do not need to specify the ‘ When writing your own scripts, follow these simple guidelines:
Parsing the Selection ListOne of the MEL functions you will need most often is also one of the easiest to use. Most MEL scripts interact with the user's current selection. Your scripts will have to be able to determine what objects are selected and, in some cases, what types of objects they are and how they relate to other elements within the scene. It is easy to get the current selection list using MEL. Simply use the ‘ string $select[] = `ls -sl`; If your script changes the active selection you may wish to restore it when it is appropriate to do so. Keep the array you obtained with ' select -r $select; The ‘ To process each node in the selection list you can use a variation of the
for ( $node in $select ) // process each selection
{
/* … */
}
Maya automatically declares On the first pass, While the "+" operation may be used with the string datatype it is not allowed on a string array. That means you cannot directly add something to the selection list like this: $select = $select + "selectThisToo"; // Error: Illegal operation "+" on data of type string[]. // The correct way to do this is to determine the number of items in the array using the ‘ int $lastSelect = size( $select ); $select[ $lastSelect ] = "selectThisToo"; The ‘ You can use the ‘ ls -sl; // Result: pSphereShape1 nurbsSphereShape1 emitterShape1 // ls -sl -type "nurbsSurface"; // Result: nurbsSphereShape1 // ls -sl -type "mesh"; // Result: pSphereShape1 // ls -sl -type "nurbsSurface" -type "pointEmitter"; // Result: nurbsSphereShape1 emitterShape1 // Note that in this example the user has explicitly selected the shape nodes for each object. The ‘ There are several methods of determining an object’s type without restricting the list results. One of the easiest ways is to check each item is using either the ‘ string $select[] = `ls -sl`; // Result: pSphereShape1 nurbsSphereShape1 // nodeType "pSphereShape1"; // Result: mesh // nodeType "nurbsSphereShape1" // Results: nurbsSurface // objectType -isType "nurbsSurface" nurbsSphereShape1; // Result: 1 // By using these checks you can verify that your script can process the types of objects selected. You should ignore types not supported by your script, if possible, or alert the user as to the requirements of your script. In the example above both nodes listed were shape nodes. Unfortunately, you cannot assume that the selection list will always cooperate and give you the shape nodes when you need them. Very often you will be given the transform node instead. Compare the results below: string $select[] = `ls -sl`; // Result: pSphere1 nurbsSphere1 // nodeType "pSphere1"; // Result: transform // nodeType "nurbsSphere1" // Results: transform // That’s hardly helpful for determining if you are being given a polygon object, a NURBS object, or even a camera. In this case it will be necessary to find the shape node yourself. Use the ‘ string $relatives[] = `listRelatives -shapes "pSphere1"`; // Result: pSphereShape1 // Be careful - attempting to retrieve the shape relatives for a shape node will result in an empty array: listRelatives -shapes "pSphereShape1"; // Result: // A favorite trick of Paul Anand from Alias|wavefront is to use the ‘ pickWalk -d down; If the current node is the transform node this drops down a level to the shape node. It the shape node is already selected then it remains selected. This method changes the active selection; be sure to restore it when you’re done. A convenient method for obtaining the list of shape nodes for the selected objects is using the combination of ‘ ls -sl; // Result: pCube1 pSphereShape1 // ls -sl -dag -lf; // Result: pCubeShape1 pSphereShape1 // (Thanks to Julian Mann for alerting me to this technique!) There is another approach, similar to the ‘ The ‘ string $select[] = `ls -sl`; // Result: pSphere1 nurbsSphereShape1 // filterExpand -selectionMask 12; // Poly Mesh // Result: pSphere1 // filterExpand -selectionMask 10; // Nurbs Surfaces // Result: nurbsSphere1; The ' Another advantage to this command is that it will expand the range selections to individual items. This makes it considerably easier to parse component selections. Maya normally compresses adjacent component selections using a " ls -sl; // Result: nurbsSphereShape1.cv[4][3:5] // filterExpand -sm 28 // Control Vertices (CVs) // Result: nurbsSphere1.cv[4][3] nurbsSphere1.cv[4][4] nurbsSphere1.cv[4][5] // Maya’s documentation suggests that the ‘
You can use the H2O MEL Script ‘ Note: As of Maya v3 the filterExpand selectionMasks are finally included in the on-line documentation Traversing Scene HierarchiesIn addition to knowing what types of objects are selected it is often important to know how they relate to other scene elements. A single transform node can control many underlying nodes. When working with skeletons it will be necessary to be aware of which joints are above or below others joints. There are two approaches to determining hierarchy information - the important difference between the two methods is that the latter alters the active selection, whereas the former does not. To retrieve a list of all of the children of an object: string $children[] = `listRelatives -children pSphere1`; To determine the parent for an object: string $parent[] = `listRelatives -parent pSphere1`; The ‘ To select the next or previous object at the same level: // Pick next object on same level string newSelect[] = `pickWalk -direction right`; // Pick previous object on same level string newSelect[] = `pickWalk -direction left`; To select the object up or down a level from the current selection: // Move down to and select child string newSelect[] = `pickWalk -direction down`; // Move up to and select parent string newSelect[] = `pickWalk -direction up`; Finding Specific Scene InformationIn many cases it will sufficient to allow the user's actions to determine the list of objects to act upon. In others you will want to find a specific item in the scene, or to determine if the user has yet created it. Determining whether a named object or an object type exists is easy; determining the same of an attribute for an object requires a little more work. To determine if an object exists within the scene, simply use the name as a pattern for the 'ls' command. For example, in one of my scripts I needed to create a new node to store some custom data. However, there is no need to create a node if it already exists, and attempting to do so will result in a decorated node (ie. Maya will append a number to the end of the name). The test is simple:
if ( `objExists "recallData"` )
{
// The data node exists
}
The ‘ For a more specific test the ‘
if ( size( `ls -type trim` ) > 0 )
{
// Trim performed on NURBS geometry
}
The ‘ Maya provides the animator the ability to add custom attributes to any object. As for the default attributes you retrieve the value for your custom attributes using the ‘ float $myAttr = `getAttr pSphere1.noAttr`; // Error: No object matches name: pSphere1.noAttr // For this reason it is important to verify the existence of a custom attribute before attempting to query or assign any values. Maya's '
if ( `attributeQuery -node "leftFoot" -exists "toeCurl"` )
{
// Safe to use 'toeCurl' attribute
}
The ' addAttr -ln "blink" -at double -min 0 -max 100 -dv 0 eyeRight; attributeQuery -node "eyeRight" -range "blink"; // Result: 0 100 // Unfortunately, you cannot use this method to change the value range for the attribute. 10 Tips For Writing Better MEL Scripts
if ( `window -exists myWindowName` ) deleteUI myWindowName; string $objectName = "nurbsSphere"; print ( $objectName + ".rotateY" ); // Result: nurbsSphere.rotateY // float $ry = `getAttr ( $objectName + ".rotateY" )`; // Result: 45.0 // // Warning: Some items cannot be moved // This is caused by an active manipulator tool such as the Move Tool. To avoid these messages while your script is running instruct Maya to drop the tool before performing your selections:
global string $gSelect; // Sacred Select Tool
setToolTo $gSelect;
proc getValue() { int $number = `intField -q -value int_recallItemsInList`; } global proc recall() { /* … */ intField int_recallItemsInList; /* … */ } You could also pass the names for your UI widgets as a parameter to other functions. If you do this make sure to document the purpose of the parameter and also the origin of the UI element. proc getValue( string $field ) // Parameters: $field = intField that holds value; // defined in global proc recall() { int $number = `intField -q -value $field`; } global proc recall() { /* … */ string $field = `intField`; // Must build $field into command, and encapsulate in quotes intField -e -changeCommand ( "getValue( \"" + $field + "\" )" ) $field; /* … */ } // Update and execute Recall script source recall; recall; Highlight these three lines and drag them to a new Shelf item. Now with a quick click of a Shelf Tool Maya will integrate the changes you’ve made and execute the result. The comment is included to provide a description of the Shelf Tool in the Feedback Line whenever you move the mouse over the icon, as demonstrated by the Rhonda Graphics team at SIGGRAPH’98. | ||||||||||||||||
Copyright ©2005 by Bryan Ewert, maya@ewertb.com Maya is a Registered Trademark of Alias |