Maya Mel
Maya Mel
Maya Mel
FOR
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.
CONTENTS
USING MAYA: MEL Part 1 Mel and Maya
1 INTRODUCING MEL
13
MEL FEATURES
15
Part 2 Commands
3 INTRODUCING COMMANDS
19
USING COMMANDS
21
Entering commands 21 Using the Command Line 21 Getting command return values 21 Command modes 22 Commands in expressions 23
25
Part 3 Scripting
6 INTRODUCING SCRIPTING
31
MEL 3
CONTENTS
Script files
31 31 32
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
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
43
10
MAKING STATEMENTS
57
CONTENTS
11
FLOW CONTROL
67
12
ABSTRACTING ACTIONS
Procedures 79 Scripts 80
79
13
CREATING INTERFACES
ELF commands UI elements Default parents Naming 90
81
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
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?
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
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
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
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
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.
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
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;
MEL
21
USING COMMANDS | 4
Command modes
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.
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
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;
MEL
25
keyframing an object
setKeyframe -at translate;
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;
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.
MEL
26
PART 2
COMMANDS
MEL
27
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.
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.
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.
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.
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
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
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.
MEL
34
PART 3
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.
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
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.
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.
MEL
36
PART 3
// Error: file: /maya/scripts/level3.mel line3: Cannot link to sassafrass. Check number and types of arguments expected on procedure definition. //
SCRIPTING
MEL
37
MEL
38
PART 3
MEL
39
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
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.
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
SCRIPTING
MEL
41
MEL
42
PART 3
9
VARIABLES
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.
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
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
false in on true
int
float
vector
string
matrix
yes
no
on
off
true
false
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
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>>
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
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");
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
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;
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
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.
Example data 2.6, 7.0, -9.1 -289, 33, 0 on, off, yes, no, 1, 0, true, false
Particle objects, such as the one created above, can additionally have the following attribute data types:
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
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.
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
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
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
<<$i, $i, $i>> <<$f, $f, $f>> perfect if starts with vector or floats with remaining elements 0 perfect
vector
length of vector
MEL
52
PART 3
matrix
none
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
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
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
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.
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
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
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;
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.
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>>
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;
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>>
Expanded Syntax variable = variable + 1; variable = variable - 1; variable = variable + 1; variable = 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:
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
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.
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");
// // // // // //
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.
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 () [] ! ++ - * / % ^
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
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;
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; // }
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");
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");
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"); }
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!");
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);
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.
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
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";
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
5 5
-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
5 5
MEL
86
PART 3
CREATING INTERFACES | 13
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.
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.
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.
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.
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";
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:
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
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.
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
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.
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.
MEL
104
PART 3
FAQS | 15
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;
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.
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.
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.
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.
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.
STRING FAQS
How can I change an integer to a string?
Heres an example:
int $counter = 1; string $bob = "bob"; string $number = $counter;
Note: Just as in C, you have to provide your own newline character to the print function.
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);
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>>;
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.
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.
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 >> //
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 reference a specific element of an matrix just as you would an array element:
$f = $m[1][2]
Alternatively, do this:
$listOfThings=ls; for ($thing in $listOfThings) { foo $thing; }
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.
MEL
114
PART 3
FAQS | 15
Flow control FAQs
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);
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) {
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;
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
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.
SCRIPTING
MEL
117
FAQS | 15
Modeling FAQs
int $visible = getAttr doughnut.visibility; string $type = getAttr -type doughnut.translate;
MODELING FAQS
How can I count polygons?
You can count polygons with the polyEvaluate -f command.
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;
MEL
118
PART 3
FAQS | 15
Animation FAQs
setAttr "polyMoveUV5.translate" -type double2 0 -0.1187236 ;
Then you can connect it to another node using the Connection Editor.
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"); }
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.
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.
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.
SCRIPTING
MEL
121
FAQS | 15
Script path FAQs
np_resetBrowserPrefs; pv_resetWorkspace; pv_goCurrentProject; print ("Current project is trumpet\n");
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.
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.
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.
MEL
123
FAQS | 15
Custom interface FAQs
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.
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.
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.
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.
SCRIPTING
MEL
125
FAQS | 15
Miscellaneous FAQs
MEL
126
PART 3
PART 4
MAYA GEMS
16
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
// // ========== 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
// 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
// // ========== 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
\ \ \ \ \ \
\ \ \ \ \ \ \ \ \ \ \ \ \ \
MAYA GEMS
MEL
133
dynTestAddAttr.mel
// // // // // // // // // // // // // // // // // // // // // // // // // // dynTestAddAttr.mel Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK
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
// 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
MEL
136
PART 4
dynTestEvent.mel
// // // // // // // // // // // // // // // // // // // // // // dynTestEvent.mel Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK
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
MEL
138
PART 4
MAYA GEMS
MEL
139
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
// 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
// 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 //
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
MAYA GEMS
MEL
143
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
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