|

Introduction to
MEL
In this lesson we are going to look at Maya's Embedded Langauge or MEL
and how we can use it as productivity tool. Unlike most other scripting
languages MEL is very easy to understand and implement.
If you can do it manually in Maya, you can
create a MEL script to do it automatically.
To introduce MEL we are going to create a script that automates the
creation of an FK handle for an existing joint.
Revision of FK Setup
|
We will create an FK handle for an existing
joint, such as that need for an FK arm.
So that we can apply this later to a MEL script
we will carefully note all the steps and conditions involved in the
creation of each FK handle.
Step 1: Create a controller
(Typically a NURBS circle) and point snap it to the joint in
question and freeze its transformations.
Step 2: Orient the controller
such that its local orientation axes line up with that of the joint
we wish to control
Step 3: Orient constrain the
joint to the controller
Step 4: Group the controller
to itself and move the pivot of the group to the joint's parent
joint (if it has one)
Step 5: Point and Orient
constrain the group to the joint's parent |
 |
To start with lets have a look at how Maya performs these actions using
MEL. If we open the script editor whilst working we can record which MEL
commands are required to perform each of the above tasks.
If we were to perform all these actions on the arm hierarchy shown
above we would see the following script.
|
circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3
-ut 0 -tol 0.01 -s 8 -ch 1; objectMoveCommand; rename "group3"
"Shoulder_GRP"; move -rpr 2.656576
7.581287 -1.171452 ; makeIdentity -apply true -t 1 -r 1 -s 1;
|
Step
1 |
rotate -r -os 0 0 -90
; select -r Shoulder_Joint ; select -tgl nurbsCircle2
; orientConstraint -offset 0 0 0 -weight 1; select -r
nurbsCircle2_orientConstraint1 ; delete; |
Step
2 |
select -r nurbsCircle2
; select -tgl Shoulder_Joint ; orientConstraint -offset 0 0 0
-weight 1; |
Step
3 |
select -r nurbsCircle2
; group; xform -os -piv 0 0 0; move -rpr 1.438862 7.581287
-0.527456 ; |
Step
4 |
|
select -r Clavicle_Joint ; select -add
Shoulder_GRP ; pointConstraint -offset 0 0 0 -weight
1; orientConstraint -mo -weight 1;
|
Step
5 |
From this we can see straight away that the process for repeating
exactly the steps for creating an FK controller are not that complex, but
what is important to notice is that there are several points in the code
that refer to specific objects such as the nurbsCircle2,
group3, or Shoulder_Joint.
Logical Exceptions
|
Before we can try to decipher the code above
effectively we need to be able to devise a logical flow of events
and possible scenarios that we may encounter in the creation of FK
controllers.
The first case would
be if there is no joint selected (either nothing or the object
selected is not a joint).
The second case
would be if the joint has no parent. If this is the case then we
cannot create an FK controller and we will have to advise the user
accordingly. Both exceptions will result in the prevention of the
script executing.
First lets check to see if something at all is
selected.
The MEL command ls -sl (list
command with the selected only flag) will return an array containing
a list of all the nodes currently selected. We start by creating a
string array to accept the list and then ask Maya what nodes are
currently selected.
string
$nodes[]; $nodes = `ls -sl`;
Next we need to perform a check to make sure
that only one object is selected.
if(size($nodes)==1) .........{ .........Statements if TRUE .........{ else .........{ .........//Statements if FALSE .........print("Please select ONE
joint); .........{
So how do we check so see if a joint is
selected.
The MEL command objectType
can be used to determine the type of object that has
been selected, so the following command can be used to check if the
current selection is actually a joint
if(size($nodes)==1) .........{ .........if(objectType -isType
"joint" $nodes[0]) ..................{ ..................Statements if TRUE ..................{ .........else
..................{ ..................//Statements if FALSE ..................print("The selection is not a
joint"); ..................{ .........} else
.........{ .........print("Please select ONE joint); .........{
The next thing to check before we continue is
to check to see if the selected joint is a child (ie it has at least
one parent joint). We can do this using the listRelatives command
(with the -p flag which returns only the direct parent of the
selected object);
string
$nodeParent[]; $nodeParent = `listRelatives -p
$nodes[0]`; if(size($nodeParent)==1) .........{ .........Statements if TRUE .........{ else .........{ .........//Statements if FALSE .........print("The joint selected must have a
parent joint); .........{
|
 |
So now our whole exception statement looks like this
string $nodes[]; $nodes = `ls
-sl`; if(size($nodes)==1) .........{ .........$currentJoint = $nodes[0]; .........if(objectType -isType "joint"
$nodes[0]) ..................{ ..................string
$nodeParent[]; ..................$nodeParent =
`listRelatives -p $nodes[0]`; ..................if(size($nodeParent)==1) ..........................{ ..........................Statements if TRUE ..........................{ ..................else ..........................{ ..........................print("The joint selected must have a parent
joint); ..........................{ ..................{ .........else ..................{ ..................print("The
selection is not a joint"); ..................{ .........} else
.........{ .........print("Please select ONE joint); .........{
Now that we are sure that we are dealing with a joint and one with the
correct conditions, we can start to follow through the flow of things.
Quite a few of the steps require knowledge of the joint's name.
Remember how I told you a long time ago that naming your joints correctly
is a necessary evil for later scripting... well here is the reason
why.
We want to find out what the "root" of the joint name is, eg. for
Clavicle_joint, "Clavicle" is the root. So how can we extract this from
our current joint name ($nodes[0]). To do this we can use the
tokenize MEL command. Tokenize will look through a string
for a delimiter and split the string up accordingly. Eg. tokenizing
"Clavicle_joint" with a token of "_" gives "Clavicle" and "joint". So we
can find out the root name with the following statements.
string $buffer[]; tokenize $currentJoint[0] "_"
$buffer; $root = $buffer[0]; $jointControl = $root+"_CON";
Now we can use this root anywhere to categorize our
controller with the joint it is created from.
Implementing Step 1
With all this done we can tackle STEP 1. Step 1
consists of four commands 1) Create a
circle 2) Name it 3) Move it to the joint in question 4) Freeze the controller's transformations
To create a circle, we simple use the MEL command
"circle" but we want to be able to create it at the same XYZ coordinates
as the joint. We can query the current joint with the getAttr command to find
out its current translation vector. As the joint is part of a
hierarchy we will have to unparent it first to
reveal its true translation. After the controller is in place we can reparent the joint.
Unparent; float
$jointTranslation[]; $jointTranslation = eval("getAttr
"+$currentJoint+".translate"); eval("circle
-nr 1 0 0 -c "+$jointTranslation[0]+"
"+$jointTranslation[1]+" "+$jointTranslation[2] +" -n "+$jointControl); CenterPivot; parent $nodes[0]
$nodeParent[0]; makeIdentity
-apply true -t 1 -r 1 -s 1;
Now lets compare what we initally got from Maya and
how we have used it to create a more generalised form of code.
| From Maya |
Our customized code |
circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3
-ut 0 -tol 0.01 -s 8 -ch 1; objectMoveCommand; rename "group3"
"Shoulder_GRP"; move -rpr 2.656576 7.581287 -1.171452
; makeIdentity -apply true -t 1 -r 1 -s 1; |
Unparent; float
$jointTranslation[]; $jointTranslation = eval("getAttr
"+$nodes[0]+".translate"); eval("circle -nr 1 0 0 -c
"+$jointTranslation[0]+" "+$jointTranslation[1]+"
"+$jointTranslation[2] +" -n
"+$root+"_GRP"); CenterPivot; parent
$nodes[0] $nodeParent; makeIdentity -apply true -t 1 -r 1 -s 1;
|
Implementing Step
2
Step 2 consists of two steps 1) orienting the
controller to the joint 2) deleting the
orient constraint
With all our organization this becomes quite simply
orientConstraint -offset 0 0 0 -weight 1-n
ConstrainTmp $currentJoint $jointControl; delete ConstrainTmp;
| From Maya |
Our customized code |
rotate -r -os 0 0 -90 ; select -r
Shoulder_Joint ; select -tgl nurbsCircle2 ; orientConstraint
-offset 0 0 0 -weight 1; select -r nurbsCircle2_orientConstraint1
; delete; |
orientConstraint -offset 0
0 0 -weight 1 -n ConstrainTmp $currentJoint
$jointControl; delete
ConstrainTmp; |
Implementing Step
3
Step 2 consists of one step 1) to orient
constrain the joint to the joint controller
With all our organization this becomes quite simply
orientConstraint -mo -weight 1-n $orientName $jointControl
$currentJoint;
| From Maya |
Our customized code |
select -r nurbsCircle2
; select -tgl Shoulder_Joint ; orientConstraint -offset 0 0 0
-weight 1; |
$orientName =
$root+"_orientConstraint"; orientConstraint -mo -weight 1-n
$orientName $jointControl $currentJoint; |
Implementing Step
4
Step 4 consists of one step 1) Group the controller to itself 2)
Rename the group based on the root 3) Move the group's pivot to the
joint's parent
Before we do this we need to find out what the translate coordinates of
the joint's parent are. This raises two possibilities 1) The joint's
parent has its own parent 2) The joint's parent has no parent. If
the joint has a parent we will need to temporarily unparent it. Otherwise
we just steal the coordinates.
..................string
$aboveParents[]; ..................float $controlTranslation[];
..................$aboveParents
= `listRelatives -p $nodeParent`; ..................if(size($nodeParent)==1) ...........................{ ...........................//Then it has a parent
...........................Unparent;.............. ...........................$controlTranslation =
eval("getAttr
"+$nodeParent[0]+".translate"); ...........................parent $nodeParent[0]
$aboveParents[0]; ...........................} ..................else ...........................{ ...........................$controlTranslation =
eval("getAttr
"+$nodeParent[0]+".translate"); ...........................{ ...........................$parentGroup =
$root+"Group"; ...........................group -n $parentGroup $jointControl;
xform -os -piv $controlTranslation[0] $controlTranslation[1]
$controlTranslation[2];
| From Maya |
Our customized code |
select -r
nurbsCircle2 ; group; xform -os -piv 0 0 0; move -rpr 1.438862
7.581287 -0.527456 ; |
string $aboveParents[]; float $controlTranslation[];
$aboveParents = `listRelatives -p
$nodeParent`; if(size($nodeParent)==1) { //Then
it has a parent Unparent;.............. $controlTranslation
= eval("getAttr
"+$nodeParent[0]+".translate"); parent
$nodeParent[0] $aboveParents[0]; } else { $controlTranslation = eval("getAttr
"+$nodeParent[0]+".translate"); { $parentGroup = $root+"Group"; group -n
$parentGroup $jointControl; xform -os
-piv $controlTranslation[0] $controlTranslation[1]
$controlTranslation[2]; |
Implementing Step
5
Finally all that is needed is to point and orient constrain the group
to the joint's parent
$pointParentName =
$root+"_parent_pointConstraint"; $orientParentName =
$root+"_parent_orientConstraint";
orientConstraint -mo
-weight 1-n $orientParentName nodeParent[0]
$parentGroup; pointConstraint -mo -weight
1-n $pointParentName nodeParent[0]
$parentGroup;
| From Maya |
Our customized code |
select -r Clavicle_Joint
; select -add Shoulder_GRP ; pointConstraint -offset 0 0 0
-weight 1; orientConstraint -mo -weight 1; |
$pointParentName =
$root+"_parent_pointConstraint"; $orientParentName =
$root+"_parent_orientConstraint";
orientConstraint -mo
-weight 1-n $orientParentName nodeParent[0] $parentGroup; pointConstraint -mo -weight 1-n $pointParentName nodeParent[0] $parentGroup;
|
Here
is the final MEL script
|