Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Maya Mel

Download as pdf or txt
Download as pdf or txt
You are on page 1of 146
At a glance
Powered by AI
The document provides an overview and reference for MEL (Maya Embedded Language) and how to script in Maya.

MEL features covered include variables, operators, control structures, procedures and functions. MEL can be used to customize Maya's interface and behavior.

Commands can be entered directly into Maya's command line or within a script editor. Return values from commands can be accessed. Commands have different modes.

MEL

FOR

WINDOWS, IRIX, AND LINUX


VERSION 4.5

MEL FOR WINDOWS, IRIX, AND LINUX

2002, Alias|Wavefront, a division of Silicon Graphics Limited. Printed in U S A. All rights reserved.

Alias and the Alias|Wavefront logo are registered trademarks and Alias|Wavefront, Conductors, Dispatcher, Trax, IPR, Export Express, Maya Artisan, Maya Cloth, Maya Complete, Maya Fluid Effects, Maya Fur, Maya Live, Maya Paint Effects, Maya RealTime Author, Maya Shockwave 3D Exporter, and Maya Unlimited are trademarks of Alias|Wavefront, a division of Silicon Graphics Limited. Maya is a registered trademark of Silicon Graphics, Inc., used exclusively by Alias|Wavefront, a division of Silicon Graphics Limited. IRIX and Silicon Graphics are registered trademarks and SGI is a trademark of Silicon Graphics, Inc. Lingo is a trademark and Macromedia, Director and Shockwave are registered trademarks of Macromedia, Inc. OpenFlight is a registered trademark of Multi-Gen Paradigm Inc. Wacom is a trademark of Wacom Co., Ltd. NVidia is a registered trademark and Gforce is a trademark of NVidia Corporation. Inferno and Flame are registered trademarks of Discreet Logic Inc. Linux is a registered trademark of William R. Della Croce. Red Hat is a registered trademark of Red Hat, Inc. Microsoft, Windows XP, and Windows are trademarks of Microsoft Corporation in the United States and/or other countries. Mac and Macintosh are trademarks of Apple Computer, Inc., registered in the United States and other countries. Adobe, Acrobat, and Photoshop are trademarks of Adobe Systems Incorporated. UNIX is a registered trademark, licensed exclusively through X/Open Company, Ltd. All other trade names, trademarks and/or service marks are trademarks or registered trademarks of their respective owners. This document contains proprietary and confidential information of Alias|Wavefront, a division of Silicon Graphics Limited, and is protected by Federal copyright law and international intellectual property agreements and treaties. The contents of this document may not be disclosed to third parties, translated, copied, or duplicated in any form, in whole or in part, or by any means, electronic, mechanical, photocopying, recording or otherwise, without the express prior written consent of Alias|Wavefront, a division of Silicon Graphics Limited. The information contained in this document is subject to change without notice. Neither Alias|Wavefront, a division of Silicon Graphics Limited, nor its affiliates, nor their respective directors, officers, employees, or agents are responsible for punitive or multiple damages or lost profits or any other direct, indirect, special, indirect, incidental, or consequential damages including any damages resulting from loss of business arising out of or resulting from the use of this material, or for technical or editorial omissions made in this document.

ALIAS|WAVEFRONT I 210 KING STREET EAST I TORONTO, CANADA M5A 1J7

CONTENTS
USING MAYA: MEL Part 1 Mel and Maya
1 INTRODUCING MEL
13

Understanding MEL 13 How to use this book 13

MEL FEATURES

15

Part 2 Commands
3 INTRODUCING COMMANDS
19

Understanding commands 19 MEL command documentation 19 Customizing with MEL 19

USING COMMANDS

21

Entering commands 21 Using the Command Line 21 Getting command return values 21 Command modes 22 Commands in expressions 23

CUSTOMIZING WITH MEL


Making shelf icons 25 Making hotkeys 25

25

Saving preferences using userSetup.mel 26 Adding heads up display objects 26

Part 3 Scripting
6 INTRODUCING SCRIPTING
31

Understanding scripting 31 Setting the scripting environment 31

MEL 3

CONTENTS

Script files

31 31 32

Setting script paths

Using procedures in scripts

USING THE SCRIPT EDITOR

33

Opening the Script Editor 33 Edit commands 33 Opening a script 33 Sourcing a script 34 Saving script text 34 Executing a script 35 Clearing status messages 35 Clearing command input 35 Echoing commands 35 Showing script line numbers 36 Showing the stack trace 36

USING SCRIPT NODES

39

Understanding script nodes 39 Creating script nodes 39 Testing scripts 40 Editing script nodes 41 Setting script node execution 41 Deleting script nodes 41

VARIABLES AND CONSTANTS


Variables 43 Constants 52 Data-type conversions 52 Limitations 54

43

10

MAKING STATEMENTS

57

Understanding statements and operators 57 Assignment 57 MEL 4

CONTENTS

Arithmetic 58 Comparison 62 Conditional 64 Operator precedence 65 Grouping operations 65

11

FLOW CONTROL

67

Understanding actions and flow control 67 Grouping 67 Conditional actions 68 Loops 72

12

ABSTRACTING ACTIONS
Procedures 79 Scripts 80

79

13

CREATING INTERFACES
ELF commands UI elements Default parents Naming 90

81

Understanding interface creation 81 81 82 88 88 91 92

Parents and children

UI command templates Deleting UI elements

Attaching commands to UI elements 92 A simple window 94 Modal dialogs 95 Using system events and scriptJobs 96

14

STYLE

99 Understanding style 99 Style tips 99 Using white space Adding comments Naming variables 99 100 100

MEL 5

CONTENTS

Procedures and scripts Bullet-proof scripting

102 102

15

FAQS

103

Fundamental FAQs 103 How do I make a MEL shelf button? 103 103 103 How can I get the names of selected objects? How can I get the best performance from MEL?

What is the difference between the two enter keys on the keyboard for Maya? 104 What are the differences between expression and MEL syntax? What are pointers and does MEL have any? How do I print things? 105 106 106 How can I tell if a script is available? How can I tell which script I am running? Command FAQs 107 What is the relationship between () and string argument syntax for commands? 107 What is the syntax for using equations, strings, vectors, and variables in MEL commands? 107 What is the command for getting the Set Editor? Attribute FAQs 108 Why are the extra attributes I added not in the Channel Box? 108 108 108 How can I change the order of extra attributes in the Channel Box? How do you get and use attributes that have more than one value? How do you set attributes that take more than one value? Variable FAQs 109 How can I find out what variables have been declared? How do global variables work? How do I list all global variables? String FAQs 110 How can I change an integer to a string? How do I concatenate strings? 110 110 110 109 110 109 109 108 105 104

How do you put variables and special characters into strings? Vector FAQs 111 What is a vector component? 111 111 How do I extract individual components of a vector? Array FAQs 111 How do I initialize an array? 111

MEL 6

CONTENTS

How can I dynamically increase the size of an array? How do I allocate and resize arrays? 112

112

Are local array variables destroyed by MEL or do I have to call 'clear' on them to get the memory back? 112 Matrix FAQs 112 How do I use the matrix data type? Can I specify a dynamic matrix? Flow control FAQs 113 How do I iterate through a list of things? How do I use variable argument lists? 113 113 114 115 115 112 113

How do I execute a statement created at runtime? How can I prevent a script from terminating on errors? What is the difference between eval, , and ()? Procedure and function FAQs 116 What is a simple explanation of a MEL procedure?

116 117 117

How are arrays passed in commands and function calls? How do I return a specific type of data from a MEL procedure? How do I capture a return value? Modeling FAQs 118 How can I count polygons? 118 How can I get the name of a (selected) shape node? Commands to pick curve on surface 118 How do I get and set specific UV values on a polygon? How can I create a closestPointOnSurface node? How can I get an objects pivot point in world space? Animation FAQs 119 How to randomize keyframes? Dynamics FAQs 119 How can I select a set of particles? Rendering FAQs 120 119 119 119 117

118 118 119

How can I make a list of what objects are connected to what shading groups? 120 How can I render from within a script? 120 120 What is the command to strip shaders from an object? System interaction FAQs 120 How do I execute a operating system command from MEL? How does Maya store scripts? 120 120

MEL 7

CONTENTS

On UNIX-based systems how can I use the system command to run a process in the background? 121 How do you get the current time in seconds using MEL? File control FAQs 121 How do I open and write files from MEL? 121 121 How can I export selected data to an already opened file? Project control FAQs 121 How do I change projects with MEL? Script path FAQs 122 Calling scripts 122 122 122 How to make Maya look somewhere else for scripts? How do I add a MEL script to Maya start-up? Script Editor FAQs 123 Is there an easy way to highlight text in the Script Editor? What does show line numbers in the Script Editor do? Custom interface FAQs 124 How can I change the background color? 124 124 Is there a way to destroy the window from a button click? 123 123 123 121 121

What is // Error: line <<XX>>: Cannot find procedure <<proc name>>?

Is there a way to close a window, without destroying it, from a button click? 124 How do callbacks for layouts work? 124 124 125 Can I register a callback to be notified when a window is destroyed? Are there standard dialogs available: error, warning, questions, etc.? How can I make vertical sliders? Miscellaneous FAQs 125 How do the error, warning, and trace statements work? How can I abort a MEL script while it is running? How do I export sets from a Maya file? What is the operator for raising to a power? 126 126 126 125 125 125

Can I compile my MEL script (for faster execution)?

Part 4 Maya Gems


16 INTRODUCING MAYA GEMS
dynFuncBoundary.mel Point Explosion 131 MEL 8 129

Particle Collision Boundary 129 129

CONTENTS

dynFuncExplosion.mel Testing Added Particle Attributes dynTestAddAttr.mel Testing Dynamics Events 137 dynTestEvent.mel 137

131 134

134

Dynamics Time Playback 140 dynTimePlayback.mel Finding Unshaded Objects 142 findUnshadedObjects.mel 142 140

MEL 9

CONTENTS

MEL 10

PART 1

MEL AND MAYA

INTRODUCING MEL
MEL (Maya Embedded Language) is a powerful command and scripting language that gives you direct control over Mayas features, processes, and workflows.

UNDERSTANDING MEL
MEL (Maya Embedded Language) provides the foundation for Maya. Nearly every feature of Mayas interface has been built upon MEL commands and scripts. Because Maya gives you complete access to MEL itself, you can extend and customize Maya. With MEL, you can further develop Maya into a unique creative environment for you and for your projects. You dont have to know MEL to use Maya effectively. However, familiarity with MEL can deepen your expertise with Maya. Many aspects of using MEL can be enjoyed by those with little or no programming experience. You dont have to like programming in order to like MEL. There are a number of ways that you can take advantage of MEL without getting into the details of programming. Still, once you have acquired a taste for creating MEL scripts, you will find that MEL can provide you with the means for creating the most advanced digital art imaginable. To get the most out of Maya, you need to take advantage of what you can do with MEL. Here are some examples of things you can do with MEL: Use MEL commands to bypass Mayas user interface, quickly create shortcuts, and access advanced features. Enter exact values for attributes, bypassing any restrictions to precision imposed by the interface. Customize the interface for specific scenes, changing default settings to settings you prefer for a particular project. Create MEL procedures and scripts that carry out custom modeling, animation, dynamics, and rendering tasks.

HOW TO USE THIS BOOK


This book, Using Maya: MEL describes how to use the Maya Embedded Language (MEL). If youre new to MEL, this book helps you to get started with using MEL commands and scripts. Once youve started explore MEL, this book will continue to help you by explaining how to get the most out of the commands, macros, scripts, and custom interface elements that you can create with MEL.

MEL
13

INTRODUCING MEL | 1
How to use this book This book assumes you have a basic understanding of Maya. To learn the fundamentals of MEL quickly, see the MEL lesson in Instant Maya. Throughout this book there are many examples of MEL commands and code. To run the examples, you can paste them into Mayas Script Editor and select Edit > Execute. To further familiarize yourself with the features of the Script Editor, executing scripts, and saving scripts to a file in the Maya script directory refer to the appropriate sections in the Maya documentation and users guides. This book, Using Maya: MEL, provides a general overview of using MEL commands, procedures, and scripts. For detailed information about particular MEL commands, please see the MEL Command Reference. As you learn MEL, youll find that youll need to learn more about Mayas dependency graph nodes. The online Node and Attribute Reference documentation describes Mayas dependency graph nodes in detail.

MEL
14

PART 1

MEL FEATURES
Using MELs features includes using MEL commands and creating MEL scripts. This book describes how to get the most out of MELs features by focusing on using MEL commands, creating MEL scripts, and exploring example scripts called Maya Gems. Commands MEL includes a wide variety of commands for all aspects of using Maya. For more information, see Chapter 3, Introducing Commands. Scripting Scripting is using MEL to create scripts. For more information, see Chapter 6, Introducing Scripting. Maya Gems Maya Gems are examples of MEL scripts. See Chapter 16, Introducing Maya Gems.

MEL
15

MEL FEATURES | 2

MEL
16

PART 1

PART 2

COMMANDS

INTRODUCING COMMANDS

UNDERSTANDING COMMANDS
MEL includes a wide variety of commands for all aspects of using Maya. Some typical examples of using MEL commands include quickly creating objects, precisely moving objects, and working more efficiently with objects. For example, you can use a MEL command to create a sphere named bigBoy with a radius of exactly 27.5 units:
sphere -radius 27.5 -name bigBoy;

You can then enter this MEL command to rotate bigBoy 90 degrees around the Z-axis:
rotate -r 0 0 90 bigBoy;

As another example, lets say you are creating a joint with the joint tool and you want to move the joint 5 units in an X-axis direction. You could execute the following MEL command without having to interrupt the joint creation:
move -r 5 0 0;

MEL COMMAND DOCUMENTATION


The MEL Command Reference online documentation describes each command, providing information regarding usage, syntax, return values, and examples. It lists the commands in alphabetical order and by function. After you become familiar with MEL command syntax, keep in mind that you can display a list of valid flags for a command by entering help followed by the command name in the Script Editor. Example
help move;

CUSTOMIZING WITH MEL


You can use MEL to assign commands to shelf icons, to make your own hotkeys, and to save most user preferences. You can also customize the Heads Up Display to add your own information.

MEL
19

INTRODUCING COMMANDS | 3
Customizing with MEL

MEL
20

PART 2

USING COMMANDS

ENTERING COMMANDS
Maya offers several ways to enter MEL commands; using the Script Editor or Command Line are the most common ways. You can also execute commands in script files, Maya ASCII (.ma) files, shelf icons, hotkeys, and expressions. Most often, however, you enter commands in the Script Editor. Regardless of how you enter the commands, all MEL commands must terminate with a semicolon. The following are examples of MEL commands:
sphere -name roundy; setAttr roundy.translateX 7; whatIs ls; help ls; ls -typ nurbsSurface;

USING THE COMMAND LINE


You can use the Command Line to enter MEL commands. If the Command Line is not displayed, select Options > Command Line in the Maya main menu. Although you can enter commands in both the Command Line and the Script Editor, there are some important differences: You can execute commands from the Command Line with the Enter key on either the numeric keypad or the alphanumeric keyboard. The Script Editor executes with only the numeric Enter key. The Command Line has only a single line for executing a MEL command. To enter more than one MEL command, enter the commands on a single line separated by semicolons (;). Only the last line of results is displayed to the right of the Command Line. The Script Editor displays all results.

GETTING COMMAND RETURN VALUES


Many MEL commands return a value. To capture this return value, you can use lefthand single quotes or the eval command.

MEL
21

USING COMMANDS | 4
Command modes

Using left-hand single quotes


Enclose a command within left-hand single quotes () to return command output. You can then assign this output to a variable and display it in the Script Editor. Example
string $a[]; $a = particle -p 5 0 5 -name Sun; print($a);

The first statement defines an array named $a. The second statement executes the MEL command in the quotes and assigns the output of the command to $a. The third statement displays the contents of $a to the Script Editor as follows:
Sun SunShape

You can store and display the results for any MEL command. The type of value returned is determined by the command you use. In the example above, the particle command returns a string array. So, the variable on the left hand side of the equal sign also needed to be of type string array to accept this return value.

Using the eval command


The eval command executes a command and also lets you capture the return value. This has an advantage over left-hand single quotes because you can build a command from a string. As with the left-hand single quotes, you can assign the output to a variable and display it. Example
string $command = "sphere"; eval($command + " -r 5");

The first statement assigns the string sphere to the variable $command. The second statement appends -r 5 to the string sphere and executes the complete command sphere -r 5. This creates a sphere with a radius of 5 grid units. For more information on the eval command, see the online documentation for administration commands.

COMMAND MODES
MEL command options typically act in one or more of the following modes: query, edit, and create. Query mode is for finding out the value of something, edit mode is for changing the value of something, and create mode is for creating something. In the online MEL Command Reference, the command option descriptions include a Q, E, or C to indicate query mode, edit mode, and create mode.

MEL
22

PART 2

USING COMMANDS | 4
Commands in expressions

COMMANDS IN EXPRESSIONS
You can execute MEL commands and procedures in an expression. However, your scene might malfunction if you execute commands that: disconnect or connect attributes delete or create objects or other items Rewinding your animation does not undo MEL command execution in an expression. For instance, if your expression executes MEL commands to create a pair of spheres, rewinding doesnt delete the spheres. Moreover, playing the scene again creates another pair of spheres. Although you can undo MEL commands by selecting Edit > Undo, this might not work if your scene is malfunctioning. Note also that you can undo only as many operations as is allowed by the Queue Size setting. To set the Queue Size, select Options > General Preferences. When you execute a command from the Command Line, status information appears in the Script Editor and the Command Lines response area. This information is not displayed when a command executes in an expression. For more information about expressions, please refer to Using Maya: Expressions.

COMMANDS

MEL
23

USING COMMANDS | 4
Commands in expressions

MEL
24

PART 2

CUSTOMIZING WITH MEL

MAKING SHELF ICONS


You can assign MEL commands to shelf icons. This lets you customize the Maya interface so that the commands you use frequently are displayed as icons on a shelf. To create a shelf icon for a group of MEL commands, type the commands in the lower portion of the Script Editor. Highlight the commands, then use the middle mouse button, to drag the highlighted MEL commands to the shelf. This creates a button on the shelf where you dragged the commands. These commands will be executed whenever you click that button. There is a default icon image for MEL commands. To change the icon image, use Windows > Settings/Preferences > Shelves. You can also presswhen making a menu selection to place an icon for that action on the shelf. If you middle-mouse drag the icon into the Script Editor, the name of the MEL command is displayed.

MAKING HOTKEYS
Custom hotkeys are MEL commands that are assigned to keyboard shortcuts such as Ctrl-R. With hotkeys, you can execute frequently used MEL commands quickly and easily at any time. To assign a MEL command to a Hotkey, select Window > Settings/Preferences > Hotkeys to display the Hotkey Editor. For complete information on using the Hotkey Editor, see Using Maya: Essentials Assigning Hotkeys You can assign any MEL command to hotkeys. Here are some common hotkey tasks and their respective MEL commands, including: parenting an object
parent;

changing the view layout


paneLayout -e -cn right3 $gMainPane;

displaying the Attribute Editor


editSelected;

MEL
25

CUSTOMIZING WITH MEL | 5


Saving preferences using userSetup.mel modifying Mayas preferences
commandEcho -state (! commandEcho -q -state); setShelfVisible (! isShelfVisible);

keyframing an object
setKeyframe -at translate;

displaying the Tool Settings window


toolPropertyWindow;

adding a dynamic field, for example, a turbulence field


turbulence -name turbulence -magnitude 5 -frequency 0.4;

showing hidden objects


showHidden;

selecting all objects


select -all;

You can assign any available hotkeys to these tasks.

SAVING PREFERENCES USING USERSETUP.MEL


You can use the user interface to save most Maya user preferences. To retain preferences not saved in the user interface, create a text file called userSetup.mel file in your scripts directory. Whenever you launch Maya, the MEL commands in it execute. An example command used in the userSetup.mel file is the following:
alias djs jointDisplayScale;

This creates an alias, djs, that lets you set the joint size without using the Display > Joint Size menu or typing jointDisplayScale. You can enter the djs alias with a joint size in the Command Line or Script Editor:
djs 1.5;

The joint size is set to 1.5.

Important The scene is cleared of all objects after the commands in the userSetup.mel file are executed. Therefore, any scene elements created using the userSetup.mel file will have been removed when Maya comes up.

ADDING HEADS UP DISPLAY OBJECTS


You can customize the Heads Up Display by adding your own information. You do this by creating Heads Up Display objects in your userSetup.mel file. The example userSetup.mel file below does the following:

MEL
26

PART 2

CUSTOMIZING WITH MEL | 5


Adding heads up display objects The first command in the script creates a Heads Up Display object that shows the selected objects position. The information is placed at the top right (the -section 4 flag) and 5 lines down (-block 5) so it shows up under the Object Display information. If Object Display is turned on, the position information shows up as the last line. If Object Display is turned off, the position information shows up in the top right corner. The second part of the script adds a menu item to the Display > Heads Up Display menu to control the state of the new Heads Up Display object. This works only if you have created a script called objectPosition.mel. See headsUpDisplay command for more information.
// Create custom HUD objects // Note: This assumes that there is a script called objectPosition.mel // To create a script like this for testing, see the command documentation // for the headsUpDisplay command. // headsUpDisplay -section 4 -block 5 -label "Position:" -command "objectPosition()" -event "SelectionChanged" -nodeChanges "attributeChange" HUDObjectPosition; // Add menu items to control the custom items // global string $gHeadsUpDisplayMenu; // Add a divider to separate Maya items from custom items menuItem -parent\ $gHeadsUpDisplayMenu -divider true; // Add one menu item per heads up display object created above // menuItem -parent $gHeadsUpDisplayMenu -checkBox true -label "Object Position" -command "headsUpDisplay -e -vis #1 HUDObjectPosition" -annotation "Object Postion: Toggle the display of object position"\ myObjectPostionItem;

COMMANDS

MEL
27

CUSTOMIZING WITH MEL | 5


Adding heads up display objects

MEL
28

PART 2

PART 3

SCRIPTING

INTRODUCING SCRIPTING

UNDERSTANDING SCRIPTING
Scripting is the process of creating Maya Embedded Language (MEL) scripts. A script is a collection of MEL commands or MEL procedures. By creating scripts, you can go automate tasks you might otherwise do with Mayas user interface, you can get under the hood to access all of Mayas features, and you can extend and customize the interface.

SETTING THE SCRIPTING ENVIRONMENT


To set the scripting environment, you need to consider the following topics. Script files Setting script paths Using procedures in scripts

Script files
A MEL script file (*.mel) is a file that contains MEL commands, MEL procedures, or both. Typically, you use a MEL script to execute a sequence of commands. For example, you might write a script to create a wall-shaped object and then apply a brick texture to it. You can write a MEL script using a text editor then save the MEL script in a file on disk. MEL scripts use the file extension .mel. You can use scripts for different scenes and in different work sessions. When you execute a MEL script, it does not become part of the scene; you must execute the script each time you want to repeat the action.

Setting script paths


By default, Maya looks for your MEL scripts in your scripts directory. By default, this location is under your login name. Example locations follow: The simplest way to make your scripts executable is to put them here. You can add directories to the default path that Maya uses to find scripts. There are two Maya scripts directories: maya/scripts

MEL
31

INTRODUCING SCRIPTING | 6
Setting the scripting environment maya/version/scripts Maya finds and runs scripts that are in the maya/scripts directory regardless of which version of Maya you use. Maya finds and runs scripts that are in the maya/ version/scripts directory only if you are using the matching version number of Maya. For example, maya/4.5/scripts is seen only by Maya 4.5.

Using procedures in scripts


You can use global or local procedures in MEL scripts. Global procedures are visible outside their files; local procedures are visible only within their files. If Maya encounters a command without a definition, it searches through the script paths for a MEL script with the same basename as the command. When it finds the file, it declares all the global MEL procedures within that file. Furthermore, any global procedures with the same basename as the command are executed. For example, suppose you execute the command sayWhat. Since there is no command sayWhat, Maya searches through all its script paths for a file called sayWhat or sayWhat.mel. If in one of the script directories, it finds the file sayWhat.mel script with the following contents:
proc red5() {print("red5 standing by...\n");} global proc sayWhat() {print("sayWhat online\n");} global proc GoGo() {print("GoGo online\n");}

Then the global procedures sayWhat and GoGo are declared and the sayWhat procedure is executed. The result is:
sayWhat online

Since the GoGo global procedure has been declared; you could now enter GoGo in the Command Line or Script Editor to execute it.

Using Maya internal script files


Maya has many MEL scripts it uses for its user interface and other operation details. You can examine these scripts to see the techniques of professional script writers at Alias|Wavefront. The scripts are in the startup and others directories at these locations by default: where X.X is the release number of Maya.

Caution Do not modify or insert scripts in these directories; they hold scripts for Maya user interface operation. Changes to these scripts might interfere with Maya operation. If you want to modify scripts in this directory to alter the Maya interface, copy them to your local scripts directory first. If a script in your local scripts directory has the same name as a script in the Maya internal script files directory, the one in your local scripts directory executes.

MEL
32

PART 3

USING THE SCRIPT EDITOR

OPENING THE SCRIPT EDITOR


To open the Script Editor, select Window > General Editors > Script Editor or click (the Script Editor icon) at the bottom right of the Maya window.The following options are available: Open Script Source Script Save Selected Execute Clear History Clear Input Echo All Commands Show Line Numbers Show Stack Trace

EDIT COMMANDS
The following table lists the keyboard commands available in the Script Editor. (They are also available in the Expression Editor and some input boxes.) Command Definition Copy Cut Paste Platform

OPENING A SCRIPT
You can open a script to examine, execute, or troubleshoot it. Opening a script doesnt execute it. It simply displays the script in the input section of the Script Editor.

MEL
33

USING THE SCRIPT EDITOR | 7


Sourcing a script You can execute some or all of a script displayed in the input section of the Script Editor by highlighting it with your mouse and pressing your keyboards numeric Enter key. Opening a script is useful when you want to drag some or all of it to the shelf to create an icon there. You can click the icon to execute the script. See "Making shelf icons" on page 25 for details. To open a script: 1 Select File > Open Script from the Script Editor. A file browser appears. 2 Choose the script to be opened.

SOURCING A SCRIPT
Sourcing a MEL script file executes all of the MEL commands and declares all global procedures that are contained within the script file. If you modify a procedure in a script file, Maya will not register the changes to that procedure until you source its script file. This is because Maya keeps executed procedures in memory. When you source a script file, Maya rereads the procedures in that script file. To source a script: 1 Select File > Source Script from the Script Editor. A file browser appears. 2 Choose the script to be sourced. After you source the script, all MEL commands in that file execute. All global procedures in the script are declared, but not executed. The MEL commands are executed in the order in which they appear in the file, provided there are no errors. If an error occurs, execution halts and no further procedures are loaded. When you source a MEL script, local procedures are not declared or executed. However, if you declare a local procedure by entering it in the Script Editor or Command Line, the procedure is declared globally and you can execute it at any time. Executing a procedure is essentially the same as executing a MEL command. This is useful when you want to source a MEL script file and have that action execute a procedure contained within that file. To do this, first declare the procedure, then declare the command that executes the procedure via a file browser.

SAVING SCRIPT TEXT


Use the File > Save Selected command from the Script Editor to save script text. You can either highlight text from the command input (bottom) or status message (top) portion of the Script Editor. Maya will save the highlighted text in a .mel file in the directory you specify.

MEL
34

PART 3

USING THE SCRIPT EDITOR | 7


Executing a script

EXECUTING A SCRIPT
When you want to execute a previously sourced script, you can enter the script name in the command input (bottom portion) of the Script Editor and do one of the following: press Ctrl + Enter press the Enter key on the numeric keypad select Script > Execute from the Script Editor You can also use these commands to execute a script definition that you have open in the Script Editor. If no part of the MEL script definition fails, then the definition is moved from the bottom portion to the top portion of the Script Editor. Otherwise, the definition is not moved and an error message is displayed in the top portion of the Script Editor.

Tip You can execute just a portion of the MEL script by first highlighting it and then executing (Ctrl+Enter). Executing highlighted script will not remove any of the script from the bottom portion of the Script Editor.

CLEARING STATUS MESSAGES


To clear status messages (top portion of the Script Editor), select Edit > Clear History from the Script Editor. This will delete all of the status message text. Be careful when using this command as there is no way to undo it.

CLEARING COMMAND INPUT


To clear command input text (bottom portion of the Script Editor), select Edit > Clear Input from the Script Editor. This will delete all of the command input text. Be careful when using this command as there is no way to undo it.

ECHOING COMMANDS
As you work in Maya, corresponding MEL commands often appear in the top part of the Script Editor. By default, only the most significant commands are displayed. You can display virtually all commands associated with your Maya actions by selecting Script > Echo All Commands in the Script Editor. Doing this helps you learn which MEL commands trigger actions. There is not always a one-to-one correspondence between your actions in Maya and the commands echoed to the Script Editor. For example, if you use a script to open the Attribute Editor, several MEL commands appear in the Script Editor (with echoing on):
buildObjectEdMenu MayaWindow|menu4|menuItem56; editSelected; editMenuUpdate MayaWindow|menu2;

SCRIPTING

MEL
35

USING THE SCRIPT EDITOR | 7


Showing script line numbers However, only the following MEL command is needed to bring up the Attribute Editor.
editSelected;

Also, there are not always corresponding MEL commands echoed to the Script Editor for some actions. For example, when you close the Attribute Editor nothing is echoed to the top portion of the Script Editor. To turn off echoing, select Script > Echo All Commands again from the Script Editor.

SHOWING SCRIPT LINE NUMBERS


If you have problems executing a long script because of an error, turn on script line numbers so you can find the error more easily. To display the line numbers of erring statements, select Edit > Show Line Numbers from the Script Editor. When you turn the Show Line Numbers option on, Maya displays the script line number next to the error message in the Script Editor status message box (top portion) as shown in the following figure.

The script line number is listed next to the error message.

To turn line numbers off, select Edit > Show Line Numbers again from the Script Editor menu. Maya saves the Show Line Numbers setting for future work sessions. If you turn on line numbers, they appear in the Script Editor the next time you run Maya.

SHOWING THE STACK TRACE


If you have problems executing a script with embedded script files, turn on the stack trace option to display script errors within the file hierarchy. To display a scripts stack trace, select Script > Show Stack Trace from the Script Editor. Maya displays the files stack trace in a window and an error message in the Script Editor.

MEL
36

PART 3

USING THE SCRIPT EDITOR | 7


Showing the stack trace

// Error: file: /maya/scripts/level3.mel line3: Cannot link to sassafrass. Check number and types of arguments expected on procedure definition. //

SCRIPTING

MEL
37

USING THE SCRIPT EDITOR | 7


Showing the stack trace

MEL
38

PART 3

USING SCRIPT NODES

UNDERSTANDING SCRIPT NODES


Script nodes are a way of storing a MEL script in a Maya scene file. Script nodes also contain all of the MEL commands used to create the user interface and is saved with the Maya file. You can use script nodes in a variety of ways. You can designate that a script node executes its script: when the node is read from a file before or after rendering a frame before or after rendering an animation when a file is closed using File > Open or File > New A script node has three attributes: Before, After, and Type. Depending on the Type of script, the Before and After attributes specify when the script executes.

CREATING SCRIPT NODES


You can create script nodes using the Expression Editor. To create a Script Nodes: 1 2 Select Window > Animation Editors > Expression Editor. In the Expression Editor, select Select Filter > By Script Node Name. Any existing Script Nodes are displayed in the Script Nodes list. 3 4 5 6 Enter the script in the Script window of the Expression Editor. Enter a name in the Script Node Name box. Specify if you want the script to be a Before or After script. Click the Create button. This creates the script node. Now you can specify the Type. 7 Select one of the following types of script nodes from the Execute On pulldown menu.

MEL
39

USING SCRIPT NODES | 8


Testing scripts
Demand

Executes the script when you explicitly request it using the scriptNode command (see the online command documentation for information on the scriptNode command. The before and after attributes are ignored in the this type of script. If youve designated the script as a before script, the script executes when the file is read in batch mode. If youve designated it as an after script, it executes when the file is closed or dereferenced in batch mode, or when the node is deleted. If youve designated the script as a before script, the script executes when the file is read when running Maya is in graphical user interface mode. I If youve designated it as an after script, it executes when the file is closed or de-referenced in graphical user interface mode, or when the node is deleted.

Open/Close

GUI Open/ Close

UI Configuration (Internal)

The before script contains the user interface configuration information. It is automatically generated either by Maya or a plug-in to save the panel layout and editor state information. This script node executes its script when you open a file. After execution, the node is deleted. The after script is never executed. This node will not exist if a file is referenced or imported.
Software Render

If youve designated the script as a before script, the script executes before an animation is rendered. If youve designated it as an after script, it executes after an animation is rendered. If youve designated the script as a before script, the script executes before a frame is rendered. If youve designated it as an after script, it executes after a frame is rendered.

Software Frame Render

8 9

Click the Edit button to assign the type to the script node. If you want to add another script node, click the New Script Node button. The Script window and Script Node Name box is cleared so you can enter a new script node.

TESTING SCRIPTS
You can test script nodes using the Expression Editor. To test a script: 1 2 3 4 Select Window > Animation Editors > Expression Editor. In the Expression Editor, select Select Filter > By Script Node Name. Enter the script in the Script window, or select an existing script from the Script Nodes list. Click the Test Script button. Errors are displayed in the Script Editor.

MEL
40

PART 3

USING SCRIPT NODES | 8


Editing script nodes

EDITING SCRIPT NODES


You can edit script nodes using the Expression Editor. To specify an editor for script editing: 1 2 3 Select Window > Animation Editors > Expression Editor. In the Expression Editor, select Select Filter > By Script Node Name. Select an editor form the Editor pulldown. To edit a script node: 1 2 3 4 5 Select Window > Animation Editors > Expression Editor. In the Expression Editor, select Select Filter > By Script Node Name. Select the script node you want to edit in the Script Nodes list. Edit the script node in the Script window. If you want to undo your changes, click Reload. Maya reloads the original script node. 6 To clear the Script window, click the Clear button.

SETTING SCRIPT NODE EXECUTION


To set script node execution: 1 Select File > Open Scene. or Select File > Open and click Options in the Open Scene window. 2 Click the checkbox to turn Execute Script Nodes on or off.

DELETING SCRIPT NODES


You can delete script nodes using the Expression Editor. To delete a script node: 1 2 3 4 Select Window > Animation Editors > Expression Editor. In the Expression Editor, select Select Filter > By Script Node Name. Select the script node you want to delete in the Script Nodes list. Click the Delete button.

SCRIPTING

MEL
41

USING SCRIPT NODES | 8


Deleting script nodes

MEL
42

PART 3

9
VARIABLES

VARIABLES AND CONSTANTS

A variable is a symbolic name that stands for a modifiable value. There are several similarities among the variables for the data types. All variables begin with a dollar sign. Variable names cannot include spaces or special characters. You can use underscores and numbers as long as the variable name does not start with a number. Variable names are case sensitive. In other words, $temp is a different variable name than $Temp. Examples
int int int int int int $radical7Mark; HEYchief; $ nine; $_VAL_ID___AIT_; $howdyYall; $1Bill; // // // // // // VALID ERROR: ERROR: VALID ERROR: ERROR: Does not start with "$". Does not start with "$". Invalid character in name. Number at start of name.

The following table shows the five variable types:

Type int float string vector matrix

Meaning integer (...-2, -1, 0, 1, 2...) fractional numbers one or more characters three floats array of float arrays

Examples 10, -5, and 0 392.6, 7.0, and -2.667 Whats up, chief? <<3, 7.7, 9.1>> <<1.1, 2, 3; 6.7, 5, 4.9>>

Any of the above types, except for matrix, can be an array. An array is a sequence of a certain data type. For example, a three-element int array is just an int, followed by an int, followed by an int. You can think of the matrix type as an array of float arrays or a two-dimensional array of floats.

MEL
43

VARIABLES AND CONSTANTS | 9

Declaring and assigning variables


Declaring a variable indicates that a variable with a certain name is a certain data type. Assigning a variable gives a declared variable a specific value. The examples below show standard ways of declaring and assigning variables in one step:
int $temp = 3; float $Temp = 222.222; string $tEmp = "Heya kid."; vector $teMp = <<1, 2.7, 3.2>>; matrix $temP[2][3] = <<4.5, 1, 0.2; -13, 9911, 0.007>>;

When you explicitly declare matrix variables, you must include the size of the twodimensional array. The following examples show declaration and assignment for int, float, string, and vector arrays. Examples: Array declaration and assignment
int $TEmp[5] = {100, 1000, -70, 2, 9822}; float $TeMp[4] = {43.3, -10.7, 0, 82.5}; string $TemP[3] = {"Lord", "Flies", "cool brown fox2."}; vector $tEMp[2] = {<<0, 0, 0>>, <<0.01, -2, 16>>};

If a variable is declared with no assignment, all values are assigned 0, except for strings which are assigned empty quotation marks. Examples: Declaration
float $teMP; string $TEMp[3]; vector $TEmP[2]; matrix $TeMP[3][2]; // // // // Assigned Assigned Assigned Assigned 0; {"", "", ""}; {<<0, 0, 0>>, <<0, 0, 0>>}; <<0, 0; 0, 0; 0, 0>>;

If a variable is declared or used without its type being specified, it is declared implicitly as the type that is being assigned to it. Examples: Implicit declaration
$tEMP = 0.0; string $TEMP[]; $trip = "heya Buddy"; $rip = {1, 2, 3, 4}; $lip = <<1, 2.1; 3, 4>>; $flixp = $TEMP; // // // // // // float zero element string array string four element int array two by two matrix zero element string array

Note that the value 0.0 is a float while a value of 0 is an int. This determines whether a float or an int is created during implicit declaration. Implicit declaration is not recommended because it is not as clear as explicit declaration of variables. Reserved words Reserved words are words that have inherent meaning in MEL. These words can specify a variable type, control logic, or represent a value. The following are reserved words in MEL. break case continue default do

MEL
44

PART 3

VARIABLES AND CONSTANTS | 9

else if off switch

false in on true

float int proc vector

for matrix return while

global no string yes

Data type keywords

int

float

vector

string

matrix

Boolean constant keywords

yes

no

on

off

true

false

Flow control keywords

if break

else continue

for default

while switch

do case

in

Other keywords

global

return

source

catch

alias

proc

Like variable names, reserved words are case sensitive. So, while int is an int type, Int is not. Actually, alias, source, and catch are also reserved words; since they behave like commands, they are not included in the table above.

Strings
A string is a sequence of alphabetical, numerical, or special characters. You can concatenate strings with the + operator.
string $what = "Whale"; string $title = "Great" + " White " + $what;

This creates the title variable with the contents Great White Whale.

Vectors
To access the first, second, or third component of a vector, use a period (.) followed by x, y, or z. Example
vector $LOS = <<1, 2, 7>>; float $firstComponent = $LOS.x; // Assigned 1

SCRIPTING

MEL
45

VARIABLES AND CONSTANTS | 9

float $secondComponent = $LOS.y; // Assigned 2 float $thirdComponent = $LOS.z; // Assigned 7

Unfortunately, attempting to assign a number to a vector component causes an error. To set only one component of a vector while preserving the other components, use the method below:
vector $LOCK = <<7, -4, 9>>; $LOCK = <<$LOCK.x, $LOCK.y, 3>>; // Assigned <<7, -4, 3>>

The example below causes an error:


$LOCK.z = 3000; // ERROR: Assigning to vector component.

Often, however, when accessing a vector component, you must surround it with parentheses as follows. Example
print $LOCK.x; // ERROR print($LOCK.x); setAttr persp.scaleX $LOS.x; // ERROR setAttr persp.scaleX ($LOS.x);

Arrays
You can declare an array of int, float, string, or vector types. The number of elements can be explicitly stated when the array is declared. Remember that when accessing an element of the array, the index of the first element is 0. This means that the maximum index of an array is always one less than the number of elements in the array. Example
string $array[3] = {"first\n", "second\n", "third\n"}; print($array[0]); // Prints "first\n" print($array[1]); // Prints "second\n" print($array[2]); // Prints "third\n"

The size of an array increases automatically as needed. Lets say you have an array with two elements. If you try to assign to a third element of the array, the array size automatically increases to three elements. If you query the value of an element beyond the array size, a value of 0 is returned. For a string array, empty quotation marks would be returned.
int $scores[]; // Declared as a zero element array. $scores[150] = 3; // Now a 151 element array. $scores[200] = 5; // Now a 201 element array.

The second statement above gives the array 151 elements and assigns element index 150 the value 3. The third statement expands the array to 201 elements and assigns element index 200 the value 5. When you assign a value in an array, Maya reserves memory for all elements up to that number. If you are not careful, you can exceed the capacity of your computer with a single array declaration. For example, the following two statements would force you to quit Maya on most computers:
int $bigBoy[]; $bigBoy[123456789] = 2; // DANGER

MEL
46

PART 3

VARIABLES AND CONSTANTS | 9

To remove all elements of an array use the clear function. To find the size of an array use the size function. Example
string $hats[3] = {"blue", "red", "black"}; print("There were " + size($hats) + " hats.\n"); clear($hats); print("But now there are " + size($hats) + ".\n");

The output from the above statements is:


There were 3 hats. But now there are 0.

Matrices
You can think of a matrix as an array of float arrays or as a two-dimensional array of floats. Unlike arrays, the size of a matrix cannot be altered after it has been created, and attempting to access matrix elements that do not exist will produce an error. The matrix size must be specified when it is created. Examples
matrix $a1[][] = <<1; 4>>; // ERROR: matrix $a2[][]; // ERROR: matrix $a3[2][1]; // VALID: $a3[0][1] = 7; // ERROR: $a3[1][0] = 9; // VALID Size not specified Size not specified Creates <<0; 0>>; Element doesnt exist

If a matrix is declared but not assigned a value, all of the elements in the matrix are assigned 0. Example
matrix $a4[2][4] = <<-3.4, 6, 201, 0.7; 4, 2, 9.3, 1001>>;

If you are thinking of a matrix as a two-dimensional array, the first index represents the row and the second index represents the column. matrix $a4[2][4] row 0 row 1 column 0 -3.4 4 column 1 6 2 column 2 201 9.3 column 3 0.7 1001

If you are thinking of a matrix as an array of float arrays, the first index represents the float array and the second index represents the index in that float array. matrix $a4[2][4] float array 0 float array 1 index 0 -3.4 4 index 1 6 2 index 2 201 9.3 index 3 0.7 1001

SCRIPTING

MEL
47

VARIABLES AND CONSTANTS | 9

Object attributes
An attribute is a characteristic or parameter of an object or other item in a scene. There are many ways to set attributes in Mayawith the Attribute Editor, MEL script, Toolbox tools, or expressions. You can set attributes to control virtually everything you can see in the work space. For example, a NURBS sphere has attributes scaleX, scaleY, scaleZ, rotateX, and so on. You can set these attributes for the object with the Attribute Editor right after you create the object. Object attribute names An object attribute name has the following format:
objectName.attributeName

where objectName is the objects name and attributeName is the attributes name of the object. A period divides the two parts of the name. Do not use spaces or special characters other than an underscore in an attribute name. Example Create a sphere called Brawl with the following command:
sphere -name Brawl;

You can get the value of one of its attributes:


float $yScale = getAttr Brawl.scaleY;

Brawl.scaleY is the full name of the scaleY attribute of the object Brawl. Path If two objects in a scene have different parents, they're permitted to have the same name. For example, a scene could have two spheres named doughnutHole if they both had different parents. One sphere could have a parent of GroupA and the other sphere could have no parent at all. You could specify each sphere by indicating if it had the GroupA parent or no parent at all. When you refer to an object that has the same name as some other object you must include the object's path by using the following format.
pathname|objectname

where pathname is the parent of the object and the objectname is, of course, the object's name. A pipe character (|) divides the path from the object name. Example
sphere -name doughnutHole; group -name GroupA; sphere -p 3 0 0 -name doughnutHole;

Now we have two objects named doughnutHole. But, one object has GroupA as a parent and the other has no parent. The following statement generates an error because Maya does not know which doughnutHole object to set the scaleY attribute for.
setAttr doughnutHole.scaleY 3.3; // ERROR: Which one?

MEL
48

PART 3

VARIABLES AND CONSTANTS | 9

To eliminate this error, you must enter the path of the attribute. For example to specify the doughnutHole that has GroupA as a parent you could use the following command.
setAttr GroupA|doughnutHole.scaleY 3.3;

The pipe character (|) indicates that the object to the left of the character is the parent of the object to its right. To specify an object that does not have a parent just place a pipe character to the left of the object name.
setAttr |doughnutHole.scaleY 0.3;

You can specify the full pathname of an object by giving the names of all the parents in an object hierarchy. Just separate each parent with a pipe character. Example
group -name GroupB GroupA; setAttr |GroupB|GroupA|doughnutHole.scaleY 1;

Possible data types for object attributes Each attribute has a specific data type. Geometric objects, particle objects, and other items in Maya may have attributes with these data types.

Data type float int boolean

Meaning fractional numbers integer (...-1, 0, 1, 2...) 0 or 1

Example attribute Ball.translateX BallShape.spansU Ball.visibility

Example data 2.6, 7.0, -9.1 -289, 33, 0 on, off, yes, no, 1, 0, true, false

Consider a particle called Fire created with the following command:


particle -name Fire -position 7 0 7;

Particle objects, such as the one created above, can additionally have the following attribute data types:

Data type vector array double array

Meaning array of vectors array of floating point numbers

Example attribute FireShape.position FireShape.lifespan

Example data {<<3.2, 7.7, 9.1>>, <<7, 10, 2.2>>} 1.333 1.666

You can query or set an element of a vector or double array of a particle using the getParticleAttr and setParticleAttr commands, respectively.

SCRIPTING

MEL
49

VARIABLES AND CONSTANTS | 9

Example
float $Tmp[] = getParticleAttr -at position FireShape.pt[0]; vector $particlePosition = <<$Tmp[0], $Tmp[1], $Tmp[2]>>; setParticleAttr -at position -vv 0 0 7 FireShape.pt[0];

For the vector array data type, Maya represents the specified attribute for each particle of the object with a single element of an array. Note that pt[0] represents the particle index of the first particle created FireShape. Each element is made of three floating point numbers. In a double array, Maya represents the specified attribute for each particle with a floating point number.

Important In expressions, you can use an equals sign (=) to set or get value of a variable or attribute. In MEL scripts, you can use an equals sign (=) to set or get the value of variables only. In MEL scripts, use the MEL setAttr, getAttr, setParticleAttr, and getParticleAttr commands to set and get the values of attributes.

Global and local variables


Typically, youll use variables within a single procedure. These variables are called local variables because they are only visible within that procedure. Example
float $tester;

If you create a local variable of the same name in two procedures, the two variables are separate and unrelated. For example, suppose you create a variable named $tester in two procedures. Assigning or modifying the value of one of the $tester variables has no effect on the others value. If you want to create and maintain a variable in one procedure and also use it outside of that procedure, you can declare it as a global variable. Example
global float $counter;

Because you specified this as a global variable, you can set or read the value of this variable in any other MEL command or script. You must declare the global variable again wherever you intend to use that variable. Example
global float $crash = 8; global proc holy() { $crash = 7; print($crash + "\n"); } print($crash + "\n"); // Result: 8

MEL
50

PART 3

VARIABLES AND CONSTANTS | 9

holy(); // Result: print($crash + "\n"); // Result:

7 8

Although it might seem as if the procedure holy is using the global float crash, it is actually using a local integer variable that is created implicitly (see "Examples: Implicit declaration" on page 44). The only way to use a global variable within a procedure is to again declare the global variable before you use it. Example
global float $slash = 8; global proc moly() { global float $slash; $slash = 7; print($slash + "\n"); } print($slash + "\n"); // Result: moly(); // Result: print($slash + "\n"); // Result:

8 7 7

When you declare a global variable and assign a value to it in a single statement, the assignment of the global variable occurs only when that statement is first read by Maya. A global variable in a procedure is read when that procedure is defined. Example
global proc proof() { global float $fight = 7; $fight = 2; print($fight + "\n"); }

Until the procedure proof is read in, the variable fight is not declared. In other words, Maya is not yet aware of that variables existence. However, once this procedure is read in and defined, the variable fight is declared as a global float and assigned the value 7. After its declaration, the global variable is visible to all MEL commands. This means that the global variable can be used and modified by any MEL command. However, when proof is executed, fight is assigned the value 2. For example, after the proof is defined, the following commands would produce the given results:
print($fight + "\n"); // Result: proof; // Result: print($fight + "\n"); // Result: 7 2 2

You might be wondering what would happen if two procedures tried to declare and assign a value to the same global variable. Consider the following two script files (assumed to be placed in your scripts directory): Script file: crush.mel
global proc crush() { global float $sight = 7; print $sight; }

SCRIPTING

MEL
51

VARIABLES AND CONSTANTS | 9


Constants Script file: groove.mel
global proc groove() { global float $sight = 9; print $sight; }

A value is assigned to the global variable sight only the first time Maya reads each of these scripts. Example
crush(); // Result: groove(); // Result: crush(); // Result: 7 9 9

CONSTANTS
The only constants in MEL are Boolean constants. Boolean constants are actually int types that are either 1or 0 in value. The keywords true, on, and yes have a value of 1. The keywords false, off, and no have a value of 0.

DATA-TYPE CONVERSIONS
Data-type conversion lets you convert the value of one type to the value of another type. For example, when you convert a float with a value of 1.4 to an int, its value becomes 1. The table below is a summary of how each data type is converted to a different data type. Conversion To int float string vector matrix

int ($i) float ($f) string

perfect without fraction without fraction if starts with number, else 0

perfect perfect perfect if starts with number, else 0

perfect perfect perfect

<<$i, $i, $i>> <<$f, $f, $f>> perfect if starts with vector or floats with remaining elements 0 perfect

none none none

vector

length of vector without fraction

length of vector

3 floats separated by a space

perfect for [1][3] matrix, else none

MEL
52

PART 3

VARIABLES AND CONSTANTS | 9


Data-type conversions

Conversion To int float string vector matrix

matrix

for [1][3] matrix or smaller, length of matrix without fraction

for [1][3] matrix or smaller, length of matrix

none

for [1][3] matrix or smaller, perfect with remaining elements 0

perfect

A scalar type is a non-array type. There is no conversion from array to scalar types or from scalar to array types. Examples of type conversion
int $ski = 1.8; vector $crads = 1.7; int $wild = " 3.44 dogs"; vector $wrd = " 8 2.2 cat"; int $my = <<1, 2, 3>>; string $oo = <<6, 2.2, 1>>; matrix $so[1][3] = $wrd; float $mole = <<0.3, 0.4>>; vector $ole = <<2, 7.7>>; // // // // // // // // // Assigned: Assigned: Assigned: Assigned: Assigned: Assigned: Assigned: Assigned: Assigned: 1 <<1.7, 1.7, 1.7>> 3 <<8, 2.2, 0>> 3 "6 2.2 1" <<8, 2.2, 0>> 0.5 <<2, 7.7, 0>>

Automatic conversion
Mayas automatic type conversion lets you convert types without explicitly stating them. It also automatically converts the data type for you if the type specified is not acceptable. The "Examples of type conversion" on page 53 are all automatic type conversions. However, occasionally unexpected automatic type conversions can create a problem. Following are the rules concerning automatic type conversion. There are five main rules for automatic type conversion. In these rules, the word operand is used instead of value since operand stands for the value being operated on. Strings dominate all other types. Vectors dominate floats. Floats dominate ints. If one operand is an int type and the other is a float type, MEL converts the int to a float. Between vector and matrix types, the type on the left-hand side dominates. In assignment, the type on the left-hand side dominates (see "Declaring and assigning variables" on page 44). In an assignment operation, the type of the right-hand side is converted to the type of the left-hand side. The first four rules apply for sub-expressions during the computation of the right-hand side; a final conversion takes place when assigning to the left-hand side. The following table demonstrates the rules for automatic conversions.

SCRIPTING

MEL
53

VARIABLES AND CONSTANTS | 9


Limitations

Operation
int operator float float operator int int operator vector vector operator float vector operator matrix matrix operator vector matrix operator string string operator int

Resulting data type


float float vector vector vector matrix string string

Examples
$var1 $var2 $var3 $var4 = = = = 7 + 1.3; 7.9 + 2; 2 + <<4, 5, 6>>; 0007 + " Lives!"; // // // // Type: Type: Type: Type: float (8.3) float (9.9) vector <<6, 7, 8>> string ("7 Lives!")

In the last example, 0007 is an int of value 7, which is converted to a string and concatenated with Lives!. The result is a string which implicitly declares var4 to be of type string with value 7 Lives!.

Explicit conversion
There are two ways to explicitly convert a value of one type to another type. The most common way is to specify the type in parentheses before the value. For example:
$Z = (vector) "<<1, 2, 3>>"; // Type: vector (<<1, 2, 3>>) $cools = (float) 7; // Type: float (7) $ools = (string) 47.554; // Type: string ("47.554")

You can also explicitly convert a value to another type by specifying the type followed by the value in parentheses. For example:
$ly = vector("<<1, 2, 3>>"); // Type: $ooly = int(3.67); // Type: vector (<<1, 2, 3>>) int (3)

LIMITATIONS
Integer division truncation
When Maya executes arithmetic operations on constants and variables without a declared data type, it guesses the data type based on the values present. For instance, in this statement:
float $where = 1/2; // Result: 0

Maya treats 1 and 2 as integers because they have no decimal points. The expression divides integer 1 by integer 2. The integer result is 0 with a remainder of 1. Maya discards the remainder.

MEL
54

PART 3

VARIABLES AND CONSTANTS | 9


Limitations Because where is a float variable, Maya converts the integer value 0 to floating point value 0 (which is the same value), then assigns this value to where. To get the fractional component of the value, one of the integer operands needs to be converted to a float:
float $there = 1/2.0; // Result: 0.5

Maya treats 2.0 as a floating point number because it has a decimal point. The number 1 is converted to a float and a float division takes place resulting in the value 0.5 which is then assigned to there. Another way to retain the fractional part of the division is as follows.
float $youGo = float(1)/2;

Here the 1 value is converted to a float which causes the 2 value to also be converted to a float. This creates a float division, preserving the fractional part of the division.

Precision and maximum numerical sizes


For a string, matrix, or array, the maximum size is dependent only on the amount of memory available on your computer. Floats and ints, however, have limits on their precision and maximum size. The maximum size of an int is the same as in the C language and is machine dependent. On most computers this range is from -2,147,483,648 to 2,147,483,647. The maximum precision and range of a float is the same as a double in the C language and is machine dependent. Floats have limited precision, and round-off errors can accumulate in long calculations. However, since the precision for the float type is so high (about fifteen digits of accuracy), round-off errors usually do not become a problem.

Range wrap-around
Variables have limited ranges. When these ranges are exceeded, undesired results can occur. Examples
int int int int $mighty = 2147483647 + 1; // Result: $radical = -2147483648 - 1; // Result: $buddy = 2147483648; // Result: $man = 2147483647 + 2; // Result: -2147483648 2147483647 -2147483648 -2147483647

When the maximum range of a variable is exceeded, the value of the variable wraps around to the minimum range of the variable. Also, when the minimum range of a variable is exceeded, the value of the variable wraps around to the maximum range of the variable. Example
float $GG = 1.5 + 1000000000 * 3; // Result: -1294967294.5

In this example, the multiplication is done first due to operator precedence. The multiplication is performed on two ints, so the result type is an int. Because the value of this multiplication is over the maximum range of an int, the value wraps around. The following calculation illustrates what is occurring internally:
$GG = 1.5 + 1000000000 * 3; $GG = 1.5 + 3000000000; // Maxumum int range exceded $GG = 1.5 + 3000000000 + (2147483648) - (2147483648.0);

SCRIPTING

MEL
55

VARIABLES AND CONSTANTS | 9


Limitations
$GG $GG $GG $GG = = = = 1.5 + 3000000000 + (-2147483648) - (2147483648.0); 1.5 + 3000000000 - 4294967296; 1.5 + -1294967296; -1294967294.5;

For additional information, see "Precision and maximum numerical sizes" on page 55 and "Operator precedence" on page 65.

MEL
56

PART 3

10

MAKING STATEMENTS

UNDERSTANDING STATEMENTS AND OPERATORS


Statements act on or compare data by means of operators. There are four types of operators: Assignment Arithmetic Comparison Conditional Most operators use a value on the left-hand side and a value on the right-hand side of the operator. Note that if the types of these two values are different, one of the values will be automatically converted to the type of the other value, if possible. Operators work only on operands of the same type. For more information see "Datatype conversions" on page 52.

ASSIGNMENT
Use the assignment operator to set the value for a variable. The assignment operator is represented by an equal sign (=). The variable to the left of the equal sign is assigned the value to the right of the equal sign. For example:
float $counter = 5.3;

declares a float variable and assigns it a value of 5.3.

Assignment value
The result of the assignment operator is the type and value assigned to the variable on the left side of the equal sign. This result can be used as a constant of the same type and value. Example
float $owl; float $hotdog = ($owl = 5.3) + 6;

In the second line of this example, the float $owl is assigned a value of 5.3 and $hotdog is assigned a value of 11.3.

MEL
57

MAKING STATEMENTS | 10
Arithmetic

Chained assignment
Because an assignment has a value and the operation is assigned the value to the right of the operand (see "Operator precedence" on page 65), you can use chained assignment. Example
int $i1, $i2, $i3, $i4; $i1 = $i2 = $i3 = $i4 = 6; // All variables assigned 6

ARITHMETIC
You can use the following arithmetic operator symbols to add, subtract, multiply, compare, and perform other actions with variables. Symbol + * / % ^ Meaning plus minus or negation for int, float, matrix: multiply for vector: dot product divided by remainder of division cross product Used with these data types int, float, string, vector, matrix int, float, vector, matrix int, float, vector, matrix int, float, vector int, float, vector vector

Additionally, the matrix type can be used with the modulus (%) and divide (/) operators. However, these operations must have an integer or float as the right-hand operand. For more information about these exceptional operations, see "Matrices" on page 60.

Integers and floats


For integer and floating-point attributes and variables, the arithmetic operators work according to the rules of basic math. The modulus (%) operator is an operator commonly available in programming languages. It calculates the remainder of division as shown in the examples below. Example
int $card = 7 % 3; // Result: 1

This assigns card the value 1, the remainder of 7 divided by 3. The number 7 divided by 3 equals 2, with a remainder of 1.
float $bus = 0.5 % 3; // Result: 0.5

This assigns bus the value 0.5, the remainder of 0.5 divided by 3. The number 0.5 divided by 3 equals 0, with a remainder of 0.5.

MEL
58

PART 3

MAKING STATEMENTS | 10
Arithmetic

Strings
For details on how to use the + operator with strings, see "Strings" on page 45.

Vectors
For operations between vector variables, the ^ operator calculates the cross product of the vectors, and the * operator calculates the dot product. For all other operators, each component of one vector is operated on by its counterpart component in the other vector. Examples
vector vector vector vector $Vo $Vu $me $rf = = = = <<3, 9, 5>> + <<9, 2, 3>>; <<2, 3, 4>> - <<1, 2, 3>>; <<2, 3, 2>> / <<1, 2, 5>>; <<12, 3, 9>> % <<4, 2, 5>>; // // // // <<12, 11, 8>> <<1, 1, 1>> <<2, 1.5, 0.4>> <<0, 1, 4>>

The dot product returns a float. The dot product is often conceptualized as the product of the lengths of the two argument vectors multiplied by the cosine of the angle between these vectors. Example
vector $V1 = <<4, 6, 8>>; vector $V2 = <<2, 2, 2>>; float $F1 = $V1 * $V2; // 36 (dot product)

The result of the dot product (*) operator can be calculated with the following equation:
$F1 = ($V1.x * $V2.x) + ($V1.y * $V2.y) + ($V1.z * $V2.z);

Although most operations between a vector and an int or float implicitly convert the int or float to a vector, * operations are different. For * operations between a vector and an int or float, each component of the vector is multiplied by the integer or floating-point number. Examples
vector $tak = 3.2 * <<1, 3, -5>>; // <<3.2, 9.6, -16>>

vector $sak = <<0, 1.2, 9.1>> * 5; // <<0, 6, 45.5>>

The ^ operator works only with the vector data type. It represents the cross product operator, which returns a vector. Example
vector $V3 = <<2, 0, 0>>; vector $V4 = <<0, 3, 0>>; vector $V5 = $V3 ^ $V4; // <<0, 0, 6>> (cross product)

The cross product vector is in a direction that is normal to both of the argument vectors. The magnitude of this vector is the product of the lengths of the two argument vectors, multiplied by the sine of the angle between the two argument vectors. You can calculate the resulting cross product vector with the following equation:

SCRIPTING

MEL
59

MAKING STATEMENTS | 10
Arithmetic
$V5 = <<(($V3.y * $V4.z) - ($V3.z * $V4.y)), (($V3.z * $V4.x) - ($V3.x * $V4.z)), (($V3.x * $V4.y) - ($V3.y * $V4.x))>>;

Matrices
You can add and subtract only between corresponding elements of each matrix. The matrices must have the same number of rows and columns. Examples
matrix matrix matrix matrix $Va[1][4] $Vb[1][4] $Vc[1][4] $Vd[1][4] = = = = <<2, 0, 0, <<6, 3, 7, $Va + $Vb; $Va - $Vb; 2>>; 5>>; // <<8, 3, 7, 7>> // <<-4, -3, -7, -3>>

When you multiply matrices, the number of columns of the left-hand side matrix must be equal to the number of rows of the right-hand side matrix. The resulting matrix has the same number of rows as the left matrix and the same number of columns as the right matrix. Example
matrix $Ve[2][4] = <<4, 1, 1, 2; 3, 4, 5, 8>>; matrix $Vf[4][3] = <<7, 6, 0; 7, 5, 4; 2, 1, 6; 2, 0, 2>>; matrix $Vg[2][3] = $Ve * $Vf; // <<41, 30, 14; 75, 43, 62>>

When the right-hand side operand is a scalar, the modulus and division operators operate on each element of the matrix using the scalar as the right-hand side operand. The examples below illustrates this. Examples
matrix $Vh[1][4] = <<4, 9, 5, 2>> % 3; // <<1, 0, 2, 2>> matrix $Vi[1][4] = <<1, 2, 8, 4>> / 2; // <<0.5, 1, 4, 2>>

Shortcuts
Often in scripting you will want to assign a variable the value of itself operated on by some other value. The shortcut operations give you a quick and simple way to do this. You can use shorthand assignment operators with int, float, and vector data types. These operators provide no additional functionality or execution speed, but they might save you some typing time. For example, instead of writing:
$bus = $bus + 3.5;

You could write the following line instead:


$bus += 3.5;

Both statements do the same thing, but the second requires less typing. For any arithmetic operator, you can abbreviate the format:
variable = variable operator value

to this format:
variable operator= value

MEL
60

PART 3

MAKING STATEMENTS | 10
Arithmetic The following table shows all of the shortcut operators of this form, their expanded syntax, and their values. These operators are defined only for the int, float, and vector types. However, the += operator is also defined for the string type (see "Strings" on page 45).

Shortcut Syntax variable += value; variable -= value; variable *= value; variable /= value; variable %= value; Examples

Expanded Syntax variable = variable + value; variable = variable - value; variable = variable * value; variable = variable / value; variable = variable % value;

Value variable + value; variable - value; variable * value; variable / value; variable % value;

float $mice = 25.3; $mice -= 6; // $mice %= 4; // $mice /= 3; // vector $kick = <<2, 3, 4>>; $kick += <<7, 5, 1>>; //

$mice = $mice - 6; $mice = $mice % 4; $mice = $mice / 3; $kick = $kick + <<7, 5, 1>>

There is also a ^= operator that is only defined for a vector. This operation calculates a cross product on the left-hand side vector and the right-hand side vector operand. Example
vector $ice = <<1, 2, 3>>; $ice ^= <<2, 4, 4>>; // $ice = $ice ^ <<2, 4, 4>>

Increments and decrements


There are shortcut operators that can be used for incrementing and decrementing floats and ints by 1. The following table shows these operators, their expanded syntax, and their values.

Shortcut Syntax variable++; variable--; ++variable; --variable;

Expanded Syntax variable = variable + 1; variable = variable - 1; variable = variable + 1; variable = variable - 1;

Value variable; variable; variable + 1; variable - 1;

When the increment or decrement shortcut operator precedes the variable, think of the increment or decrement as occurring before the statement is executed. However, when the operator is after the variable, think of the increment or decrement as occurring after the statement is executed. SCRIPTING

MEL
61

MAKING STATEMENTS | 10
Comparison Examples
float float $crab $crab $eel = 32.3; $crab = $eel++; // $crab = 32.3; $eel = 33.3; = $eel--; // $crab = 33.3; $eel = 32.3; = --$eel; // $crab = 31.3; $eel = 31.3; // $crab = 32.3; $eel = 32.3;

$crab = ++$eel;

Warning If more than one increment or decrement shortcut operator acts on the same variable in the same statement, the order of evaluation of the operators is unpredictable. Try to avoid this situation.

COMPARISON
Comparison operators are used to specify logical and relational expressions.

Logical
The basis of logic is whether statements are true or false. Logical operators determine whether statements are true or false, then execute them appropriately. You can use logical operators with int, float, and vector data types. The values of each type correspond to being either true or false. An int or float value is considered false when its value, converted to type int, is 0. A vector is considered to be false when its magnitude value, converted to type int, is 0. All other converted values are considered to be true. The table below displays the symbol and logical meaning of the three logical operators:

Symbol || && ! Examples


if if if if if

Logic or and not

True only if: either left-hand or right-hand side is true both left-hand and right-hand sides are true right-hand side is false

(0 || 1) print("true\n"); (0 && 1) print("true\n"); (2 && <<3, 7.7, 9>>) print("true\n"); (! 5.39 && 7) print("true\n"); (<<0, 0, 0>> || 0) print("true\n");

// // // // //

True False True False False

if (! <<0, 0, 0>>) print("true\n");

// True

MEL
62

PART 3

MAKING STATEMENTS | 10
Comparison

Relational
Relational operators compare two values. They are valid with int, float, and vector data types. The truth of the statement depends on the relation of the left-hand side value to the right-hand side. The following table lists the relational operator symbols and the conditions when a statement using them is true.

Symbol < > == != >= <= Examples


if if if if if if

True only if the left-hand side is: less than the right-hand side greater than the right-hand side equal to the right-hand side not equal to the right-hand side greater than or equal to the right-hand side less than or equal to the right-hand side

(-2.5 < 1) print("true\n"); (16.2 > 16.2) print("true\n"); (-11 == -11) print("true\n"); (-11 != -11) print("true\n"); (-11 >= -11) print("true\n"); (1 <= 0) print("true\n");

// // // // // //

True False True False True False

When a vector type is operated on by the <, >, > =, or < = operator, its magnitude is used instead of the vector itself. The magnitude of the vector is of type float. Examples
if if if if (<<1, (<<1, (<<0, (<<0, 2, 2, 0, 5, 3>> 3>> 4>> 0>> < <<3, 2, 1>>) print("true"); <= <<3, 2, 1>>) print("true"); > <<3, 2, 1>>) print("true"); <= <<-3, -4, 0>>) print("true"); // // // // False True True True

When the == or != operator compares two vectors, the vectors themselves are used. If each component of one vector is the same as the corresponding component of the other vector, the vectors are equal. Examples
if (<<1, 2, 3>> == <<3, 2, 1>>) print("true"); // False if (<<1, 2.2, 3>> == <<1, 2.2, 3>>) print("true"); // True if (<<1.2, 2, 3>> != <<0, 0, 0>>) print("true"); // True

SCRIPTING

MEL
63

MAKING STATEMENTS | 10
Conditional

Tip Note the difference between the assignment operator (=) and the equality operator (==). Sometimes the error of using one instead of the other is hard to find. For example, using the assignment operator instead of the equality operator produces a value. This value can be used as a logical truth or falsehood. Mixing up these operators the other way is just as dangerous since a variable may be assigned a value when it was not intended to be.

Comparisons evaluated as integers


All comparison operators produce integer results. Although it is unusual to mix comparison operators and arithmetic in the same statement, it is legal. In fact, you can use an int variable as part of a logical statement and to store logical results. Examples
int $sra int $rra int $rrr int $sar if ($rra = (4.7 == 4.7) + 5; = <<1, 2, 3>> >= <<9, 0, 0>>; = 0 || 72.3; = 3 * (1.2 && ! <<0, 0, 0>>); || $rrr) print("true\n"); // // // // // Assigned: Assigned: Assigned: Assigned: True 6 0 1 3

Logical operators only work using integer operands. Although you can compare true values it is dangerous to do so. Consider the following example:
int $xsv = 5; if ($xsv) print("true\n"); // True if (true) print("true\n"); // True if ($xsv == true) print("true\n"); // False

Variable $xsv represents a true value because its value, converted to type int, is not 0. However, there are many int values that are not 0. In fact, the keyword true also represents a true value since its value is 1 (see "Constants" on page 52). However, both of these true values are not equal to one another. One int value is 1 and the other int value is 5. Due to this potential problem, you should not compare true values. Even if both values are true values, it does not mean that the values are equal, as the above example illustrates.

CONDITIONAL
The conditional operator has three operands. The first operand is a test condition that represents true or false. This operand is followed by a question mark (?), then the second and third operands separated by a colon (:). If the test condition is true, the operand after the ? is used. Otherwise the operand after the : is used. Below is the format of the conditional operator.
test condition ? statement1 : statement2;

Example
float $src = rand(5) < 3 ? 15 : 25;

MEL
64

PART 3

MAKING STATEMENTS | 10
Operator precedence In the above example, the test condition is evaluated as an int type. If rand(5) returns a number less than 3, $src is assigned the value 15; otherwise $src is assigned the value 25. Maya evaluates either statement1 or statement2, never both. Example
int $full = 23; int $large = 1 < 2 ? ++$full : --$full;

In this example, both large and full will be assigned 24. Example
float $mog = <<0, 0, 0>> ? 8 : 3.3;

Because Maya interprets the 8 as an integer in the above statement, the float 3.3 is converted to an int before being assigned to $mog. This assigns the value of 3 to $mog.

OPERATOR PRECEDENCE
The following shows the order of operator precedence in MEL. Operators on the same row have equal precedence. If a statement has two or more operators with the same precedence, the left-most operator is evaluated first. Unary and assignment operators are right associative; all others are left associative.
Highest () [] ! ++ - * / % ^

< <= > >= == != && || Lowest ?: = += -= *= /=

Examples
int $chow = 3 + 5 * 2; float $blu = 5 * ++$chow; $blu = 5 && 3 % 2 / 3; $blu -= $chow += ! 5 < 3; // // // // int $chow = (3 + (5 * 2)) float $blu = (5 * (++$chow)) $blu = (5 && ((3 % 2) / 3)) $blu -= ($chow += ((! 5) < 3))

These examples illustrate the default order for operator precedence. To change the order for operator precedence, use grouping. For more information, see Grouping operations.

GROUPING OPERATIONS
Parentheses, which are used for grouping operations, are at the top of the operator precedence hierarchy. As shown in the following examples, parentheses are useful for manually specifying the order of operator evaluation.

SCRIPTING

MEL
65

MAKING STATEMENTS | 10
Grouping operations Examples
int $mao = (3 + 5) * 2; float $fir = (1 + 2) * 5 * ($mao < 20); $mao /= 2 + ((($fir -= 10) == 5) < 0.5);

MEL
66

PART 3

11
GROUPING

FLOW CONTROL

UNDERSTANDING ACTIONS AND FLOW CONTROL


To control the execution order of many statements, use flow control. Flow control lets you conditionally and repeatedly execute sections of MEL script. This lets you create clear and simple MEL scripts that execute with great complexity and power. The most fundamental component of flow control is grouping.

With grouping you can: execute a group of statements in place of a single statement create script modularity define the visibility of local variables Typically, you use grouping to execute a group of statements where only one statement is allowed. To delimit a group of statements, use the curly braces ({}). For example, the if statement allows only one statement to be executed if its condition is true. Any statements after this one statement would be executed unconditionally. To execute them conditionally, you would need to add an if statement for each command. This would be inefficient and tedious. Example
int $mok = 241; if ($mok % 3 == 0) print("Its true!\n"); print("This is always executed\n"); if ($mok % 3 == 0) print("Its really really true!\n");

Grouping the statements allows the use of just one if statement. Example
int $sok = 241; if ($sok % 3 == 0) { print("Its true!\n"); print("Its really really true!\n"); }

MEL
67

FLOW CONTROL | 11
Conditional actions All the statements inside a grouping, even if there is only one, must terminate with a semicolon. No semicolon is necessary after the closing brace of a grouping. Grouping is also necessary to surround the body of a procedure. Example
proc delta() { print("Delta is active.\n"); print("Roger that.\n"); }

Optional use of grouping is seldom used, although it is useful for avoiding name conflicts and to recover memory allocated for local variables inside the grouping. See Variable visibility for additional information.

Variable visibility
Local variables within a grouping are destroyed after the grouping has been executed. This recovers the memory allocated to these local variables at the time the grouping has been executed and also makes these variables invisible outside of the grouping. The local variables inside a grouping exist only in that grouping. Example
int $real = 28; { float $ghost = 73.3; print($real + "\n"); // real exists in grouping print($ghost); // ghost exists in grouping } print($real); // real exists outside of grouping print($ghost); // ERROR: ghost exists only in grouping

Local variables within a procedure are considered local to that procedure. Therefore, a local variable declared inside a procedure will only be visible within that procedure.

CONDITIONAL ACTIONS
Conditional statements let you execute a statement or grouping only if the test condition is true when evaluated as a type int. This test condition must be enclosed in parentheses, and the resulting value must be an int, float, or vector. The test condition value is then converted to an int type to represent either true or false. If the test condition has a value of type int or float, the test condition is true only if the value, converted to type int, is not 0. Examples
if if if if if (0) print("true\n"); (1) print("true\n"); (-17.4) print("true\n"); (0.9) print("true\n"); (-0.7) print("true\n"); // // // // // False True True False False

If the test condition has a value of type vector, the test condition is true only if the magnitude of the vector, converted to type int, is not 0.

MEL
68

PART 3

FLOW CONTROL | 11
Conditional actions Examples
if if if if if (<<0.9, 0.3, 0.3>>) print("true\n"); (<<.8, 0.3, 0.7>>) print("true\n"); (<<0, 0, 0>>) print("true\n"); (<<0, 4, -37>>) print("true\n"); (<<0, 1, 0>>) print("true\n"); // // // // // False True False True True

The test condition can include any variables or operators (even the assignment operator), but the resulting value must be of type int, float, or vector.

if
The if conditional statement has the following format:
if (test condition) statement;

If test condition is true, statement executes. Examples


if (9836 % 27 > 13) print("Wow, thats interesting!\n"); if (3743 % 17 < 8) { print("These are..."); print(" useful results.\n"); }

else
The else statement works only with the if conditional statement. It has the following format:
if (test condition) statement1; else statement2;

If test condition is true, statement1 executes, otherwise statement2 executes. The statement1 and statement2 can be any valid statements. Examples
if (rand(10) < 5) print("That was random.\n"); else print("No it wasnt.\n"); if (rand(2)) print("It takes one to get here\n"); else { print("This is just..."); print(" less than one"); }

SCRIPTING

MEL
69

FLOW CONTROL | 11
Conditional actions

else if
The else if statement works only with the if else conditional statement. It has the following format:
if (test condition1) statement1; else if (test condition2) statement2;

If test condition1 is true, statement1 executes. Otherwise, if test condition2 is true, statement2 executes. If neither test condition is true, neither statement will be executed. The statement1 and statement2 can be any valid statement. Example
float $random = rand(2); if ($random < 1) print("That was random.\n"); else if ($random < 2) print("Sure was.\n"); else print("Thats impossible...\n");

In the above example: If the random variable value is less than 1, only That was random.\n prints. If the random value is between 1, inclusive, and two, exclusive, only Sure was.\n prints. If the value of random is exactly 2, only Thats impossible...\n prints. The rand(2) call would rarely return a value that was exactly 2. Example
float $crow = rand(10); if ($crow < 5) print("The crow has landed.\n"); else if ($crow < 7) { print("The crow is between five..."); print(" and seven.\n"); }

switch
A switch statement executes one of several pieces of statements based on the value of the control value. This control value can be an int, float, string, or vector data type. The body of the switch is enclosed in braces and is comprised of one or more blocks of statements called cases. Cases are labeled by the word case followed by a value of the same type as the control value, then a colon. The control value determines which case statement gets executed. If a case statement value is equal to the control value statement, that case statement is executed. The switch statement has the following general form:
switch (control value) { case value1:

MEL
70

PART 3

FLOW CONTROL | 11
Conditional actions
statement1; break; case value2: statement2; break; case value3: statement3; break; ... default: statement4; break; }

After a case statement, you may have any statement including flow control. To prevent the MEL execution from continuing on to the next case, you can use a break statement. Within a switch, a break statement causes the rest of the switch statement to be ignored. For more information on the break statement see, "break" on page 77. Example: break statement
int $sway = rand(3); switch ($sway) { case 0: print("Case 0\n"); // Executed only if $sway = 0 break; case 1: print("Case 1\n"); // Executed only if $sway = 1 break; case 2: while (rand(10) < 7) // These statements print("I say!\n"); // are executed only print("Case 2\n"); // if $sway = 2 break; }

Tips Although the last case in a switch statement does not need a break statement since the switch is at its end, it is still a good idea to add the break statement. If you add more cases to the switch statement, the break statement is already there. If you want the switch execution to continue through the next case statement, you can omit the break statement. However, this can lead to problems when the code is modified at a later time. Example
int $argo = rand(2); switch ($argo) { case 0: print("Food\n"); // Executed if $argo is 0. case 1: print("Fight\n"); // Executed if $argo is 0 or 1. break; }

SCRIPTING

MEL
71

FLOW CONTROL | 11
Loops You may want more than one case statement to execute the same block of MEL statements. For example, if you wanted both the control values of a and A to execute some statements, you could write something similar to the following example: Example
string $mt = rand(2) < 1 ? "a" : "b"; string $mp = rand(2) < 1 ? "A" : "B"; string $XXz = rand(2) < 1 ? $mt : $mp; switch ($XXz) { case "a": case "A": print("Apple\n"); // Executed if "a" or "A" break; case "b": case "B": print("Banana\n"); // Executed if "b" or "B" break; }

In this example, the variable $mt could be either a or b and variable $mp could be either A or B. Additionally, the variable $XXz could be either variable. This means that $XXz and the control value could be either a, b, A, or B. To specify a block of statements to execute only if none of the case values match the control value, you can use the default label. This label may be located anywhere in the switch statement, but it usually appears after all of the case statements. If there is no default label and none of the case values match the control value, the switch statement does nothing. Example: default label
vector $mgb = <<1, 1, 0>>; switch ($mgb) { case <<0, 1, 1>>: print("Who\n"); // break; case <<1, 0, 1>>: print("What\n"); // break; default: print("Why\n"); // break; // }

Executed if $mgb is <<0, 1, 1>>

Executed if $mgb is <<1, 0, 1>>

Executed if $mgb is not <<0, 1, 1>> or <<1, 0, 1>>

In the above example, the default case is executed and Why\n prints.

LOOPS
Conditional statements execute statements when a certain test condition is true. Loop statements repeatedly execute statements while a certain test condition is true.

MEL
72

PART 3

FLOW CONTROL | 11
Loops Although looping allows you great control and power in writing scripts, it can also be a source of problems. Loops that endlessly repeat execution of statements will do just thatnever end. For example, executing while (1); will loop nothing forever. Maya will never stop executing this line; dont try it unless you are prepared to quit Maya. This section describes the three main loop statements, while, do-while, and for. The loop interruption statements, continue and break, are also described. For information on what determines a true condition, see "Conditional actions" on page 68.

while
A while loop continues to execute some designated statements, as long as a certain condition is true. It has the following format:
while (test condition) statement;

If test condition is true, Maya executes the statement. Maya then evaluates the test condition again. If the test condition is true, it executes the statement again. This process continues until the test condition is false. At that time the loop exits. Example
int $files = 5; while ($files > 2) print("There are " + $files-- + " files left.\n");

The above example produces the following output:


There are 5 files left. There are 4 files left. There are 3 files left.

When the condition is first evaluated in the above example, files has the value of 5 which creates the true condition that 5 is greater than 2. Therefore, the print statement is executed, which also decrements files to a value of 4. At this point, the test condition is evaluated again with a value of 4 for files. The test condition is again true so the print statement is executed, decrementing files to a value of 3. Again the test condition is evaluated to be true, and so the print statement is executed. Finally, with a value of 2 for files, the test condition is false, since 2 is not greater than 2. The while statement exits. To have more than one line of MEL script executed when the test condition is true, use grouping (see "Grouping operations" on page 65). For information on the decrement operator (--), see "Increments and decrements" on page 61. Example
int $t = -10; while ($t < 0) { print("t minus " + (-$t) + " seconds and counting.\n"); $t = $t + 1; } print("Houston, we have lift-off!\n");

SCRIPTING

MEL
73

FLOW CONTROL | 11
Loops

do-while
A do-while loop is very similar to a while loop because both execute some specified statement as long as a certain test condition is true. However, the do-while loop first executes the statement and then checks whether or not to repeat the loop. This ensures that the statement is executed at least once. A do-while loop has the following format.
do statement; while (test condition);

Note that the do-while loop must terminate with a semicolon (;). Example
do print("This is randomization kid.\n"); while (rand(2));

In the above example, rand(2) is a float value between 0 and 2. This number is converted to an int of value 0, 1, or 2 (see "Conditional" on page 64). A value of 1 or 2 will repeat the loop; a value of 0 will exit the loop. Each time the test condition is evaluated, the rand(2) can return a different number. Therefore, the test condition has about a 50 percent chance of being true and about a 50 percent chance of being false. Here is a similar example using grouping:
do { print("Here comes the rain again.\n"); print("Raining on my head like a memory.\n"); } while (rand(2));

for
Often you may want a loop control that has initialization, test, and a change of condition statement. For this you can use the for loop. The for loop has the following format:
for (initializer; test condition; change of condition) statement;

The initializer is executed only once, before the rest of the for loop is executed. The initializer is a statement that is generally used to assign a value to a variable in the test condition. You can use the initializer to execute any statement or you can omit the initializer entirely. However, it cannot be used to declare a variable. The for loop evaluates test condition before executing statement. This part of the for loop is exactly like the while loop. In fact, a for loop is just a while loop with an initializer and change of condition statement. However, if the test condition is missing, the test condition is assumed to always be true, which would create an error in a while loop. While the test condition is true, the statement is executed; as soon as it is evaluated to be false, the loop is exited. The change of condition statement is executed at the end of each iteration of the loop, as if it were added to the end of the loop. Typically, the change of condition statement is used to change some loop-control variable, although you can use it for any statement or omit it entirely.

MEL
74

PART 3

FLOW CONTROL | 11
Loops Examples
int $Index; for ($Index = 0; $Index < 2; $Index++) print("Give me a beat!\n"); for ($Index = 0; $Index < 3;) { print("Can I get some?\n"); $Index = $Index + 1; } for (; $Index--;) print("Give me all your lovin.\n"); for (;;) if (rand(5)) print("Forever yours.\n"); else break;

These examples show some different possibilities when using the for loop. In the last for loop, the if else statement is considered a single statement. For information on the decrement or increment operators, see "Increments and decrements" on page 61. For more information on what determines a true condition, see "Conditional actions" on page 68. Although the initializer cannot be used to declare a variable, it can be used to implicitly declare a variable. Example
for ($xxx = 0; $xxx < 3; $xxx++) print("Hit me three times.\n");

The for loop also allows you to use multiple initializers or multiple incrementors. To do this, separate each initializer and change of condition statement with a comma (,). Examples
int $nx1, $nx2; for ($nx1 = 0, $nx2 = 10; $nx1 < $nx2; $nx1++, $nx2--) print("nx1 = " + $nx1 + ", nx2 = " + $nx2 + "\n"); float $cg = 25.3; for (; $cg < 93.8; $nx1--, $nx2 = rand(11), $cg *= 1.7) { print("nx1 = " + $nx1 + ", nx2 = " + $nx2 + "\n"); print( "CG levels currently at " + $cg + "\n\n"); }

For information on the shortcut operator, *=, see "Shortcuts" on page 60.

for-in
The for-in loop is a derivative of the for loop. It is specialized for working with arrays. Often you might want to iterate through all the elements of an array. While a for loop requires an index variable, initializer, test condition, and incrementor, the for-in loop requires only an element variable. The for-in loop has the following format:
for (element in array) statement;

SCRIPTING

MEL
75

FLOW CONTROL | 11
Loops Example: for-in loop
string $car; string $cars[3] = {"n NSX", " Porsche", "n Acura"}; for ($car in $cars) print("I have a" + $car + ".\n");

The result is:


I have an NSX. I have a Porsche. I have an Acura.

Example: for loop


int $carIndex; string $cars[3] = {"n NSX", " Porsche", "n Acura"}; for ($carIndex = 0; $carIndex < size($cars); $carIndex++) print("I have a" + $cars[$carIndex] + ".\n");

Both of the above for loops are equivalent but the for-in loop requires less typing. Example
vector $coordinates[2] = {<<1, 2, 3>>, <<4, 3, 7>>}; for ($coordinate in $coordinates) { print("Coordinate: " + $coordinate + ".\n"); print("You sank my battleship!\n"); }

continue
The continue statement works inside all loops. It forces the next iteration of the loop to occur, skipping any remaining statements in the loop. Example
float $fox = 5; for ($fox = 0; $fox < 5; $fox++) { print("$fox equals: " + $fox + "\n"); if ($fox > 2) continue; print(" Got here\n"); }

The output is:


$fox equals: Got here $fox equals: Got here $fox equals: Got here $fox equals: $fox equals: 0 1 2 3 4

MEL
76

PART 3

FLOW CONTROL | 11
Loops Without the if statement, the loop would also output Got here after the lines $fox equals: 3 and $fox equals: 4. Maya ignores the continue statement until $fox increases to a value greater than 2. When $fox becomes 3 or greater, the continue statement executes and skips the remaining statement in the loop, the statement that prints got here.

break
The break statement exits a loop immediately. You can use a break statement inside all loops. Example
float $free = 0; while ($free < 10) { print("$free equals: if ($free++ == 3) break; } print("Im free!");

" + $free + "\n");

The output is:


$free equals: $free equals: $free equals: $free equals: Im free! 0 1 2 3

Without the if statement, the loop would execute 10 times and display the numbers 0 through 9. The break statement terminates the loop after $free is equal to 3, so the print statement in the loop is only executed four times.

SCRIPTING

MEL
77

FLOW CONTROL | 11
Loops

MEL
78

PART 3

12

ABSTRACTING ACTIONS
Abstracting actions is bringing together actions as a procedure or script.

PROCEDURES
A MEL procedure is a group of MEL commands that can be executed by a single command. Procedures can be local or global. Local procedures are visible only within their file. Global procedures are visible outside their file. Typically, you create procedures in a script with a text editor. You can also enter procedures in the Script Editor. The form of a MEL procedure is:
global proc return_type procedure_name ( arguments ) { MEL_statements }

Elements in italics are optional. Each argument consists of an argument type and name. You can use multiple arguments, separated by commas. In the following example, the global MEL procedure, helloValue, takes an integer and a string and returns a string.
global proc string helloValue( int $value, string $person ) { string $greeting; $greeting = Hello + $person + , number + $value; return $greeting; }

Declaring procedures
Before you execute a procedure, you must declare it. Declaring a procedure loads it into Mayas memory so it can be executed. To declare a procedure in a file, use the source command in the Script Editor or the Command Line to source the script that contains the procedure. You can also enter a procedure directly in the Script Editor. This also executes the script. After you source a script, you must source it again if you modify it. For more information on sourcing a script file, see "Sourcing a script" on page 34.

MEL
79

ABSTRACTING ACTIONS | 12
Scripts

Declaring functions
You cannot use a default argument when you declare a function. A function is a procedure with a return value. When you execute a function, you must provide all arguments. For example, you cannot declare a function as follows:
proc int splat (int $value, bool = true)

The assignment (=) in the statement creates a default assignment in C. It is not allowed in MEL. You also cannot overload functions. If you use the same name for procedures with different argument lists or return types, the last procedure will overwrite the previous one. For example, if you had the following two procedures:
rad (int $x); rad (string $foo);

the second procedure would overwrite the first.

Executing procedures
Using a defined MEL procedure is the same as using any other MEL command or function. To execute the above MEL procedure helloValue, enter the name of the MEL procedure in a script, the Script Editor, or the Command Line.
helloValue( 1, "Jake" ); // Result: Hello Jake, number 1 //

The helloValue procedure requires an integer and a string argument in order to be successfully called. Another way to execute a procedure does not use parentheses or commas. For example, to execute the helloValue procedure this way, enter the following:
helloValue 7 "Torq"; // Result: Hello Torq, number 7 //

SCRIPTS
A MEL script is a file that contains MEL commands, MEL procedures, or both. Typically, you use a MEL script to execute a sequence of commands. For example, you might write a script to create a wall-shaped object and then apply a brick texture to it. You can write a MEL script using a text editor then save the MEL script in a file on disk. MEL scripts use the file extension .mel. You can use scripts for different scenes and in different work sessions. When you execute a MEL script, it does not become part of the scene; you must execute the script each time you want to repeat the action. See "Executing a script" on page 35 for details on executing a script.

MEL
80

PART 3

13

CREATING INTERFACES
This chapter describes how to build user interface elements such as windows using the Extended Layer Framework (ELF) interface commands. These commands are an extension to the regular MEL commands. Please note that this chapter is an introduction and overview of the ELF commands. For details and a complete description of each command, see the online MEL Command Reference documentation.

UNDERSTANDING INTERFACE CREATION


There are a some basic concepts that assist in understanding how to build windows using the ELF commands. This section describes the important elements and terminology: "ELF commands" on page 81 "UI elements" on page 82 "Parents and children" on page 88 "Default parents" on page 88 "Naming" on page 90 "UI command templates" on page 91 "Deleting UI elements" on page 92

ELF commands
Most ELF commands create and modify UI elements. The commands that create UI elements are named after the type of element that they create. They accept optional flags with arguments and also accept as a final argument the name that you want to assign to the element being created (See the Naming section). For example:
window -visible true -title "Test Window" TestWindow1;

Note that ELF UI command flags are optional, however all flags default to a particular value. In the example above you will notice that the window does not contain a menu bar because the default value of the -mb/menuBar flag is false. ELF UI commands also have other modes where they are not creating new elements but changing or querying existing elements. If the flags -e/edit, -q/query or ex/exists are used then the named element will be edited, queried or tested for existence. The following example will return the title of the window created above.
window -query -title TestWindow1;

MEL
81

CREATING INTERFACES | 13

Note that for querying no arguments are required for the flag. Only one flag may be queried at a time as only one result can be returned at a time. Multiple parameters can be specified with the edit flag, and the exists flag expects only the name of the element being tested.
window -edit -title "New Title" -maximizeButton false TestWindow1; window -exists TestWindow1;

In almost all cases, to edit or query a UI element you need to know the name and exact type of element that you are working with. There are a couple of special commands that relax this restriction. The control command can work on any type of control and the layout command can work on any type of layout.

UI elements
The following sections introduce the basic elements that appear in ELF user interfaces. These elements are described in detail in the MEL command lists.

Windows
Windows are usually the first element created when building an interface. They contain all the other UI elements. ELF commands allow control over window size, position, and border elements such as minimize, maximize buttons and resize handles. Windows can optionally contain a menu bar. Below is illustrated a typical Motif window.

By default, when a window is created Maya will remember its name, size and position. The next time that window is shown its size and position are restored, overriding any arguments you may have set with the window command. You may find it convenient while creating your interface to turn off this behavior via the UI Preferences window or by using the windowPref -remove command.

Controls
Controls are the familiar elements in windows such as buttons, check boxes, icons, fields and sliders. These are the elements that contain the functionality of the window. When the user presses a button or drags a slider they expect something to happen. Commands and scripts can be attached to the controls to be executed on user actions. Attaching will be described in a later section. For a list of the controls that are available, see the UI: Controls section of the Command List by Function.

MEL
82

PART 3

CREATING INTERFACES | 13

Layouts
Layouts are UI elements that contain and arrange other UI elements. They are the principle means of controlling formatting in ELF windows. There are a number of different specialized layouts that arrange their contents in particular ways. For example a column layout arranges its contents vertically one after another in a single column, like a list, whereas a row layout arranges its contents horizontally beside each other. There are other layouts for other arrangement schemes. Layouts can contain other layouts to achieve a wide variety of appearances. All commands that create layouts end in Layout e.g., gridLayout. For a list of the layouts that are available, see the UI: Layouts section of the Command List by Function.

The frameLayout, tabLayout, and menuBarLayout commands have extra capabilities not necessarily related to positioning their children. Frame layout A frame layout has an expand/collapse option in which it has a button beside its title to toggle its state. When in the collapsed state the contents of the frame layout are hidden and the layout collapses to take up very little space. The frameLayout callbacks for expanding or collapsing layout are only called if the layout is collapsed or uncollapsed through the visible interface (for example, the small arrow icon the user can click on.) Using code such as the following will not invoke the callback:
frameLayout -e -collapse true $theFrame;

Having callbacks work in this way is the only way we can allow things to get set up correctly when the window is first being created without getting into infinite loops. If a callback is needed and you know it is safe then call it directly at the same time you do the collapse or expand. Tab layout A tab layout contains a number of other layouts, of which only one is displayed at a time. Each of the child layouts have a file folder like tab that can be selected to make that layout the visible one.

SCRIPTING

MEL
83

CREATING INTERFACES | 13

Menu bar layout A menu bar layout allows you to insert a menu bar anywhere in your window. Form layout One of the more powerful layouts is the formLayout. This layout supports absolute and relative positioning of child controls. For example, you may specify that a controls position remains fixed while its dimensions are relative to the size of the window. This concept is best illustrated with the following example.
window -widthHeight 300 200 TestWindow2; string $form = formLayout -numberOfDivisions 100; string $b1 = button -label "A"; string $b2 = button -label "B"; string $b3 = button -label "C"; string $b4 = button -label "D"; string $b5 = button -label "E"; formLayout -edit -attachForm -attachForm -attachControl -attachPosition -attachNone -attachForm -attachForm -attachForm -attachOppositeControl -attachPosition -attachNone -attachForm -attachControl -attachOppositeControl -attachNone -attachOppositeControl -attachControl -attachOppositeControl -attachNone -attachOppositeControl $form; showWindow TestWindow2;

$b1 $b1 $b1 $b1 $b2 $b2 $b2 $b2 $b3 $b3 $b3 $b3 $b4 $b4 $b4 $b4 $b5 $b5 $b5 $b5

"top" "left" "bottom" "right"

5 5 5 $b2 0 75

"top" "left" 5 "bottom" 5 "right" 5 "top" 0 $b1 "left" 5 75 "bottom" "right" 5 "top" 0 $b3 "left" 0 $b3 "bottom" "right" 0 $b3 "top" 0 $b4 "left" 0 $b4 "bottom" "right" 0 $b4

The resulting window has button A fixed to the top left corner of the window, while its bottom edge is attached to button B and its right edge is attached such that its width is 75% of the windows width. With these attachments button A will grow or shrink as appropriate when the window is resized. Also note the attachments on buttons D and E will align their left and right edges to the button above. Most of the formLayout attachment flags operate as you would expect them to. AttachOppositeForm and attachOppositeControl require some extra explanation. As child controls are added to the form they do not have a position but do have an order and thus an implied position relative to one another. In terms of the

MEL
84

PART 3

CREATING INTERFACES | 13

attachControl flag the natural place for the top of the second child to connect to is the bottom of the first child. The natural place for the left edge of the second child to connect to is the right edge of the first one. Thus the second child is, in a sense, right of and below the first, the third is right of and below the second and so on. Consider now that we want to make the second child attach beside the first one and that it must be a relative attachment so that child 2 will stay beside child 1 when the forms size changes. The regular attachControl lets us connect the left of child 2 to the right edge of child 1, attachControl child2 left 0 child1; says to attach the left edge of child 2 to the edge of child 1 that is nearest in the left-right direction with a spacing offset of 0 pixels. Remembering that the implicit order has child 2 positioned immediately right of child 1 the nearest edge is then child 1s right edge. But attachControl cant make the top of child 2 line up with the top of child 1 because of the implied ordering that attachControl follows. That is when attachOppositeControl is used.
attachOppositeControl child2 "top" 0 child1;

says to attach the top edge of child 2 to the edge of child 1 farthest from child2, its top edge, with a spacing offset of 0 pixels. The form knows to place two objects with the same top edge position side by side.
window string string string string TestWindow3; $form = formLayout; $b1 = button -label "AAAAAAAAA"; $b2 = button -label "BBBBB"; $b3 = button -label "CCCC";

formLayout -edit -attachForm -attachForm

$b1 "top" $b1 "left"

5 5

-attachControl $b2 "top" 0 $b1 -attachControl $b2 "left" 5 $b1 -attachNone $b2 "right" -attachNone $b2 "bottom" -attachControl $b3 "top" 0 $b2 -attachControl $b3 "left" 0 $b2 -attachNone $b3 "right" -attachNone $b3 "bottom" $form; showWindow TestWindow3;

Next we see the action of the attachOppositeControl flag on the position of the second button. Note that as long as the first button is attached to the top of the form this use of attachOppositeControl is the same as doing an attachForm $b2 top. If button 1 was attached relative to a control that could move the use of attachOppositeControl here would be essential here.
window string string string string TestWindow4; $form = formLayout; $b1 = button -label "AAAAAAAAA"; $b2 = button -label "BBBBB"; $b3 = button -label "CCCC";

formLayout -edit

SCRIPTING

MEL
85

CREATING INTERFACES | 13

-attachForm -attachForm -attachOppositeControl -attachControl -attachNone -attachNone

$b1 "top" $b1 "left" $b2 $b2 $b2 $b2

5 5

"top" 0 $b1 "left" 5 $b1 "right" "bottom"

-attachControl $b3 "top" 0 $b2 -attachControl $b3 "left" 5 $b2 -attachNone $b3 "right" -attachNone $b3 "bottom" $form; showWindow TestWindow4;

Now we use attachOppositeControl in the other direction to make the third button fit directly under the second.
window string string string string TestWindow5; $form = formLayout; $b1 = button -label "AAAAAAAAA"; $b2 = button -label "BBBBB"; $b3 = button -label "CCCC";

formLayout -edit -attachForm -attachForm -attachOppositeControl -attachControl -attachNone -attachNone -attachControl -attachOppositeControl -attachNone -attachNone $form; showWindow TestWindow5;

$b1 "top" $b1 "left" $b2 $b2 $b2 $b2 $b3 $b3 $b3 $b3

5 5

"top" 0 $b1 "left" 5 $b1 "right" "bottom" "top" 0 $b2 "left" 0 $b2 "right" "bottom"

And to have the third button line up below the first and extend over as far as the left edge of the second we do the following:
window string string string string TestWindow6; $form = formLayout; $b1 = button -label "AAAAAAAAA"; $b2 = button -label "BBBBB"; $b3 = button -label "CCCC";

formLayout -edit -attachForm -attachForm -attachOppositeControl -attachControl -attachNone -attachNone -attachControl -attachForm

$b1 "top" $b1 "left" $b2 $b2 $b2 $b2

5 5

"top" 0 $b1 "left" 5 $b1 "right" "bottom" 0 $b2 5

$b3 "top" $b3 "left"

MEL
86

PART 3

CREATING INTERFACES | 13

-attachControl -attachNone $form; showWindow TestWindow6;

$b3 "right" 0 $b2 $b3 "bottom"

Note that now that the attachForm $b3 left 5" places button 3 to the left of button 2 the nearest side for the -attachControl $b3 right 0 $b2 is now button 2s left edge. And finally, we want the third button to run from the left edge of button 1 to the right edge of button 2.
window string string string string TestWindow7; $form = formLayout; $b1 = button -label "AAAAAAAAA"; $b2 = button -label "BBBBB"; $b3 = button -label "CCCC";

formLayout -edit -attachForm -attachForm -attachOppositeControl -attachControl -attachNone -attachNone -attachControl -attachOppositeControl -attachOppositeControl -attachNone $form; showWindow TestWindow7;

$b1 "top" $b1 "left" $b2 $b2 $b2 $b2 $b3 $b3 $b3 $b3

5 5

"top" 0 $b1 "left" 5 $b1 "right" "bottom" "top" 0 $b2 "left" 0 $b1 "right" 0 $b2 "bottom"

Groups
Some controls often appear together in applications. For example a float slider often has a field beside it to indicate its value, or an editable field often has non-editable text beside it indicating the nature of the field. Groups in ELF are collections of controls that are bundled together within one command for convenience. Using groups is more efficient and they also take advantage of ELFs higher level formatting functions that will be described later. Anything that a group command creates can be created using the individual commands of its component elements. All commands that create groups end in Grp e.g., floatFieldGrp.

Menus
Menus appear in a menu bar at the top of a window or in a menu bar layout. They may also be attached to any control or layout by using the popupMenu command. Menus contain menu items and can be hierarchical i.e., a menu item can contain another sub-menu of its own. Menus also have commands or scripts attached to

SCRIPTING

MEL
87

CREATING INTERFACES | 13

them so that when selected some action will occur. Note that while an option menu control (see, the documentation for the optionMenu command) may look similar to menus it is a control and behaves differently. Furthermore, neither the menu or menuItem commands are required to construct the contents of an option menu. For a list of the menus that are available, see the UI: Menus section of the Command List by Function.

Collections
Collections are a grouping of toggle controls that are linked together so that only one may be selected at a time. There are currently four controls that support this behavior: radio buttons, icon/text buttons, tool buttons and radio button menu items. The corresponding collection commands are: radioCollection, iconTextRadioCollection, toolCollection and radioMenuItemCollection, respectively. The collections themselves are only a specification of a grouping and have no visual appearance.

Parents and children


You will see the terms parent and child used in relation to UI elements and ELF commands. In this context a parent is simply a UI element that contains other UI elements, and a child is an element that is contained within a parent. A child of one parent may also be the parent of other children. Windows are the top-most parent of the hierarchy. Other elements in the hierarchy can be layouts, controls, menus, menu items etc. The hierarchy can be arbitrarily deep as layouts can contain other layouts and menu items can contain sub-menus.

Default parents
To simplify creation of windows and reduce clutter in scripts ELF commands understand the idea of default parents. This means that it is not necessary to explicitly specify the parent for each element created. When a window is created it will become the default parent for any subsequent menus or controls. New UI elements will appear inside that window until the default parent is explicitly changed (with the setParent command) or another window is created. There are different default parents for layouts and menus. A window is the initial default parent for controls and if the window is created with a menu bar then it is also the initial default parent for menus. When a layout is created it will become the new default parent for layouts and controls. When a menu bar layout is created it will become the new default parent for menus. When a menu is created it will become the default parent for menu items. The default parent is changed either implicitly by creating a new parent or explicitly using the setParent command. To change the default parent for menus the -m/ menu flag is used. Setting a parent to either a window or a menu bar layout will set the default parent for both menus and layouts. The following is a small code example that illustrates the use of default parents for layouts. Script 1. Example of default parent layout
window ExampleWindow1; columnLayout; button -label "Button 1"; button -label "Button 2"; rowColumnLayout -numberOfColumns 2;

MEL
88

PART 3

CREATING INTERFACES | 13

text -label "Name:"; textField; text -label "City:"; textField; setParent ..; checkBox -label "Lights "; checkBox -label "Camera "; checkBox -label "Action "; showWindow ExampleWindow1;

The text elements and the textField elements are children of the row column layout. They are arranged by the row column layout to be in two columns. If the setParent .." command wasnt used then the default parent would continue to be the row column layout and the check boxes would be laid out in two columns also. To demonstrate, the following example is identical to the previous except that the setParent command is commented out. Script 2. Effect of setParent command on default parent layout
window ExampleWindow2; columnLayout; button -label "Button 1"; button -label "Button 2"; rowColumnLayout -numberOfColumns 2; text -label "Name:"; textField; text -label "City:"; textField; //setParent ..; checkBox -label "Lights "; checkBox -label "Camera "; checkBox -label "Action "; showWindow ExampleWindow2;

Note that the setParent command accepts -up and -top as flags to move up the hierarchy one level or to the top of the hierarchy respectively similar You can also explicitly specify a new default parent e.g., setParent <windowOrLayoutName>;. The setParent command can also be queried for the current parent e.g., setParent -query. The following is a brief example that illustrates the use of default parents for menus. Script 3. Sample default parent menu
window -menuBar true ExampleWindow3; menu -label "File" TestFileMenu; menuItem -label "Open" menuItem1; menuItem -label "Close" menuItem2; menuItem -label "Quit" menuItem3; menu -label "Edit" TestEditMenu; menuItem -label "Cut" menuItem1; menuItem -label "Copy" menuItem2; menuItem -label "Paste" menuItem3; menu -label "Options" TestOptionsMenu; menuItem -label "Color" -subMenu true menuItem1; menuItem -label "Red"; menuItem -label "Green";

SCRIPTING

MEL
89

CREATING INTERFACES | 13

menuItem -label "Blue"; setParent -menu ..; menuItem -label "Size" -subMenu true menuItem2; menuItem -label "Small"; menuItem -label "Medium"; menuItem -label "Large"; setParent -menu ..; showWindow ExampleWindow3;

All commands that create UI elements also accept the -p/parent parentName flag for explicit specification of that elements parent. This flag will always take precedence over the default parent. Collections are treated differently. They use the current layout as a default parent and they also accept the -p/parent flag to be explicitly parented. However, collections also have the ability to span windows and have a -g/global flag to select this behavior. When the -g/global flag is used the collection will have no parent. Collections are parented only to facilitate their deletion. When the parent is deleted the collection will also be deleted. Global collections must be explicitly deleted.

Naming
Every UI element created with an ELF command has a name. The name is necessary so that the element can be referenced after it has been created. For example the name of a control is required to query its current value or state. When using an ELF command to create a control the name is the last parameter in the command. If a name is not supplied then a unique name for the control is generated. All ELF elements, with the exception of windows, have parents that they exist within. To avoid name conflicts with existing UI elements names need only be unique within the scope of the parent. For example in the script to create menus (shown above) each menu has a menu item named menuItem1. To distinguish between elements with the same name the full hierarchical path name of the element is used. For these menu items their full names would be ExampleWindow3|TestFileMenu|menuItem1, ExampleWindow3|TestEditMenu|menuItem1 and ExampleWindow3|TestOptionsMenu|menuItem1. With the window from Script 3 still visible, execute the following commands one at a time to query the respective labels.
menuItem -query -label ExampleWindow3|TestFileMenu|menuItem1; menuItem -query -label ExampleWindow3|TestEditMenu|menuItem1; menuItem -query -label ExampleWindow3|TestOptionsMenu|menuItem1;

ELF commands that create UI elements all return the full name of that element. Using the full name of an element will guarantee that you are referencing the right element. If the short name for an element is used e.g., menuItem1 there is the possibility that you will not be referencing the intended element if multiple elements with the same name exist. When using the short name ELF will first look below the current default parent for a match. If multiple matches are found then the first one is returned.

MEL
90

PART 3

CREATING INTERFACES | 13

UI command templates
Command templates are a means of specifying default parameters for ELF commands. They are intended to support a consistent appearance in an applications user interface. By specifying default arguments for text alignments, border styles, indentations, etc. an application will have a more coherent appearance. The look of the application can be modified in one place by modifying the default arguments in the command templates. A single template can hold the defaults for any number of ELF commands. Multiple templates can exist holding different sets of default parameters. During execution the default parameters are transparently added to the argument list for the commands that are part of the current template. Any parameters that are explicitly specified in the argument list will override the default parameters in the template. The defaults are only parsed once when the template is created, and thereafter are kept in the parsed state for later use. To create a new empty command template the uiTemplate command is used. Each command can add its defaults to a template using the -dt/defineTemplate flag along with the specific template that it is specifying and the parameters that it wants to have as defaults. A template is made current with the setUITemplate command. Each template is named and they can be pushed and popped to change the current template for a certain section of script. Typically a script writer will push their desired command template at the beginning of a procedure and pop it at the end of the procedure to restore whatever was the previous template. If no templates are desired then it is prudent to set the current template to NONE (the keyword for indicating no current templates). Whenever a new window is created the command template stack is cleared so pushing templates must be done after window creation to have an effect. Commands can also utilize any existing template without changing the current one by using the -ut/useTemplate flag. Script 4. Command templates
// Create a new template object. // if (!uiTemplate -exists TestTemplate) { uiTemplate TestTemplate; } // Add the command default parameters to the template. // frameLayout -defineTemplate TestTemplate -borderVisible true -labelVisible true -labelAlign "center" -marginWidth 5 -marginHeight 5; button -defineTemplate TestTemplate -width 150 -label "Default Text"; // Now make a window. // window -title "Test Window" ExampleWindow4; // Make our template current // setUITemplate -pushTemplate TestTemplate; frameLayout -label "Buttons" TestFrameLayout; columnLayout TestColumnLayout;

SCRIPTING

MEL
91

CREATING INTERFACES | 13
Attaching commands to UI elements
button; button -label "Not Default Text"; button; Restore previous, if any template to clean up.

// // setUITemplate -popTemplate; showWindow ExampleWindow4;

This window shows the results of the script. Notice how the default parameters defined for the template were added to the subsequent commands. For example we added the label text Default Text as a default parameter for the button command, the first and third buttons had that parameter applied as a default without explicitly specifying it. However the second button overloaded the default argument by specifying its own argument for the label text flag, Not Default Text. The default parameters for a command can be changed at any time by simply reexecuting the command with the -dt/defineTemplate flag for the specified template. Try changing the button commands default label string in the above template and then re-execute the window creation part of the above example.
button -defineTemplate TestTemplate -label "New Default Text";

To prevent accidental use of a template that is still active, the window command clears the current template when a window is created. Use the setUITemplate command after the window command or it will have no effect.

Deleting UI elements
UI Elements are deleted using the deleteUI command or when their patent is deleted. For example, executing the command after running Script 4 above will delete the column layout TestColumnLayout and its button children.
deleteUI ExampleWindow4|TestFrameLayout|TestColumnLayout;

To avoid a build up of user created UI elements the default behavior for windows is that they and their contents are deleted when they are closed. Therefore closing a window with the Motif window menu or the -vis/visible false flag will delete the window and its contents. A window can be made persistent when it is not visible by using the -ret/retain flag on creation.

ATTACHING COMMANDS TO UI ELEMENTS


After creating a window containing all the elements that your require you will want it to do something. Each control can execute MEL commands or procedures triggered by user actions. The types of actions that are supported for each control depend upon the nature of that control. For example buttons only support the

MEL
92

PART 3

CREATING INTERFACES | 13
Attaching commands to UI elements execution of a command when they are pressed, whereas sliders support commands when they are dragged and also when they change value. See the command documentation for the list of callbacks supported by each control. A simple example is to attach a command to a button. The following command will change the buttons label text when the button is pressed. Script 5. Simple Functionality
window -width 200 -title "Test Window" ExampleWindow5; columnLayout; // Create the button. // string $button = button -label "Initial Label"; // Add the command. // string $buttonCmd; $buttonCmd = ("button -edit -label \"Final Label\" " + $button); button -edit -command $buttonCmd $button; showWindow ExampleWindow5;

In this example a single command is attached to the button. It is equally easy to attach procedures with arguments. The following example slightly modifies the above example. Script 6. Simple Functionality in a Procedure
window -title "Test Window" -widthHeight 200 100 ExampleWindow6; columnLayout; // Create the button. // string $button = button -label "Initial Label"; // Add the command. // button -edit -command ("changeButtonLabel " + $button) $button; showWindow ExampleWindow6; proc changeButtonLabel (string $whichButton) { string $labelA; string $labelB; string $currentLabel; $currentLabel = button -query -label $whichButton; $labelA = "New Label A"; $labelB = "New Label B"; if ($currentLabel != $labelA) { button -edit -label $labelA $whichButton; } else { button -edit -label $labelB $whichButton; }

SCRIPTING

MEL
93

CREATING INTERFACES | 13
A simple window
}

Often the value of the control is needed as a parameter in the command that it issues. To avoid querying the control each time its state changes, its value can be symbolically embedded in the command as the string #1. When the control changes value then the #1 will be substituted with the actual value of the control at the time the command is issued. Groups with multiple values use #2, #3, etc. for the values of their different components. For example, a float field group with three fields can represent the values of each of those fields in its commands with #1, #2, #3 respectively. Often you will want to have a control show the value of a nodes attribute and update when that attribute changes. The easiest way to do this is to use the attr versions of the controls. i.e. attrFieldGrp instead of floatFieldGrp. If an attr command doesnt exist then use the connectControl command.

A SIMPLE WINDOW
The following is a sample window to illustrate some of the concepts mentioned. Script 7. A Simple Window
// Create the window. // window -title "Test Window" ExampleWindow7; columnLayout ColumnLayout; frameLayout -labelVisible false -marginWidth 5 -marginHeight 5; columnLayout; text -label "Overall Intensity"; rowLayout -numberOfColumns 3; string $radioButton1, $radioButton2, $radioButton3; radioCollection; $radioButton1 = radioButton -label "Low"; $radioButton2 = radioButton -label "Medium"; $radioButton3 = radioButton -label "High"; setParent ..; text -label "Light Switches"; rowColumnLayout -numberOfColumns 2 -columnWidth 1 130 -columnWidth 2 130; string $checkBox1, $checkBox2, $checkBox3, $checkBox4; $checkBox1 = checkBox -label "Front Spot"; $checkBox2 = checkBox -label "Center Spot"; $checkBox3 = checkBox -label "Near Flood"; $checkBox4 = checkBox -label "Sunlight"; setParent ExampleWindow7|ColumnLayout; textField -text "Ready" -editable false -width 278 StatusLine; // Set initial state. // radioButton -edit -select $radioButton1; checkBox -edit -value on $checkBox1;

MEL
94

PART 3

CREATING INTERFACES | 13
Modal dialogs
checkBox -edit -value off $checkBox2; checkBox -edit -value off $checkBox3; checkBox -edit -value on $checkBox4; // Add functionality. // radioButton -edit -onCommand "showStatus \"Low Intensity\"" $radioButton1; radioButton -edit -onCommand "showStatus \"Med Intensity\"" $radioButton2; radioButton -edit -onCommand "showStatus \"High Intensity\"" $radioButton3; checkBox -edit -changeCommand "showStatus \"Front Spot: #1\"" $checkBox1; checkBox -edit -changeCommand "showStatus \"Center Spot: #1\"" $checkBox2; checkBox -edit -onCommand "showStatus \"Near Flood On\"" -offCommand "showStatus \"Near Flood Off\"" $checkBox3; checkBox -edit -onCommand "showStatus \"Sunlight On\"" -offCommand "showStatus \"Sunlight Off\"" $checkBox4; showWindow ExampleWindow7; // Procedure to update the status line. // global proc showStatus (string $newStatus) { textField -edit -text $newStatus ExampleWindow7|ColumnLayout|StatusLine; }

MODAL DIALOGS
ELF provides command support for two different pre-packaged modal dialogs. Both dialogs allow user configurability of the message text, number of buttons, and button label text. The enter and escape keys are also supported. A confirm dialog provides a message and user definable buttons through the confirmDialog command. When the dialog is dismissed the command returns which button was selected. For example the following command will produce the dialog shown below.
confirmDialog -message "Are you sure?" -button "Yes" -button "No" -defaultButton "Yes" -cancelButton "No" -dismissString "No";

SCRIPTING

MEL
95

CREATING INTERFACES | 13
Using system events and scriptJobs The -defaultButton flag indicates which button will be selected if the enter key is pressed, and the -cancelButton flag indicates which button will be selected if the escape key is pressed. A prompt dialog works similarly to a confirm dialog except that it also provides an editable scrolling field through which the end user can reply to the prompted question. For example the following command will produce the dialog shown below.
promptDialog -message "Enter name:" -button "Ok" -button "Cancel" -defaultButton "Ok" -cancelButton "Cancel" -dismissString "Cancel";

After the dialog has been dismissed the you can query the promptDialog command for the text that the user entered e.g., promptDialog -query; This will return any text typed into the scroll field by the user.

USING SYSTEM EVENTS AND SCRIPTJOBS


It is possible to create scripts in MEL which will run whenever a particular system event occurs. This is done using the scriptJob command. Maya defines a number of system events that you can attach scripts to. These events are triggered by the normal use of Maya. There are events that tell you when the selection has changed, when a new file has been opened, and when a new tool is picked. You can get a complete listing of all the events using the scriptJob command with the -listEvents flag: scriptJob -listEvents; The names of these events is generally selfexplanatory; detailed descriptions can be found in the scriptJob documentation. There is another kind of system event called a condition. A condition is like an event, except that is also has a value of either true or false. For example, there are conditions that tell you when something is selected, or when an animation is playing back. You can get a complete list of all conditions using the scriptJob command with the -listConditions flag:
scriptJob -listConditions;

A condition triggers its attached scripts whenever its state changes from true to false, or from false to true. You can test its state at any time using the isTrue command. Finally, there is an event generated when the value of an attribute of an object changes. When you attach a script to an event or a condition, it doesnt run right away. When the event or condition is triggered, the script is added to a queue and is run the next time the system is idle. No matter how many times the event or condition is triggered during a busy time, the script will only run once the next time the system is idle. Important Note: scriptJobs only work when you are running Maya with its graphic user interface.

MEL
96

PART 3

CREATING INTERFACES | 13
Using system events and scriptJobs They do not work in batch mode or prompt mode. They are meant to be used to customize your user interface. Dont try to use them to make things happen during the running of an animation, because they will not execute during playback or batch rendering. Use expressions instead.

Examples
Lets say for example that you want to write a script which will select a particular object whenever nothing else is selected. Here is a script to select the object:
select -r myObject;

You want this to run whenever nothing is selected. There is a condition called SomethingSelected which is true only when something is selected. When this condition becomes false, you want to run your script. Here is the command to do this:
scriptJob -conditionFalse "SomethingSelected" "select -r myObject";

For another example, lets say instead that you want your object to always be selected. You can have a scriptJob that runs every time the selection changes and insures that your object is there:
scriptJob -event "SelectionChanged" "select -add myObject";

In this example, you want to warn yourself if an object in your scene goes up too far. You can have a script that will check the translateY value of the object whenever it changes:
global proc checkY(){ float $y = getAttr myObject.ty; if ( $y > 10.0 ){ window; columnLayout; text -l "Object is too far up!"; showWindow; } } scriptJob -attributeChange "myObject.ty" "checkY";

Deleting jobs
When you use the scriptJob command to attach a script to an event or condition, the command returns a unique job number. You can use this number to delete (kill) the jobs you have created. Lets say the example above returned the number 17. To stop this script from running any more, you can use the scriptJob command with the -kill flag, like this:
scriptJob -kill 17;

To get a complete listing of all the scriptJobs running in the system, use the -listJobs flag:
scriptJob -listJobs;

This returns a list of job numbers, followed by all the flags and arguments used by the scriptJob command to create the job in the first place. There are a number of ways you can cause jobs to kill (delete) themselves automatically. If you create the job with the -runOnce flag set to true, the job will only run one time, and then delete itself. SCRIPTING

MEL
97

CREATING INTERFACES | 13
Using system events and scriptJobs You can use the -parent flag to attach a job to a particular element of the UI, so that when the UI element is deleted, the job is deleted with it. This next example creates a window. A scriptJob is used to update the text in the window, which says whether or not something is selected. When the window is deleted, the job is killed automatically:
global proc updateSelWind(){ if ( isTrue SomethingSelected ){ text -edit -label "Something is selected." selText; } else { text -edit -label "Nothing is selected." selText; } } string $windowName = window; columnLayout; text selText; updateSelWind; showWindow $windowName; scriptJob -parent $windowName // attach the job to the window -conditionChange "SomethingSelected" "updateSelWind";

Seeing your jobs run


Normally, running jobs are not displayed in the Script Editor window. You can get them to display, however, by turning on the Echo All Commands options in the Edit menu of the Script Editor.

See also
For more detailed information about using events and conditions, see the documentation for these commands: scriptJob, isTrue, condition, and dimWhen.

MEL
98

PART 3

14

STYLE
Having a good scripting style is as important as creating a script that works.

UNDERSTANDING STYLE
Following good style tips in your scripts can improve the look of the script and reduce its visual complexity. If a script is clearly written, it will be easy for you and others to understand and perhaps modify. Although a script with poor style might work when you first create it, later on when you (or someone else) has to figure out how it works, you will suffer much needless grief. Also, using a good scripting style can help you clarify your own ideas while you create a script, making complicated scripts easier to create as well as understand.

STYLE TIPS
Consider the following style factors when you create scripts:

Using white space


You can improve the format of your MEL scripts with proper use of white space and comments. Both make the script easier to read and understand. White space includes spaces, tab characters, and blank lines. When you add white space to a script, the execution of the script is not affected. However, judicious use of white space can greatly increase the readability of your script. Note that you must insert at least one space between keywords and variables. Other than that, white space is used only to organize your script into a readable format. For example, consider the following problematic MEL script:
int string $text; if (rand(10 $scale = 0; ) <

1){ $scale = 10; $text = "Exceptional scaling";} else $text = "Default scaling";

Technically, the above example is correct. However, the format makes it difficult to read. You can use spaces, tabs, and blank lines to make the script more understandable. Here is the same script with better use of white space:

MEL
99

STYLE | 14
Style tips
int $scale = 0; string $text; if (rand(10) < 1) { $scale = 10; $text = "Exceptional scaling"; } else $text = "Default scaling";

Adding comments
Adding comments for each MEL file, procedure, or logical segment enhances the readability of the script. This is important because someone, including yourself, may need to understand or modify your script after it is written. The comments can act as explanations, reminders, or descriptions in your script. You can create single-line or variable-line comments. Single-line comment To create a single-line comment, enter two forward slashes (//), then enter the comment:
int $locator = 7; // Default locator number is lucky.

Variable-line comment To create a variable-line comment, enter a forward slash asterisk (/*) at the beginning of the comment. At the end of the comment, enter an asterisk forward slash (*/). You can apply this type of comment on a portion of a line or multiple lines.
/* This is an example of a variable-line comment. */

Be aware that this comment technique doesnt work in expressions. Only // works in expressions. Nesting a variable-line comment will cause an error. Be careful that you do not enclose other variable-line comments inside a variable-line comment. The following example shows an incorrect variable-line comment:
/* I am commenting out the below MEL command. int $lock = 7; /* Default lock number is lucky. */ */

The above example causes an error. To avoid this problem, you might want to use only single-line comments.

Naming variables
When you are using variables in scripts, remember these style guidelines: Use descriptive variable names Avoid magic numbers Avoid global variables

MEL
100

PART 3

STYLE | 14
Style tips

Use descriptive variable names


To keep your MEL script clear and understandable to yourself and future users, use a variable name that describes the variables function. Variable names such as x, i, and thomas are not as informative as carIndex, timeLeft, and wingTipBend. However, do not be too verbose. For example, indexForMyNameArray, is overly descriptive. Be clear, descriptive, and terse.

Avoid magic numbers


A magic number is a number that seems to come from deep space. In general, if a number is not 0 or 1, it is a magic number. Of course, when you are scripting in MEL you will probably use numbers other than 0 or 1. If you use magic numbers, try to use a variable at the beginning of the script or string to hold that number. This allows easy identification and access to numbers and strings that may need to be modified in the future. For example:
float $PI = 3.14159; string $errorMessage = "Need to select object first.";

Lets say you used the PI variable at the beginning of the script and used that variable instead of the actual number at each place in your script where it was needed. You could quickly change the value of PI to increase its accuracy.

Avoid global variables


Global variables are dangerous to use for the exact reason that people use them: they are visible outside of the specific procedures and MEL scripts where they were declared. This visibility also makes them susceptible to being modified by any other MEL script that tries to use a global variable with the same name. This can create a problem that can be very difficult to find. Example
proc int checkVisibility(int $value) { global int $myIndex = 0; $myIndex = $myIndex + $value; return $myIndex; } proc iSeeYou() { global int $myIndex = 0; int $value = checkVisibility(1); $myIndex = $myIndex + $value; print($myIndex); } iSeeYou; // Result is 2.

When the procedure iSeeYou is executed, the myIndex global variable becomes 2. This is because both procedures increment myIndex. However, when you need to use a global variable, create a unique name so you do not overwrite the data of an existing global variable. You should also avoid global variables in procedures.

SCRIPTING

MEL
101

STYLE | 14
Style tips

Procedures and scripts


There are three general guidelines to keep your MEL procedures and scripts more readable and maintainable: Avoid global procedures. Limit procedures and command scripts to 50 lines. Limit files to 500 lines.

Avoid global procedures


Like global variables, global procedures are susceptible to being modified by any other MEL script that tries to use a global procedure with the same name. If you use global procedures, be sure to use a unique name so that you do not overwrite an existing procedure. Another potential problem with global procedures is memory requirements. Maya stores in memory every global procedure it encounters. The more global procedures you have loaded, the more memory Maya uses to store them.

Limit procedures and command scripts to 50 lines


To keep your procedures and MEL command scripts tractable, limit them to 50 lines. Exclude any comments or blank lines from your 50-line limit. Procedures and MEL scripts may become too complex when they are over 50 lines.

Limit files to 500 lines


Many MEL scripts contain multiple procedures. For these larger script files, it is a good idea to limit their length to 500 lines. If a file exceeds this length, consider splitting it into multiple files. This keeps your MEL script files manageable.

Bullet-proof scripting
When composing MEL scripts, keep the user in mind (even if you are the only user). Make sure that the MEL script considers user errors and handles these errors gracefully. Think about the errors that your MEL script might encounter. After checking for an error and finding that it is present, have a reasonable contingency action in your MEL script for that error. Example
proc burn(string $items[]) {print("Burning all items!\n");} proc burnSelected() { string $selected_s[] = ls -sl; if (size($selected_s) > 10) burn($selected_s); else print("Need more than ten items to burn."); }

In this example, if the burnSelected procedure lacks what it needs to perform, it creates an error message rather than failing. It assumes that the burn procedure would fail if given less than ten items. Of course, in this example, the burn procedure would not fail since all it does is print a string.

MEL
102

PART 3

15

FAQS
The FAQs in this chapter were culled from Maya developers, hotline support, trainers, and discussion lists. The questions and answers directly reflect the concerns and questions of people learning and using MEL. Please note that the complexity of the explanations can vary depending on the subject matter.

FUNDAMENTAL FAQS
How do I make a MEL shelf button?
To make a shelf button for a MEL command, all you have to do is drag-and-drop the command from the Script Editor to the shelf. Maya will automatically create a default icon for you.

How can I get the names of selected objects?


To get the names of all the currently selected objects, use the following command:
ls -sl;

How can I get the best performance from MEL?


The following tips can help you write more efficient MEL code: Specify the size of an array in a declaration, if known For example, use float $a[42]; instead of float $a[];. All arrays grow as required, so if you know dont know exactly how many elements an array might hold, but you know a reasonable maximum, use it. Without a size specified, MEL uses a default size of 16 elements for allocating memory for arrays. For example, use
float $a[50]; $a=someCmd;

where someCmd would typically return less than 50 things. For the same reason, use explicit size when initializing arrays. For example, use
float $a[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

To reference a global variable, you must explicitly declare it in the scope in which it is used This is necessary because MEL allows the implicit declaration of variables through assignment. For example,

MEL
103

FAQS | 15

$flag = 42;

implicitly declares $flag to be an integer defined within the current scope. MEL cant discern whether the you mean to reference a global variable $flag or to define your own locally. Requiring you to explicitly declare globals before referencing them relieves you from having to be aware of all the global data that can exist within Mayas system. Initialization is different from assignment This distinction is really only important for global data. For non-global data, initialization works exactly the same as assignment because it will get executed every time the script or procedure containing it gets executed. Global initialization occurs only once and takes places before any execution occurs. For this reason, the initializer value must be a compile time constant. Using explicit declaration will produce faster executables When MEL has complete type information at compile time, it can produce executables which use functions specific to these data types to run the script. If MEL cannot determine a variables type at compile time, it must defer the type checking to runtime. This is an overhead which is avoided if type information is known at compile time.

What is the difference between the two enter keys on the keyboard for Maya?
The alphanumeric enter key is like a typewriter enter key: it just places the cursor on the next line. In contrast, the keypad enter causes Maya to execute the contents of the Script Editor. In general, you should highlight the text in the Script Editor before executing it. This ensures that the text remains in the input window even if an error occurs. The two enter keys also behave slightly different if used in the command line. The alphanumeric enter key causes the focus of the cursor to leave the command line. This frees the user up for other input but also executes the commands in the command line. If the keypad enter is used in the command line, the commands are executed but the focus of the cursor remains in the command line. Note that using the alphanumeric enter key in the channel box will also cause the focus of the cursor to leave the channel box after input which is generally the desired result.

What are the differences between expression and MEL syntax?


There are only two differences between expression and MEL syntax: direct access of object attributes, and the use of the time and frame variables. Direct access of object attributes In an expression, you can directly access object attributes where as in MEL you must use the getAttr, setAttr, getParticleAttr, or setParticleAttr commands. The following are some examples of expression syntax that directly accesses object attributes.
persp.translateX = 23.2;

MEL
104

PART 3

FAQS | 15

float $perspRotX = persp.rotateX;

To do something like the above in MEL you would have to use the setAttr and getAttr commands as the following examples illustrate.
setAttr("persp.translateY", 23.2); float $perspRotY = getAttr("persp.rotateY");

Execute the following command in the Script Editor to create a couple particles:
particle -position 1 2 3 -position 2 1 3 -name dust;

now you can use the following expression syntax for the particle shape:
vector $pos = position; acceleration = <<2, 1, 0>>;

To do something like the above in MEL you would have to use the setParticleAttr and getParticleAttr commands as the following examples illustrate.
select dustShape.pt[0]; float $temp[] = getParticleAttr("-attribute", "position", "dustShape.pt[0]"); vector $position = <<$temp[0], $temp[1], $temp[2]>>; setParticleAttr("-attribute", "velocity", "-vectorValue", -3, 0, 0, "dustShape.pt[0]");

Note that the above MEL commands are only for the first particle in the particleShape. Use of time and frame variables In an expression, you can use the time and frame predefined variables. For example:
persp.translateY = frame; persp.rotateY = time;

You cant use time and frame in MEL. To access time and frame information in MEL, you have to do something like the following:
float $frame = currentTime -q; string $timeFormat = currentUnit -query -time; currentUnit -time sec; float $time = currentTime -q; currentUnit -time $timeFormat;

What are pointers and does MEL have any?


From the point of view of a computer, a variable consists of the data it holds along with its address, which indicates where the computer stores the variables data. Some programming languages allow you access and manipulate variable addresses by providing a special type of variable that can hold variable addresses. This special type of variable is called a pointer. MEL does not currently include pointers.

How do I print things?


The print function is overloaded to accept a single scalar argument of types int, float, string, vector and matrix. Consider the following examples:
$a = 42; print $a;

SCRIPTING

MEL
105

FAQS | 15

$b = 4.2; print $b; $c = "Hello World\n"; print $c; $v = <<1.1,2,3>>; print $v; $m = <<1.0, 2.5, 34; 42.42, 100.0, 99.99>>; print $m;

Most people needing to print something will be wanting to print strings constructed from various values. This requires the use of the string concatenation operator(+). Heres how to construct a string with embedded variable references:
for ( $i=0; $i<10; ++$i) { print ("This is the " + $i + "th time through this for loop.\n"); } string $nameOfSphere[] = `sphere`; print ("The name of my new sphere is: " + $nameOfSphere[0] + "\n");

Or, you can embed a command right into the string concatenation expression: print
("The name of my new sphere is: " + sphere + "\n");

Be careful that the command you embed actually returns a scalar value. String concatenation cannot handle arrays, so the following is incorrect:
print ("Heres a list of things: " + ls + "\n");

and you will get an execution error. Note that you need to put parentheses around these string concatenation expressions or else you will get a syntax error.

How can I tell if a script is available?


Use the exists command. The exists command is used to query for the existence of a command or procedure. It can be used to prevent runtime errors if you want to execute a script that may not be available. For example, to find out if a script named test.mel that defines a procedure named test is in your script path, you can do this:
if (exists test) { test; } else { warning "Test script not run"; }

How can I tell which script I am running?


Use the whatIs command. The whatIs command returns a string indicating whether the argument is a command, a procedure, a script, or is unknown. If you give it a script name, it will return the path of the script. This is useful if you suspect that Maya is using the wrong script and you want to double-check. For example:
whatIs test.mel; // Result: Script found in: ./test.mel //

MEL
106

PART 3

FAQS | 15
Command FAQs

COMMAND FAQS
What is the relationship between () and string argument syntax for commands?
The relationship is best understood by experimentation. Try executing the following commands in the Script Editor:
global proc example(int $chow, string $color) {} // Declaration of trick example 3 legoGreen; example "3" "legoGreen"; example(3, legoGreen); // This works. // This works. // This fails.

In command style, MEL commands (the first two examples above), arguments are treated like strings. In expressions and in the procedure style MEL commands (the last example above), arguments are not treated like strings so you must make the arguments strings where necessary:
example(3, "legoGreen"); // This works.

The same thing applies to commands:


ls -sl -type transform; // This works because the arguments are // converted automatically to strings. ls "-sl" "-type" "transform"; // This works because the arguments are // already strings. ls("-sl", "-type", "transform"); // This works because the arguments are // already strings. ls(-sl, -type, transform); // This fails because the arguments are // NOT converted automatically to strings.

What is the syntax for using equations, strings, vectors, and variables in MEL commands?
The following shows some examples and explanations of the syntax for using equations, strings, vectors, and variables in MEL commands:
sphere -name cake; int $feet = -1; setAttr cake.tx $feet + 3; setAttr cake.tx ($feet + 3);

// Wrong // Right

When using an equation in a MEL command you must surround the equation with parentheses:
string $object = "cake"; setAttr $object.tx 2; setAttr ($object + .tx) 2; setAttr ($object + ".tx") 2; // Wrong // Wrong // Right

You cannot combine strings by having them right next to each other. The only way to do it is to use the + operator between strings. Also, .tx is not a string, .tx is. Remember to use parentheses, because combining strings is done using an equation:

SCRIPTING

MEL
107

FAQS | 15
Attribute FAQs
vector $code = <<1, 2, 3>>; setAttr cake.tx $code.z; setAttr cake.tx ($code.z);

// Wrong // Right

Note that when using vector components in a MEL command you must surround the vector component with parentheses.

What is the command for getting the Set Editor?


The command for getting the Set Editor is as follows:
tearOffPanel "set editor" "setEditor" true;

ATTRIBUTE FAQS
Why are the extra attributes I added not in the Channel Box?
Suppose you have written a script that creates extra attributes on an object, but they are not being displayed in the Channel Box. Also, their keyframes dont show up in the Time Slider. To get the extra attributes displayed in the Channel Box, you need to use the following command on the attributes in your script:
setAttr -e -keyable true

How can I change the order of extra attributes in the Channel Box?
You cant change the order of extra attributes in the Channel Box. Maya requires the order to be the order in which they were created. You could write a script that reads the current attributes, deletes them all, and adds them again in the order you want. However, this would break connections with expressions and other objects.

How do you get and use attributes that have more than one value?
A common problem is how to get and use the values of an attribute that has several values. For example, you might want to execute the following:
string $shapes[] = sphere; string $cmd; $cmd = "xform -ws -p true -piv " + getAttr ($shapes[0] + ".translate");

However, the last line will cause an error. This is because the getAttr command returns an array of floats (the translate x, y and z values), and an array value can not be added to a string. The only way turn these translate values into a string is to first put them into an array of floats so that the individual values can be used:
float $trans[] = getAttr ($shapes[0] + ".translate");

Now, you can build the command string by using the individual translate values that you just extracted. (A non-array value, which is in this case an element of a float array, can be added to a string.) Remember to add a space to the string in between the translate values to they dont get combined. (For example, you will probably want 0 0 0" instead of 000.)
$cmd = "xform -ws -p true -piv " + $trans[0] + " " + $trans[1] + " " + $trans[2];

MEL
108

PART 3

FAQS | 15
Variable FAQs
// Result: xform -ws -p true -piv 0 0 0 // eval($cmd);

How do you set attributes that take more than one value?
Lets say that you want to set the translate attribute with one of the following was but it is just plain not working.
sphere -name nurbsSphere1; vector $newPos1 = <<1, 2, 3>>; setAttr nurbsSphere1.translate $newPos1; // ERROR float $newPos2[3] = {1, 2, 3}; setAttr nurbsSphere1.translate $newPos2; // ERROR

The trick here is that you must separate the elements of the vector or array in the setAttr command and surround them with parentheses:
setAttr nurbsSphere1.translate ($newPos1.x) ($newPos1.y) ($newPos1.z); setAttr nurbsSphere1.translate ($newPos2[0]) ($newPos2[1]) ($newPos2[2]);

Actually, only for the vector do you need to surround the components with parentheses. But it does not hurt to add parentheses and it is easier to remember if you always do this.

VARIABLE FAQS
How can I find out what variables have been declared?
How can you check if a variable has been declared without getting an error? And how to check a variable that hasnt been declared? Use the env command. This stores a list of all currently declared global variables. Then parse through the list comparing the name of the variable that you are checking against the list. Return a 1 if that is in the list and a 0 otherwise.

How do global variables work?


The syntax is as follows:
global <type-specifier> <variable-name>

For example:
global float $floatArray[100];

To reference a global variable within a procedure, you must explicitly declare it at the outermost scoping level so that it will be used within the procedure. For example:
global int $counter = 0; proc int useCounter() { global int $counter; return $counter++; }

SCRIPTING

MEL
109

FAQS | 15
String FAQs If you do not explicitly declare $counter as a global variable, MEL will assume that it is local to the procedure and will either implicitly declare the variable if it is part of an assignment statement, or else it will give an error (as in the case above) for being referenced before being defined. What declaring the variable at the outermost scoping level means is best illustrated using a counter-example:
global int $counter = 0; proc int useCounter(int $switch) { if ( $switch >= 0 ) { // open curly brace opens a new scope. global int $counter; $counter++; } else { // close curly brace closes the scope. return -1; } return $counter++; // ERROR - use of $counter outside of // scope where it was declared. }

Alias|Wavefront uses the convention of starting the name of global variables with a g--for example, $gMainWindow. To prevent name clashes you should choose a different prefix for your own global variables.

How do I list all global variables?


Use the env command. The env command returns a list of all global variables that have been defined. Note that if a global variable exists in a script that hasnt been run yet, it will not show up in the output from env.

STRING FAQS
How can I change an integer to a string?
Heres an example:
int $counter = 1; string $bob = "bob"; string $number = $counter;

How do I concatenate strings?


Use the + operator. For example:
string $who="world"; print ("Hello " + $who + "\n");

Note: Just as in C, you have to provide your own newline character to the print function.

How do you put variables and special characters into strings?


To put variables into strings you must use the + operator (or += operator). The following shows some example uses of this operator to put variables into strings.
int $int = 7; float $float = 3.1459; string $string = "XX-XX";

MEL
110

PART 3

FAQS | 15
Vector FAQs
vector $vector = <<1.2, 2.3, 3.4>>; string $build = "Building an int, " + $int + ", into a string.\n"; $build = $build + "Building a float, " + $float + ", into a string.\n"; $build = $build + "Building a string, " + $string + ", into a string.\n"; $build = $build + "Building a vector, " + $vector + ", into a string.\n"; print($build);

Here is the output:


Building Building Building Building an int, 7, into a string. a float, 3.1459, into a string. a string, XX-XX, into a string. a vector, 1.2 2.3 3.4, into a string.

To build special characters into a string just precede the special character with a back slash ( as the following examples illustrate.
string string string string $quote = "'"; $newLine = "\n"; $tab = "\t"; $forwardQuote = "\"";

VECTOR FAQS
What is a vector component?
A vector is a type of data stored by maya that consists of 3 distinct numerical components. For example the vector defined by:
vector $hello = <<5, 7, 9>>;

is comprised of the three individual components 5, 7, 9. The first component is called the x component, the second is the y component, the third the z component. So, in general:
vector $variableName = <<x,y,z>>;

How do I extract individual components of a vector?


The following example shows how you can extract individual vector components and assign them to different variables:
vector $test = <<1,4,9>>; int $firstComponent = $test.x; int $secComp = $test.y; int $thirdComp = $test.z;

ARRAY FAQS
How do I initialize an array?
Examples are the easiest way to answer this question:
$myArray[10] = 1;

This implicitly declares $myArray to be an array of 10 ints, and assigns 1 to the last element, a[9].

SCRIPTING

MEL
111

FAQS | 15
Matrix FAQs
int $myArray[5]= { 1,2,3,4,5 };

The above declares $myArray to be an array of size 5 with the a[0] value initialized to 1, a[1] to 2, and so on.

How can I dynamically increase the size of an array?


Suppose youd like to dynamically grow an array. Some interpreted languages offer commands like push and pop to put things into a list and then retrieve them in an orderly way. How can you build your own arrays in MEL that are not generated by the return value of a function? One way to dynamically increase the size of an array is to do the following.
int $num[]; int $i; int $j; for($i = 0; $i<10;$i++) { $j = size($num); $num[$j] = $i; }

You are taking the size of the array and then using that value as the index. Remember that the first value in an array is at index 0 and the second element would be at index 1 and so on. If you have an array with 6 items in it and you do a size command the answer will be 6, but the last item in the array is accessed using 5 as the index. Therefore using 6 as the index would point to the next value in the array.

How do I allocate and resize arrays?


You dont. MEL does it for you when you assign the variables a value. (MEL is significantly different from a language such as C in this respect.)

Are local array variables destroyed by MEL or do I have to call 'clear' on them to get the memory back?
Arrays and other variables are freed when you leave the scope in which they were defined. So, if an array is stored in a local variable, it will be automatically freed when leaving the procedure, loop, or if statement in which it was defined.

MATRIX FAQS
How do I use the matrix data type?
To explicitly declare a matrix, you must specify 2 dimensions:
matrix $m[2][3]=<<1,2,3; 4,5,6>>; // Result: << 1 2 3; 4 5 6 >> //

or you can implicitly declare it:


$a=<<1,2,3; 4,5,6>>; // Result: << 1 2 3; 4 5 6 >> // $b = $a; // implicitly declares $b the same shape as $a.

A matrix expression is surrounded by double angle brackets. Rows are separated by semicolons and the columns of a row are separated by commas. A vector now is just a special case of a matrix.

MEL
112

PART 3

FAQS | 15
Flow control FAQs You can add, subtract, multiply, divide, and modulo a matrix by a scalar. Operations with scalars produces a result the same shape as the matrix. You can do matrix multiplication:
matrix $m[3][4], $n[4][3], $res[3][3]; $m = << 1,2,3,4; 5,6,7,8; 9, 10, 11, 12 >>; $n = << 1,2,3; 4, 5,6; 7, 8, 9; 10, 11, 12 >>; $res = $m * $n; $p = $m * $n; //implicitly declares $p a 3x3 matrix.

You can negate a matrix:


$negp = -$p

You can reference a specific element of an matrix just as you would an array element:
$f = $m[1][2]

Can I specify a dynamic matrix?


You cant specify the size of a matrix with a variable. Also, there is no command which will clear a matrix and free up the memory it uses.

FLOW CONTROL FAQS


How do I iterate through a list of things?
If you have a command which returns a homogeneous list, you can use an array. MEL currently supports single dimensioned arrays of type int, float, vector, and string. Most commands which return lists produce lists of strings. A good example of this is the ls command. So, to loop through the items returned by the ls command, do this:
$listOfThings=ls; // Note that if listOfThings hasnt been declared // yet, it will be dynamically typed based on the // result of the "ls" command. for ($i=0; $i < size($listOfThings); ++$i) { foo $listOfThings[$i]; }

Alternatively, do this:
$listOfThings=ls; for ($thing in $listOfThings) { foo $thing; }

How do I use variable argument lists?


At the procedure definition site, declare your argument as an array of whatever data type you need. At the call site, use an array variable of the same type. Alternatively, you can use the array expression notation to create a array without having to declare a variable and do all of the assignments into it. For example: SCRIPTING

MEL
113

FAQS | 15
Flow control FAQs
proc foo ( float $f[], string $s[]) { print("size of f=" + size($f) + "\n"); for ( $i=0; $i < size($f); ++$i ) { print("f[" + $i + "]=" + $f[$i] + "\n"); } print("size of s=" + size($s) + "\n"); for ( $i=0; $i < size($s); ++$i ) { print("s[" + $i + "]=" + $s[$i] + "\n"); } } float $ff[2]={0.9, 1.2}; float $gg[]; for ( $i=0; $i < 10; ++$i ) { $gg[$i] = $i; } foo $ff {}; // passes the array "$ff" and the empty array to foo. foo $gg {"hello", "world"}; // passes the array "$gg" and an array of 2 strings // to foo. foo {} {}; // calls foo with 2 empty arrays.

Note that array expressions get their base type from the type of the first element in the list. So, to force your array expression to be of a certain type, you can cast the first element:
foo {(float)1, 2, 3} {"hello"}; // make first array an array of float, not int.

How do I execute a statement created at runtime?


Use the eval command. The eval command is designed to allow execution of a string that is built at runtime. For example:
switch($timeOfDay) { case "morning": $shape = "circle"; break; case "afternoon": $shape = "sphere"; break; case "evening": $shape = "cone"; break; default: $shape = "cylinder"; } eval $shape -r 5; // create specified shape with radius 5.

Alternatively, you could use eval in the following way:


eval ($shape+"-r 5");

See also the evalEcho and evalDeferred commands.

MEL
114

PART 3

FAQS | 15
Flow control FAQs

How can I prevent a script from terminating on errors?


Use the catch command. Normally a runtime failure will terminate the execution of a script. The catch command is designed to allow recovery from runtime failures. This is useful if you are executing a command or script that may fail but that failure is expected and shouldnt stop the script currently being executed. The most common use for catch is when executing a runtime generated command.
catch( eval($cmd) );

Another example is when the failure of a command needs to be noted.


if (catch(rename $oldName $newName)) { // error due to non-unique name confirmDialog -title "Alert" -button "OK" -defaultButton "OK" -message "Name is not unique. Please select another:"; }

What is the difference between eval, , and ()?


Commands and procedures are executed in the same way. The following examples illustrate this point.
proc float myTime(string $dummyFlag, float $time) currentTime -e 1; myTime -e 1; currentTime "-e" "1"; myTime "-e" "1"; currentTime("-e", 1); myTime("-e", 1); {return $time;}

To execute a command or procedure and get the return value you could use the eval, , or ( ) syntax as the following examples illustrate.
string $transforms[]; $transforms = eval("ls -type transform"); $transforms = ls -type transform; $transforms = ls("-type", "transform");

Below are the pros and cons on using each of these types of syntax. Pros and cons for eval syntax: 1 Delayed evaluation. This means that when a script is executed, if the command is not defined, Maya will still try to execute it. For example, if you try to execute a script that first loads a plugin and then immediately executes it, the script will fail when the plugin command is executed. This is because Maya initially evaluates the script to check for commands that it does not know. However, if the plugin command is executed using the eval syntax then the script will not fail. Can embed commands. For example: eval(sphere; cone; ls); Entire command, including its arguments, must be a single string. For example:
eval(ls -type transform);

2 3

Pros and cons for syntax: 1 2 Immediate evaluation. Can not embed commands.

SCRIPTING

MEL
115

FAQS | 15
Procedure and function FAQs 3 4 Do not need to put string arguments in quotes. For example: string $trans2[] =
ls -type transform;

Can not use this syntax as a stand alone command. For example, you can not do the following: ls -type transform; Pros and cons of ( ) syntax:

1 2 3

Immediate evaluation. Can not embed commands. Must put string arguments in quotes. For example: ls("-type", transform);

PROCEDURE AND FUNCTION FAQS


What is a simple explanation of a MEL procedure?
A MEL procedure is a collection of MEL commands that can be easily accessed by executing only the name of that procedure (and any associated arguments) instead of executing the individual MEL commands one at a time. A procedure generally has the following format:
<<global>> proc <<return type>> procName (<<argument list>>) { MEL commands; }

The items inside the << and >> symbols above are optional and depend on the specific case of usage. A typical example is shown below:
global proc myProcedure (string $letter, int $number) {

print ($letter + " " + $number); }

When executed, the above procedure will print out a letter then a space then a number. The information that gets printed out is determined by the arguments the user passes in. For example, the above procedure could be executed using the following:
myProcedure hello 5;

The printed result from MEL is:


hello 5

In this example, the argument list of the procedure is (string $letter, int $number). This means that the hello procedure is expecting two pieces of information to be sent into it before it can successfully execute. In this case, the user (or another procedure) must supply a string and a number otherwise an error will occur. The above execution assumes that the procedure either resides in a script file with the same name as the procedure (and a .mel extension), or that it has been highlighted in the Script Editor and executed.

MEL
116

PART 3

FAQS | 15
Procedure and function FAQs

How are arrays passed in commands and function calls?


Arrays are passed by reference. If you pass an array as an argument to a procedure and modify that argument within the procedure, the array will have the modified values upon return from the procedure call. For example:
proc fred( string $myArray[] ) { for ( $i=0; $i<size($myArray); ++$i ) { $myArray[$i] = "fred"; } $myArray[$i] = "flintstone"; // add to the end of the array. } string $a[] =ls -geometry; print("Before call to fred\n"); print $a; fred($a); print("After call to fred\n"); print $a; produces this output: Before call to fred nurbConeShape1 nurbConeShape2 nurbSphereShape1 nurbSphereShape2 After call to fred fred fred fred fred flintstone

How do I return a specific type of data from a MEL procedure?


The syntax for the proc line is:
proc <return_type> procName ( optional parameters ) ...

where <return_type> is one of the valid MEL data types. So, to have your procedure foo return a string, use:
proc string foo ()

Note that if you omit the return type, your procedure cannot return anything. Conversely, if you want your procedure to return something, you must explicitly indicate this on the proc line.

How do I capture a return value?


In order to do this you should know what the type is of the value that you want to get. This is because you need to put the value of what you are seeking into some MEL variable of a certain type (such as int, float, string, int array, matrix). You can find out what type you need by looking at the documentation for the command or procedure. Examples of capturing attribute values:
sphere -name doughnut; float $doughXvalue = getAttr doughnut.translateX; float $doughPosition[] = getAttr doughnut.translate;

SCRIPTING

MEL
117

FAQS | 15
Modeling FAQs
int $visible = getAttr doughnut.visibility; string $type = getAttr -type doughnut.translate;

Example of capturing the return value of a command:


string $objects[] = ls -sl;

Example of capturing the return value of a procedure:


proc string dayTripper(float $noise) {return "tripzThis";}

string $whatTheDealyYo = dayTripper(22.3);

MODELING FAQS
How can I count polygons?
You can count polygons with the polyEvaluate -f command.

How can I get the name of a (selected) shape node?


In general, you can use ls -sl for getting the names of currently selected nodes. To get shape node names only, you can use ls -s. You can also use the listRelatives command to get the names of all the shape nodes that are hierarchically below (that is, child nodes) the currently selected nodes. For example:
string obj[]= ls -sl; listRelatives -s $obj[0];

Commands to pick curve on surface


What is the command to pick a curve on surface? Suppose you would like to set up marking menus to pick curves and curve on surface. You can do the following:
selectMode -object; selectType -allObjects false; selectType -curveOnSurface true;

Now you can drag the results to the shelf, and youre ready to rock! Alternatively, drag this to the shelf:
setObjectPickMask "All" 0; setObjectPickMask "Curve" true;

How do I get and set specific UV values on a polygon?


Use the PolyMoveUV command. A good way to use this command is in conjunction with setAttr statements. To see how MEL implements this, create a polyPlane, then pick some polyUVs on that plane. Select the plane then open Window > UV Texture Editor. This shows us the UV coordinates for the selected object. With the PolyUV(s) still selected, choose Polygon > Move component then use the manipulators displayed in the UV Texture Editor to see what MEL commands get written to the Script Editor window. Generally, the output looks something like:

MEL
118

PART 3

FAQS | 15
Animation FAQs
setAttr "polyMoveUV5.translate" -type double2 0 -0.1187236 ;

You can set or store the outputs using normal arrays.

How can I create a closestPointOnSurface node?


To create this node, simply enter the following in the Script Editor:
createNode closestPointOnSurface

Then you can connect it to another node using the Connection Editor.

How can I get an objects pivot point in world space?


Use the xform command. For example:
xform -q -ws -rp ball; // Result: 7.099792 7.984488 -4.93999 // xform -q -ws -sp ball; // Result: 7.099792 7.984488 -4.93999 //

ANIMATION FAQS
How to randomize keyframes?
Basically. youll use the keyframe command with the -vc (valueChange) option, and youll pass it a rand MIN MAX as argument. For example, to randomize sphere.tx between 1.5 and 3.2:
float $random; int $n=keyframe -q -kc sphere.tx; //total number of keyframes in tx for($i=0;$i<$n;$i++) { $random=rand 1.5 3.2; keyframe -e -at tx -in $i -vc $random sphere;

To randomize all the attributes, you can write an upper loop in which you change the attribute to be randomized.

DYNAMICS FAQS
How can I select a set of particles?
Suppose you wants to be able to select a group or set of particles. For example, you want to run a simulation, stop it, select some particles, go back to frame 1, deselect the particles, run the simulation, and then be able to reselect the same set of particles. You can either use the quick set or a MEL script. In MEL, you can do the following:
//Saves current selection for later use. string $selectionSet[];

SCRIPTING

MEL
119

FAQS | 15
Rendering FAQs
$selectionSet = ls -sl; //Recalls saved selection. select -r $selectionSet;

RENDERING FAQS
How can I make a list of what objects are connected to what shading groups?
Heres an example of how to make a list of what objects are connected to what shading group:
for ($SG in $listofShadinggroups) { string $connectedObjects[] = sets -q $SG; for ($connectedObject in $connectedObjects){ print ( $connectedObject + " is connected to " + $SG

+ "\n"); }

How can I render from within a script?


You can use the system and batchRender commands to render from within a script. For example, you could use the batchRender command as follows:
batchRender -f "absolute path to filename";

Alternatively, you could do the following:


system ("Render -s 1 -e 10 -b 1 absolutepath to filename");

In this case, you would need to do a file save command before issuing that command to ensure that the rendered scene is the most current version.

What is the command to strip shaders from an object?


Use the disconnectAttr command, for example:
string $dgSetMember[]=`listConnections -type shadingEngine -p 1 nurbsSphereShape1` ; string $instObjGrp=`connectionInfo -sfd $dgSetMember[0]`; disconnectAttr $instObjGrp $dgSetMember[0];

SYSTEM INTERACTION FAQS


How do I execute a operating system command from MEL?
You can simply use a system call from MEL. Example of usage would be as follows:
system "ls -l";

This will print the current directory to the Script Editor in long format. Check out the online MEL Command Reference documentation under administrative commands for more information.

How does Maya store scripts?


Does Maya store any scripts (global proc) or any global variables in the file when saving, or are they always newly loaded when opening a new session?

MEL
120

PART 3

FAQS | 15
File control FAQs All the global variables and global procedures are stored in memory during the session and die when the program finishes and are not stored in your file. When you restart Maya, certain procedures and variables that are part of the interface are automatically reloaded to build the interface. If you need a variable to be persistent between two sessions, you can use the command optionVar that stores persistent variables in the file userPrefs.mel. Moreover, if you need one of your scripts to be present automatically when you start Maya, you can put them in a file named userSetup.mel, located in your script directory. Finally, you can use a script nodes to keep a script with a particular scene.

On UNIX-based systems how can I use the system command to run a process in the background?
To run a command in the background (that is, do a non-blocking system call), you must redirect all of the commands output:
system("cmd >/dev/null 2>&1 &");

Of course, you can send output to somewhere other than /dev/null if you like.

How do you get the current time in seconds using MEL?


The following commands create a $time variable which gives you the current time in seconds.
string $timeFormat = currentUnit -query -time; currentUnit -time sec; float $time = currentTime -q; currentUnit -time $timeFormat;

Note that the $time variable is not automatically updated.

FILE CONTROL FAQS


How do I open and write files from MEL?
Use the fopen and fwrite commands.

How can I export selected data to an already opened file?


You can use a variation on the following:
string $tmp =file -q -sn; file -rename "tests" ; file -es; file -rename $tmp;

PROJECT CONTROL FAQS


How do I change projects with MEL?
Heres an example for a project named trumpet:
workspace -o "/home/matt/maya/projects/trumpet";

SCRIPTING

MEL
121

FAQS | 15
Script path FAQs
np_resetBrowserPrefs; pv_resetWorkspace; pv_goCurrentProject; print ("Current project is trumpet\n");

SCRIPT PATH FAQS


Calling scripts
How does Maya call a script, and how does Maya know where the script is located? Within MEL you can set the script path temporarily for a session of Maya using the putenv command. For example:
putenv "MAYA_SCRIPT_PATH" "<explicit path>";

You can set the script path of Maya with an environment variable. For example, on IRIX, you could add the following to your .cshrc file:
setenv MAYA_SCRIPT_PATH /remote/scriptDisk/scriptFiles/;/home/ dave/scripts/;~/maya/scripts/

You can specify multiple paths if they are separated by semi-colons. Within MEL you can check this variable, but not modify it unless you do a system call. The command is:
internalVar -usd

In the Render Globals > Render Options > Post Render MEL script field, specify a global mel procedure that is contained in a MEL script. Omit the .mel extension. This script must be located in the script path.

How to make Maya look somewhere else for scripts?


On IRIX, is there a way to make Maya look somewhere else for scripts besides ~/ maya/scripts? You can set the MAYA_SCRIPT_PATH environment variable. For example, on IRIX, you could add the following to your .cshrc file:
setenv MAYA_SCRIPT_PATH /remote/scriptDisk/scriptFiles/;/home/ dave/scripts/;~/maya/scripts/

The above allows Maya to search several directories for scripts.

What is // Error: line <<XX>>: Cannot find procedure <<proc name>>?


The error message
//// Error: line 1: Cannot find procedure "fred". //

usually means that MEL cannot locate the procedure that the script or command you are executing requires. In other words, either the procedure has not been highlighted and executed in the Script Editor, the name was misspelled, or it doesnt exist in any of the scripts in your script path. It can also mean that there has not been enough information supplied to the script or command in order for it to work properly.

MEL
122

PART 3

FAQS | 15
Script Editor FAQs The first thing to do is to make sure that the procedure exists either on disk in your ~/maya/scripts directory (or script path). Check to make sure the spelling of the procedure name matches the spelling that you are executing. If you have confirmed that it exists in a script or has been sourced into memory via the Script Editor. The next thing to check is the argument list of the procedure that is reporting the problem.

How do I add a MEL script to Maya start-up?


How do you add a mel script to the Maya start-up? Say for instance that you want to change defaultRenderGlobals as follows:
setAttr "defaultRenderGlobals.animation" 1; setAttr "defaultRenderGlobals.extensionPadding" 4;

and you want this to happen for everybody running Maya, but of course without affecting their user preferences. You tried putting a mel script with the above into the /usr/aw/maya/scripts/ startup directory and the /home/$USER/maya/scripts directory, but neither attempt affected Maya on start-up. To retain preferences that are not saved in the user interface, create a userSetup.mel file in your ~/maya/scripts directory. Whenever you launch Maya, the MEL commands in it are executed. An example command used in the userSetup.mel file would be the following:
alias djs jointDisplayScale;

This creates an alias, djs, that lets you set the joint size without using the Display Joint Size menu or typing jointDisplayScale. You can enter the djs alias with a joint size in the Command Line or Script Editor:
djs 1.5;

The joint size is set to 1.5. You could also set Render globals or other prefs in this file. The scene is cleared after the commands in the userSetup.mel file are executed. Therefore, any scene elements created using the userSetup.mel file will have been removed when Maya comes up.

SCRIPT EDITOR FAQS


Is there an easy way to highlight text in the Script Editor?
Yes, if you are running Maya on, you can do the following: clicking LMB twice highlights a word clicking LMB three times highlights an entire line clicking LMB four times highlights the entire window.

What does show line numbers in the Script Editor do?


This option causes Maya to print out the line number of the script or group of commands where an error was encountered. There is no way to display printed line numbers in the current Maya Script Editor. An easy workaround is to use a separate editor that does support line numbers so you can track down the problem quickly. Jot, nedit, and vi all have this ability on. SCRIPTING

MEL
123

FAQS | 15
Custom interface FAQs

CUSTOM INTERFACE FAQS


How can I change the background color?
Use the following command:
displayRGBColor "background" r g b

Is there a way to destroy the window from a button click?


If you dont have the -retain flag set then the window should be destroyed when it is closed. If you want to delete a window, use the deleteUI -window command:
window -t "Master Gizmo" -w 200 masterGizmoWin; rowLayout; button -l "Delete This Window" -align "center" -c "deleteUI -window masterGizmoWin"; showWindow masterGizmoWin;

Is there a way to close a window, without destroying it, from a button click?
You can edit the window visibility state to dismiss it:
window -edit -visible false ;

Remember to use the -retain flag when creating the window, otherwise it will be destroyed anyway when it is closed.

How do callbacks for layouts work?


The frameLayout callbacks for expanding or collapsing layout are only called if the layout is collapsed or uncollapsed through the visible interface (for example, the small arrow icon the user can click on.) Using code such as the following will not invoke the callback:
frameLayout -e -collapse true $theFrame;

Please note that having callbacks work in this way is the only way we can allow things to get set up correctly when the window is first being created without getting into infinite loops. If a callback is needed and you know it is safe then call it directly at the same time you do the collapse or expand.

Can I register a callback to be notified when a window is destroyed?


Use scriptJob -uiDeleted command:
global proc uiDeletionCallback () { print "Window has been deleted\n"; } window -t "Master Gizmo" -w 200 masterGizmoWin; rowLayout; button -l "Close" -align "center" -c "window -edit -visible false masterGizmoWin"; showWindow masterGizmoWin; scriptJob -runOnce true -uiDeleted masterGizmoWin uiDeletionCallback;

MEL
124

PART 3

FAQS | 15
Miscellaneous FAQs This is useful if you need to do some cleanup work, and the user uses the window control menu to close the window instead of the buttons that you have provided.

Are there standard dialogs available: error, warning, questions, etc.?


Use the promptDialog command.

How can I make vertical sliders?


There are only two types of slider commands that allow the vertical orientation. They are floatSlider and intSlider. Note that he following commands do not accept the vertical orientation: floatSliderGrp, floatSliderButtonGrp, and intSliderGrp. The flag for the vertical orientation is -hr. This boolean flag is true by default, which specifies a horizontal slider. For example, to create a vertical slider, you would use:
floatSlider -hr 0;

MISCELLANEOUS FAQS
How do the error, warning, and trace statements work?
The syntax is as follows: [error|warning|trace] <expr>; Each of these commands takes only 1 argument. These commands are built-in MEL procedures which are provided so that the user can manipulate the output of his/her scripts. Here is how the output from these commands is directed:
error command window prepended with an error message prefix and surrounded

by //.
warning command window prepended with an warning message prefix and

surrounded by //.
trace directly to standard error.

NOTE: The error command also causes execution to terminate with an error. Using error is like raising an exception because the error will propagate up through the call chain. You can use catch to handle the error from the caller side. For example,
$l = ls -lights; if (size($l) == 0) { error "No Lights"; }

The above will produce the following output and terminate execution of your script:
// Error: line 4: No Lights //

If you dont want execution to end, then you probably want to use the warning command instead.

How can I abort a MEL script while it is running?


Unfortunately, you cannot abort a MEL script while its running. The only thing you can do is undo the operation once its done.

SCRIPTING

MEL
125

FAQS | 15
Miscellaneous FAQs

How do I export sets from a Maya file?


You can use the following:
ls -typ objectSet;

What is the operator for raising to a power?


The operator is pow. For example, $xpow5 will raise the value of $x to the 5th power.

Can I compile my MEL script (for faster execution)?


No, MEL is only an interpreted language.

MEL
126

PART 3

PART 4

MAYA GEMS

16

INTRODUCING MAYA GEMS


The following Maya Gems are useful scripts that you can study to learn more about MEL: "Particle Collision Boundary" on page 129 "Point Explosion" on page 131 "Testing Added Particle Attributes" on page 134 "Testing Dynamics Events" on page 137 "Dynamics Time Playback" on page 140 "Finding Unshaded Objects" on page 142

PARTICLE COLLISION BOUNDARY


By Bret A. Hughes Alias|Wavefront Santa Barbara Development Center This script, dynFuncBoundary.mel, tests the particle collision boundary for a mesh plane. The script creates an emitter above a sphere that is above a plane. The emitted particles are affected by gravity as they bounce off the sphere and the plane.

dynFuncBoundary.mel
// // // // // // // // // // // // // // // // dynFuncBoundary.mel Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK Creation Date: Author: 09 September 1996; Modified 08 January 2000 bah

Procedure Name: dynFuncBoundary Description: Creates scene to test the particle collision boundary for a mesh plane. Input Arguments:

MEL
129

INTRODUCING MAYA GEMS | 16


Particle Collision Boundary
// // // // // None. Return Value: None.

// // ========== dynFuncBoundary ========== // // SYNOPSIS // Creates scene to test the particle collision boundary for // a mesh plane. // global proc dynFuncBoundary() { // Clear the scene and reset the timeline. // file -f -new; currentTime -e 1; // Display information to the user about what to expect from this // subtest and give some time for the user to read this information. // print( "\nParticles fall and collide with ball and plane.\n" ); system( "sleep 1" ); // Create the bottom plane. // nurbsPlane -name plane; scale 7.01291 7.01291 7.01291; rotate 0rad 0rad -1.5708rad; move 0 0.2 0; // Create the ball above the plane. // polySphere -name ball; scale 1.20479 1.20479 1.20479; move 0 2.7 0; // Create the emitter above the ball and plane. Make the particles // affected by gravity and have them bounce off the ball and the // bottom plane. // emitter -type omni -r 100 -mnd 0 -mxd 0.7 -spd 1 -pos 0 5 0 -name emitter; particle -name particles; connectDynamic -em emitter particles; gravity -dx 0 -dy -1 -dz 0 -m 9.8 -pos 10 10 0 -name gravity; connectDynamic -f gravity particles; collision -r 0.50 -f 0.14 plane; collision -r 0.50 -f 0.14 ball; connectDynamic -c plane -c ball particles; // Make the picture a pretty one and play the test. // select -r particles; selectMode -component; hide plane ball;

MEL
130

PART 4

INTRODUCING MAYA GEMS | 16


Point Explosion

// Set up the playback options. // float $frames = 150; playbackOptions -min 1 -max $frames -loop once; // Time how long it takes to play the scene and then determine the // playback frame rate. Make sure when getting the frame rate // that no values are divided by zero. // float $startTime = timerX; play -wait; float $elapsed = timerX -st $startTime; float $fps = ($elapsed == 0.0 ? 0.0 : $frames/$elapsed); // Print the frames per second (fps) of the subtest in the form X.X. // print("dynFuncBoundary: Done. ("); print( (int)($fps * 10)/10.0 + " fps)\n" ); } // dynFuncBoundary //

POINT EXPLOSION
By Bret A. Hughes Alias|Wavefront Santa Barbara Development Center This script, dynFuncExplosion.mel, creates an emitter that emits particles. The emitter, Explosion, has extra attributes to control several properties of a simulated explosion. These attributes include the start frame, duration, intensity, fullness, and power of the explosion.

dynFuncExplosion.mel
// // // // // // // // // // // // // // // // // // // dynFuncExplosion.mel Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK Creation Date: Author: 21 September 1996; Modified 08 January 2000 bah

Procedure Name: dynFuncExplosion Description: Creates a point explosion that can be modified. Input Arguments: None. Return Value: None.

MAYA GEMS

MEL
131

INTRODUCING MAYA GEMS | 16


Point Explosion
//

// // ========== dynFuncExplosion ========== // // SYNOPSIS // Creates a point explosion that can be modified. // // global proc dynFuncExplosion() { // First delete anything that might be left over // from a previous test. // file -f -new; currentTime -e 1; // Display information to the user about what to expect from this // subtest and give some time for the user to read this information. // print( "\nBOOM!\n" ); system( "sleep 1" ); // Create emitter to be the source of the particles eminating from // the explosion. Add an internal variable to the emitter to // control amplitude attributes of the emitter. Render the particles // as multi streaks. // emitter -type omni -r 100 -mnd 0 -mxd 0 -spd 1 -pos 0 0 0 -n Explosion; addAttr -sn "ii" -ln "InternalIntensity" -dv 5 -min 0 -max 100 Explosion; particle -name ExplosionParticle; connectDynamic -em Explosion ExplosionParticle; setAttr ExplosionParticleShape.particleRenderType 1; // MultiStreak // Link // addAttr addAttr addAttr addAttr addAttr addAttr addAttr addAttr some renderable attributes to the particles. -ln -ln -ln -ln -ln -ln -ln -ln colorAccum -dv true ExplosionParticleShape; lineWidth -dv 1.0 ExplosionParticleShape; multiCount -dv 10.0 ExplosionParticleShape; multiRadius -dv 0 ExplosionParticleShape; normalDir -dv 2.0 ExplosionParticleShape; tailFade -dv 0 ExplosionParticleShape; tailSize -dv 3 ExplosionParticleShape; useLighting -dv false ExplosionParticleShape;

// Create some user-modifiable attributes to modify the // explosion. // select -replace "Explosion"; addAttr -sn "st" -ln "Start" -dv 10 -min 0 -max 100 Explosion; addAttr -sn "du" -ln "Duration" -dv 20 -min 0 -max 200 Explosion; addAttr -sn "in" -ln "Intensity" -dv 10 -min 0 -max 100 Explosion; addAttr -sn "fu" -ln "Fullness" -dv 10 -min 1 -max 100 Explosion; addAttr -sn "po" -ln "Power" -dv 10 -min 0 -max 100 Explosion; // Create the time the explosion has been alive for

MEL
132

PART 4

INTRODUCING MAYA GEMS | 16


Point Explosion
// and the fraction of the full explosion for that time. // Make the explosion intensity a curve instead of // linear interpolation for the explosion fraction. // BEWARE of MAGIC NUMBERS!!!! // expression -ae true -s " Explosion.rate = Explosion.Fullness * 40 * Explosion.InternalIntensity; ExplosionParticleShape.multiRadius = Explosion.Fullness * Explosion.Intensity * 0.005; Explosion.speed = Explosion.InternalIntensity * Explosion.Power / 10.0; "; expression -ae true -s " if (frame >= Explosion.Start && frame <= Explosion.Start + Explosion.Duration) { float $ExplosionLife = frame - Explosion.Start; float $ExplosionFraction = 1 - (abs($ExplosionLife Explosion.Duration/2) / (Explosion.Duration/2)); Explosion.InternalIntensity = Explosion.Intensity * pow($ExplosionFraction, 121 / pow(Explosion.Power + 1, 2)); } else { Explosion.InternalIntensity = 0; }; " -o Explosion; // Set up the playback options. // float $frames = 70; playbackOptions -min 1 -max $frames -loop once; // Time how long it takes to play the scene and then determine the // playback frame rate. Make sure when getting the frame rate // that no values are divided by zero. // float $startTime = timerX; play -wait; float $elapsed = timerX -st $startTime; float $fps = ($elapsed == 0.0 ? 0.0 : $frames/$elapsed); // Print the frames per second (fps) of the subtest in the form X.X. // print("dynFuncExplosion: Done. ("); print((int)($fps * 10)/10.0 + " fps)\n"); } // dynFuncExplosion //

\ \ \ \ \ \

\ \ \ \ \ \ \ \ \ \ \ \ \ \

MAYA GEMS

MEL
133

INTRODUCING MAYA GEMS | 16


Testing Added Particle Attributes

TESTING ADDED PARTICLE ATTRIBUTES


By Ramsey Harris Alias|Wavefront Santa Barbara Development Center This script, dynTestAddAttr.mel, tests dynamics. It keyframes an added attribute called tailSize and adds it to a particle shape. The particles are emitted by a simple point emitter.

dynTestAddAttr.mel
// // // // // // // // // // // // // // // // // // // // // // // // // // dynTestAddAttr.mel Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK

Creation Date: Author:

31 May 1996; Modified 08 January 2000 rh

Procedure Name: dynTestAddAttr Description: Test adding user attributes to a particle shape. Create a particle object, set its render type to streak, and add a dynamic attribute "tailSize". The streak render plug-in will use the attribute "tailSize" if it is available. Input Arguments: None. Return Value: Number of errors that occurred in the test.

// // ========== dynTestAddAttr ========== // // SYNOPSIS // Test adding user attributes to a particle shape. // Create a particle object, set its render type to // streak, and add a dynamic attribute "tailSize". // The streak render plug-in will use the attribute // "tailSize" if it is available. // global proc int dynTestAddAttr() { // First delete anything that might be left over // from a previous test. //

MEL
134

PART 4

INTRODUCING MAYA GEMS | 16


Testing Added Particle Attributes
file -force -new; currentTime -e 1; // Create emitter and particle object. // emitter -type omni -r 90 -mnd 0 -mxd 0.5 -spd 5 -pos 2 0 2 -n myEmitter; particle -n myParticle; connectDynamic -em myEmitter myParticle; // Set the render mode to streak and add a dynamic // attribute for the tail size. // setAttr myParticleShape.particleRenderType 6; // Streak addAttr -ln tailSize -dv 4 myParticleShape; // Set some // setKeyframe setKeyframe setKeyframe setKeyframe setKeyframe setKeyframe setKeyframe setKeyframe keyframes on the dynamic attribute. -t -t -t -t -t -t -t -t 0 -v 0 -at tailSize myParticleShape; 10 -v 1 -at tailSize myParticleShape; 20 -v 2 -at tailSize myParticleShape; 30 -v 5 -at tailSize myParticleShape; 50 -v 10 -at tailSize myParticleShape; 70 -v 5 -at tailSize myParticleShape; 90 -v 1 -at tailSize myParticleShape; 100 -v 0 -at tailSize myParticleShape;

// Check for correct tail size at start of test. // // currentTime -e 0; int $errors = 0; float $tailSize = getAttr myParticle.tailSize; if ( $tailSize != 0 ) // Warning Magic# { print( "dynTestAddAttr: Failure: Start of test: The tail " + "size ("+ $tailSize + ") should be 0.\n" ); $errors += 1; } // Set up the playback options. // float $frames = 50; playbackOptions -min 1 -max $frames -loop once; // Time how long it takes to play the scene and then determine the // playback frame rate. Make sure when getting the frame rate // that no values are divided by zero. // float $startTime = timerX; play -wait; float $elapsed = timerX -st $startTime; float $fps = ($elapsed == 0.0 ? 0.0 : $frames/$elapsed); // Check for correct tail size at middle of test. // $tailSize = getAttr myParticle.tailSize; if ( ($tailSize < 9.9) || ($tailSize > 10.1) ) // Warning Magic# {

MAYA GEMS

MEL
135

INTRODUCING MAYA GEMS | 16


Testing Added Particle Attributes
print( "dynTestAddAttr: Failure: Frame 50: The tail size (" + $tailSize + ") should be about 10.\n" ); $errors += 1; } // Print the frames per second (fps) in the form X.X of subtest. // print( "dynTestAddAttr: Subtest 1. (" + (int)($fps * 10)/10.0 + " fps)\n"); // Set up the playback options. // $frames = 100; playbackOptions -min 1 -max $frames -loop once; currentTime -e 1; // Time how long it takes to play the scene and then determine the // playback frame rate. Make sure when getting the frame rate // that no values are divided by zero. // $startTime = timerX; play -wait; $elapsed = timerX -st $startTime; $fps = ($elapsed == 0.0 ? 0.0 : $frames/$elapsed); // Check for correct tail size at end of test. // $tailSize = getAttr myParticle.tailSize; if ( $tailSize > 0.1 ) { print( "dynTestAddAttr: Failure: End of test: The " + "tail size (" + $tailSize + ") should be close to 0.\n"); $errors += 1; } // If there are no errors, the addAttr passed this test. // if ( $errors == 0 ) print( "dynTestAddAttr: Passed. (" ); else print( "dynTestAddAttr: Failed. (" ); // Print the frames per second (fps) in the form X.X. // print((int)($fps * 10)/10.0 + " fps)\n"); // Reset the current time to zero so user can replay the test. // currentTime -e 1; return $errors; } // dynTestAddAttr //

MEL
136

PART 4

INTRODUCING MAYA GEMS | 16


Testing Dynamics Events

TESTING DYNAMICS EVENTS


Rob Tesdahl and Jonathan Southard Alias|Wavefront Santa Barbara Development Center This script, dynTestEvent.mel, tests the functionality of particles and particle collision events. It creates two emitters over a tilted plane. The particles emitted are affected by gravity as they collide with the tilted plane. Upon collision the particles either split or emit, depending on which emitter they came from.

dynTestEvent.mel
// // // // // // // // // // // // // // // // // // // // // // dynTestEvent.mel Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK

Creation Date: Author: Procedure Name: dynTestEvent

4 September 1996; Modified 09 January 2000 robt, js

Description: Test the basic functionality of collision events. Input Arguments: None. Return Value: Number of errors that occurred in the test.

// // ========== dynTestEvent ========== // // SYNOPSIS // Test the basic functionality of collision events. // global proc int dynTestEvent() { // First delete anything that might be left over // from a previous test. // file -force -new; currentTime -e 1; int $errors = 0; // Create the planes to bounce off. // nurbsPlane -d 3 -p 0 0 0 -w 1.5cm -lr 1 -axis 0cm 0cm 0cm

MAYA GEMS

MEL
137

INTRODUCING MAYA GEMS | 16


Testing Dynamics Events
-name table; scale 10 10 10; rotate -1.5708rad 0rad 0rad; move -os 0.5 0.5 0; move -r -5 0 5; rotate -r 10 0 0; // Create the particle shapes to do the bouncing and splitting. // Material assignments will be interesting only if the lighting is // set. // particle -inherit 1.0 -p 0 5 -3 -n blueParticles; addAttr -ln colorBlue -dv 1.0 -at double blueParticlesShape; particle -inherit 1.0 -p 0 5 -3.5 -n redParticles; addAttr -ln colorRed -dv 1.0 -at double redParticlesShape; particle -inherit 1.0 -p 0 5 -3.5 -n greenParticles; addAttr -ln colorGreen -dv 1.0 -at double redParticlesShape; gravity -pos 10 10 10 -m 20 -name gravityField; // Warning: Changing resilience will change the (hardcoded) // number of particles that this test expects to create. // collision -r 1.0 -f 0.01 table; connectDynamic -f gravityField -c table blueParticles redParticles greenParticles; event -split 2 -sp 0.2 blueParticles; event -emit 3 -die true -sp 0.2 redParticles; event -emit 1 greenParticles; // Set up the playback options. // float $frames = 55; playbackOptions -min 1 -max $frames -loop once; // Time how long it takes to play the scene and then determine the // playback frame rate. Make sure when getting the frame rate // that no values are divided by zero. // float $startTime = timerX; play -wait; float $elapsed = timerX -st $startTime; float $fps = ($elapsed == 0.0 ? 0.0 : $frames/$elapsed); // Check whether any blue particles went through the boundary. // if ( getAttr blueParticles.boundingBoxMinZ < getAttr table.boundingBoxMinZ ) { print( "dynTestEvent: Failure: \"blueParticles\" particles " + "went through boundary.\n" ); $errors += 1; } // Check whether any red particles went through the boundary. //

MEL
138

PART 4

INTRODUCING MAYA GEMS | 16


Testing Dynamics Events
if ( getAttr redParticles.boundingBoxMinZ < getAttr table.boundingBoxMinZ ) { print( "dynTestEvent: Failure: \"redParticles\" particles " + "went through boundary.\n" ); $errors += 1; } // Make sure that the blue particle hit one Z wall, creating two // particles that each hit the other Z wall to create four total particles. // This is visually apparent from the side and front views together. // int $blueParticles_i = particle -count -q blueParticles; if ( $blueParticles_i != 4 && ! $errors ) // Warning Magic# { print( "dynTestEvent: Failure: There are " + $blueParticles_i + " \"blueParticles\" particles instead of the correct " + "value, 4.\n" ); $errors += 1; } // Test that the number of events resulting in a red particle // creation is correct. // int $redParticles_i = particle -count -q redParticles; if ( $redParticles_i != 9 && ! $errors ) // Warning Magic# { print( "dynTestEvent: Failure: There are " + $redParticles_i + " \"redParticles\" particles instead of the correct " + "value, 9.\n" ); $errors += 1; } // Check the totalEventCount variable. // if ((getAttr redParticles.totalEventCount != 4) || (getAttr blueParticles.totalEventCount != 3)) { print( "dynTestEvent: Failure: Event count attributes had " + "incorrect value(s).\n" ); $errors += 1; } // Check the event attribute on the green particles. // float $event[] = particle -at event -order 0 -q greenParticlesShape; if ($event[0] != 2) { print( "dynTestEvent: Failure: Event attribute had incorrect" + "value(s).\n" ); $errors += 1; } // If there are no errors, the events passed this test. // if ( $errors == 0 ) { print( "dynTestEvent: Passed. (" ); }

MAYA GEMS

MEL
139

INTRODUCING MAYA GEMS | 16


Dynamics Time Playback
else { print( "dynTestEvent: } // Print the frames per second (fps) in the form X.X. // print( (int)($fps * 10)/10.0 + " fps)\n" ); // Reset the current time to zero so user can replay the test. // currentTime -e 1; return $errors; } // dynTestEvent // Failed. (" );

DYNAMICS TIME PLAYBACK


Ramsey Harris Alias|Wavefront Santa Barbara Development Center This script, dynTimePlayback.mel,determines the dynamics playback rate in frames/ second from frame 0 to a frame you specify.

dynTimePlayback.mel
// // // // // // // // // // // // // // // // // // // Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK Creation Date: Author: Description: Playback from frame 0 to frame <n> and return the the playback rate in frames/sec. If a negative frame count is given, this indicates silent mode. In silent mode, no output is printed. This version is intended for use in batch tests of dynamics. It requests particle and rigid body positions every frame. RETURN Frame rate in frames/sec 8 May 1996 rh

global proc float dynTimePlayback( float $frames ) { int $silent; // Get the list of particle shapes. // string $particleObjects[] = ls -type particle;

MEL
140

PART 4

INTRODUCING MAYA GEMS | 16


Dynamics Time Playback
int $particleCount = size( $particleObjects ); // Get the list of transforms. // This will include rigid bodies. // string $transforms[] = ls -tr; int $trCount = size( $transforms ); // Check for negative $frames. This indicates // $silent mode. // if ($frames < 0) { $silent = 1; $frames = -$frames; } else { $silent = 0; }

// Setup the playback options. // playbackOptions -min 1 -max $frames -loop "once"; currentTime -edit 0;

// Playback the animation using the timerX command // to compute the $elapsed time. // float $startTime, $elapsed; $startTime = timerX; play -wait; int $i; for ($i = 1; $i < $frames; $i++ ) { // Set time // currentTime -e $i; int $obj; // Request count for every particle object. // for ($obj = 0; $obj < $particleCount; $obj++) { string $cmd = "getAttr " + $particleObjects[$obj]+".count"; eval( $cmd ); } // Request position for every transform // (includes every rigid body). // for ($obj = 0; $obj < $trCount; $obj++) { string $cmd = "getAttr " + $transforms[$obj]+".translate"; eval ($cmd);

//

MAYA GEMS

MEL
141

INTRODUCING MAYA GEMS | 16


Finding Unshaded Objects
} } $elapsed = timerX -st $startTime;

// Compute the playback frame $rate. Print results. // float $rate = ($elapsed == 0 ? 0.0 : $frames / $elapsed) ; if ( ! $silent) { print( "Playback time: " + $elapsed + " secs\n" ); print( "Playback $rate: " + $rate + " $frames/sec\n" ); } return ( $rate ); } // timePlayback //

FINDING UNSHADED OBJECTS


John R. Gross Alias|Wavefront Toronto Development Center In the course of a complex production, its possible that objects can get accidentally disconnected from their shaders. This script, findUnshadedObjects.mel, finds any unshaded objects, which can help you identify objects that have been accidentally disconnected from their shaders.

findUnshadedObjects.mel
// // // // // // // // // // // // // // // // // // // // // Copyright (C) 1997-1998 Alias|Wavefront, a division of Silicon Graphics Limited. The information in this file is provided for the exclusive use of the licensees of Alias|Wavefront. Such users have the right to use, modify, and incorporate this code into other products for purposes authorized by the Alias|Wavefront license agreement, without fee. ALIAS|WAVEFRONT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ALIAS|WAVEFRONT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK Creation Date: 5/August/98

MEL
142

PART 4

INTRODUCING MAYA GEMS | 16


Finding Unshaded Objects
// // Author: jrg // // Procedure Name: // findUnshadedObjects // // Description: // This procedure examines all geometry in the scene, and reports any // that are not connected to any shading group. It returns the number of // such unconnected objects that were found. // It also reports (but does not include in the reported count) any objects // that are connected to multiple shaders. // global proc int findUnshadedObjects() { string $listOfShapes[] = ls -geometry; int $numShapes = size($listOfShapes); int $whichShape; string $shapeType[]; string $shaders[]; int $numShaders; int $numUnshaded = 0; for ($whichShape = 0; $whichShape < $numShapes; $whichShape++) { $shapeType = ls -showType $listOfShapes[$whichShape]; // // Skip over curves, as they are not rendered anyway. // if ($shapeType[1] == "nurbsCurve") { continue; } // // Get a list of all shading engines connected downstream // from this geometry. // $shaders = listConnections -source true -type shadingEngine $listOfShapes[$whichShape]; $numShaders = size($shaders); if ($numShaders == 0) { print("Object " + $listOfShapes[$whichShape] + "is not connected to any shading engine.\n" + "It will not show up when rendered.\n"); $numUnshaded++; } else if ($numShaders > 1) { print("Object " + $listOfShapes[$whichShape] + "is connected to " + $numShaders + "shading engines.\n"); } } return $numUnshaded; }

MAYA GEMS

MEL
143

INTRODUCING MAYA GEMS | 16


Finding Unshaded Objects

MEL
144

PART 4

INDEX
Symbols
! 62 - 58 != 63 % 58 && 62 * 58 + 58 / 58 < 63 <= 63 == 63 > 63 >= 63 ^ 58 || 62 conditional statements 68 break 71 default label 72 else 69 else-if 70 if 69 loops 72 switch 70 constants 52 continue statements 76 converting data types 52 cross product 59 custom interface creation 81 customizing Maya saving preferences 26

G
ANIMATION
MEL 145
global procedures 102 global variables 50, 101 grouping operations 65, 67 variable visibility 68

H
hotkeys 25

I
if statements 69 implicit declaration 44 increment operators 61

D
data type conversion 52 data types maximum size 55 precision 55 declaring procedures 79, 80 variables 44 decrement operators 61 default label statements 72 dot product 59 do-while statements 74

A
arithmetic operators 58 floats 58 integers 58 strings 59 vectors 59 arrays 46 assigning values 46 size 46 assigning variables 44 assignment operators 57 chained assignment 58 shortcuts 60 value 57

L
left-hand single quotes 22 local array variables 112 local variables 50 logical operators 62 loop statements 72 break 77 continue 76 do-while 74 for 74 for-in 75 while 73

E
echoing 35 else statements 69 else-if statements 70 eval command 22 executing commands 21 procedures 80 explicit declaration 44

M
magic numbers 101 matrices 47, 60 adding and subtracting 60 MEL documentation 14 examining Maya execution scripts 32 modulus operator 58

B
Boolean constants 52 break statements 71, 77

C
chained assignment 58 comments 100 single line 100 variable line 100 comparison operators 62 evaluated as integers 64 conditional operator 64

F
files length 102 for statements 74 for-in statements 75 freeing local variables 112 functions declaring 80

O
object attributes 48 data types 49 path name 48 operator precedence 65

INDEX

operators arithmetic 58 assignment 57 comparison 62 conditional 64 decrement 61 increment 61 logical 62 relational 63 shortcuts 61

single line comment 100 strings 45 switch statements 70

U
userSetup.mel 26

V
variable line comment 100 variables 43 declaring 44 global 50, 101 in grouping 68 in scripts 100 local 50 local array 112 naming 43, 101 range wrap-around 55 types 43 vectors 45, 59

P
preferences saving 26 procedures 102 declaring 79 executing 80 global 102 in scripts 32 length 102

R
range wrap-around 55 relational operators 63 reserved words 44

W
while statements 73 white space 99

S
Script Editor button 33 script nodes 39 attributes 39 creating 39 deleting 41 editing 41 setting execution 41 specifying an editor 41 testing scripts 40 scripts 80, 102 bullet-proofing 102 defined 80 errors 102 length 102 paths 31 procedures in 32 storing in scene files 39 shelf icons 25 shortcut operators 61 incrementing and decrementing 61

MEL 146

You might also like