### A06   SIMPLE EXPRESSIONS CONTENTS

What is a MEL Expression?
Expression Components.
An Example of a Simple Gear Pair.
A Clockwork.
Using a Simple Function.
A Variable Speed Control.

### A06   SIMPLE EXPRESSIONS

Using expressions in Maya can be advantageous to most Maya users and you can increase complexity and functionality of your work by using them.  This is a reasonably simple introduction to MEL expressions and should make your life as animator a whole lot easier.   This exercise in clockwork is one of those circumstances that really does warrant expressions to make the choreography of the scene really efficient.   The idea is that if we can set up the correct mechanical relationship between all these clockwork parts then we will be able to start up, speed up, slow down, reverse and stop all from one single animation curve (or channel) without having to worry about each separate component.

What is a MEL Expression?

An expression usually takes the form of a simple assignment:-
pCube2.rotateY = pCube1.rotateY;
This simple line of code when entered into the expression editor is the same as making a direct connection between Cube2 and Cube1's Y channel. You can describe this assignment as:-
The pCube2's rotation in the y axis will equal the pCube1's rotation in the y axis.   Therefore pCube2's orientation in the y axis will be the same as, or governed by, pCube1's orientation in the y axis.   The assignment is finished off with a semicolon.

Here is another example:-
pCube2.rotateY = pCube1.translateY * 10;
You can describe this assignment as:-
The pCube2's rotation in the y axis will equal the pCube1's translation in the y axis but times 10.   Therefore pCube2's orientation in the y axis will be the same as, or governed by pCube1's position in the y axis but multiplied by ten.   The assignment is finished off with a semicolon.

Here is another example of three assignments:-
pCube2.rotateX = pCube1.rotateX;
pCube2.rotateY = pCube1.rotateY;
pCube2.rotateZ = pCube1.rotateZ;
You can describe these assignments as:-
The pCube2's rotations will be equal to pCube1's rotations.   Therefore pCube2's orientation will be the same as, or governed by pCube1's orientation.

Expression Components

Within an expession Maya objects are defined by their name. Examples are:-
pCube1
pCylinder1
myDog
nurbsSphere1

Their channels (attributes) are defined by the attribute name which is separated from the object name by a dot (full stop or period).   Examples of pCube1's attributes are:-
pCube1.translateX
pCube1.translateY
pCube1.translateZ
pCube1.rotateX
pCube1.rotateY
pCube1.rotateZ
pCube1.scaleX
pCube1.scaleY
pCube1.scaleZ
pCube1.visibility

You could even have your own attributes like:-
pCube1.rattle
pCube1.drive

Within an expression their is only one object and attribute allowed on the left side of the assignment operator.   An examples is:-
myDog.translateZ = 0;
but you can have a string of assignments in the same expression:-
pCube1.translateX = pCube1.translateY = pCube1.translateZ = 0;
The expression above sets all the translate channels of pCube1 to zero;
I don't recommend this if your just starting out.   Keep it simple and keep each assignment on a separate and new line as follows:-
pCube1.translateX = 0;
pCube1.translateY = 0;
pCube1.translateZ = 0;
The assignment operator itself is the equals sign (=) which is the only assignment operator we will using in this exercise but there are others.   Their can be any number of object attributes and operators on the right hand side of the assignment operator but let us try and keep it simple to save confusion.
Examples could be:-
pCube1.rotateX = 0;
pCube1.rotateX = 2 + 3;
pCube1.rotateX = (pCylinder1.rotateY * 3) +15;
pCube1.rotateX = (pCylinder1.rotateY * 3) + (pCylinder2.rotateZ * 5);
Each expression need not be on a new line but for clarity I suggest that you do.
Each expression must be terminated with a semi colon (;)

You can use brackets to make sure the calculations are done in the order that you require.
An example might be pCube1.rotateX = 3 * 2 + 5;   This would yield a final calculation of 11.
However, pCube1.rotateX = 3 * (2 + 5); would yield a final calculation of 30.

You can use "//" (two forward slashes) to comment out lines of code or for leaving remarks.
Example might be:-
// These following three expressions set my cube translations to zero but this line of text has no effect
pCube1.translateX = 0;
pCube1.translateY = 0;
pCube1.translateZ = 0;

Create a Poly Cylinder in the Y axis with the following parameters.
Radius 1, Height 0.5, Subdivisions Axis 12, Subdivisions Height 1, Subdivisions Caps 0.

Pick alternate faces around the circumference and extrude local to:-
Local Translate Z = 0.5
Local Scale X = 0.5

Rename the Cylinder to “Cog_1”

Create a Poly Cylinder in the Y axis with the following parameters.
Radius 2, Height 0.5, Subdivisions Axis 24, Subdivisions Height 1, Subdivisions Caps 0.

Position at TranslateZ 3.5

Pick alternate faces around the circumference and extrude local to:-
Local Translate Z = 0.5
Local Scale X = 0.5

Rename this Cylinder to “Cog_2”

Main Menu bar/Modify/Freeze Transformations of Cog_2

If the teeth of the cogs are miss aligned we can correct this in the expression later.
Select cog_1 and Key at frame 0, RotateY value 0.
Select cog_1 and Key at frame 50, RotateY value 360.
Make sure the rotate Y curve is straight by having linear keys.
Set the time to run between frame 1 and frame 50 and test the rotation of cog_1.

Now write an expression using each of the expressions below in turn.
// Cog_2 will turn at the same rate as Cog_1 divided by 2. (or half the speed of Cog_1)
Cog_2.ry = Cog_1.ry / 2;

// By making the 2 a minus 2, Cog_2 will turn in the opposite direction of Cog_1
Cog_2.ry = Cog_1.ry / -2;

// Your cogs may already be meshed but if they are not then add a 15 degrees offset to the formula.
Cog_2.ry = (Cog_1.ry / -2) + 15;

Although it wouldn't make any difference to this expression it is good practice to use brackets to force the division to be calculated first.

A Clockwork
THE BRIEF
A Clockwork.

Artistic Elements Covered: Scene Fabrication & Camerawork
Technical Elements Covered: Using Expressions

Scene file "Clockwork".     Sequence Duration 8 to 10 seconds

Position the spare gears shafts in the scene to implement a mechanical relationship with the pre animated handle and write mel expressions to animate these gears shafts meaningfully.   When complete, use mel expressions coupled with a library function, to express wear and tear.

Load the Maya scene file and build a mechanism using the parts provided.   You can duplicate some or all of these parts if you are confident that you can write expressions for them all.
When you have loaded scene and found the expression editor, you will see that the first expression headed “// Turn the next gear set“ has been written for you.   Arrange the parts and write an expression for each of the other components so that the mechanism operates in a mechanically correct way.

float \$turn = frame * 10;

// Turn Handle *******************************************
Start_P8.rotateX = \$turn;

// Turn next gear set ************************************
set_A_12_12_1.rotateY = (Start_P8.rotateX * 8 / 12) + 15.0;

The functionality of the code above follows.
float \$turn = frame * 10;
This declares a floating point variable called \$turn which is assigned the value of frame multiplied by ten.   “frame” is a special variable which contains the frame number from the current position of the time line cursor.

Start_P8.rotateX = \$turn;
This assigns the value of the Variable \$turn into the X rotation of Start_P8 (the handle part of the mechanism).
set_A_12_12_1.rotateY = (Start_P8.rotateX * 8 / 12) + 15.0;
This connects the next piece of the mechanism.
set_A_12_12_1's Y rotation is governed by Start_P8's X rotation but to a ratio of 8/12 (equivalent to * 0.66666r), plus an offset of 15 degrees so that the teeth mesh.

Carry on until all the parts are operational.

Using your completed clockwork scene file, we will introduce a noise function to represent wear and tear of the mechanism.
Functions are very useful and it is possible to write your own but for this example we will use one which already exists in the Maya software and which is relatively simple to use.
Take a look at the text below and type this in to the script editor MEL input field:-

noise(1.0);

Highlight the text and then press enter to run the code.   You should get the following result in the upper output field of the script editor:-

// Result: 0.759318 //

Noise is a function that requires just one floating point argument which is placed within brackets after the function name.   Using the argument, which in this case is 1.0, the noise function will calculate a single random floating point number.
Now type this in to the script editor MEL input field:-

noise(2.0);

Highlight the text and then press enter to run the code.   You should get the following result:-

// Result: -0.348634 //

If you were to re-enter an argument of 1.0 to the noise function then it would return a consistent value of 0.759318.   This means that although the noise function produces a different random value for every different value of argument, it is consistent in the results that are generated.   An argument of 1.0 will always generate an output of 0.759318 and an argument of 2.0 will always generate an output of -0.348634

In a fresh scene create a polygon cube.
In the expression editor enter the following expression:-

pCube1.translateY = noise (frame);

Play back the animation over 200 frames and you should see the poly cube moving randomly in the y direction.
To amplify the movement by a factor of three, alter the expression to:-
pCube1.translateY = noise (frame) * 3.0;

This effectively takes the result generated by the noise function and multiplies it by 3.0.
To slow the frequency of the movement by a factor of four then alter the expression to:-
pCube1.translateY = noise (frame / 4.0);
//OR
pCube1.translateY = noise (frame * 0.25);

This effectively takes the variable called frame and divides it by 4 (OR multiplies it by 0.25) before it is passed as an argument to the noise function.
To do adjustments to both amplitude and frequency then alter the expression to:-
pCube1.translateY = noise (frame * 0.25) * 3.0;

To visualize the output curve then select pCube1 and go the the graph editor and from it's menu bar select View / Show Results.

If you return to your finished clockwork scene file then you can implement a vibration for the set_A_12_12_1 component by writing the following in the expression editor.

set_A_12_12_1 = noise (frame * 0.25) * 3.0;
Before you implement this for all your clockwork components, it would be a good idea to make the amplitude (currently 3.0) a variable which can be key framed.
Create a NURBS circle and rename it “control”.
Add a floating point attribute called “rattle”.
Set key of the rattle channel to 0.0 at frame 50 then set key to 3.0 at frame 150.

set_A_12_12_1.rotate.Z = noise(frame * 0.25) * control.rattle;

When you play the animation now, you should find that the vibration of this component slowly builds up between frames 50 and 150.
Before you implement this for all your clockwork components we need to make a couple of alterations to make the animation more flexible later on.
Enter this line of code above the existing “set_A_12_12_1.rotate.Z = noise(frame * 0.25) * control.rattle;” in the expression editor.
float \$turn_R = frame * 0.25;

Now change the next existing line below to:-
set_A_12_12_1.rotate.Z = noise(\$turn_R) * control.rattle;

This is how the code should look:-
float \$turn_R = frame * 0.25;
set_A_12_12_1.rotate.Z = noise(\$turn_R) * control.rattle;

Make sure the vibration still works by running your animation again.   You can now implement this expression for all the rest of the clockwork components.

A Variable Speed Control
A further extension to this project is to control of the speed of the mechanism so that we can animate it starting, stopping, speeding up, slowing down or even reversing.

There are two ways of implementing this. Method one is to drive the mechanism directly from a single channel (an additional attribute to “control” named “drive”) which replaces the use of the global variable “frame”.
Method two, is to continue to use the global variable “frame” but to control the speed by adding a single
channel (an additional attribute to “control” named “speed”) which attenuates the variable “frame” value. Method 1: Adding a Drive Channel.
Select your NURBS curve “control” and add a floating point attribute called “drive”.
Key the “drive” channel value of “control” to zero at frame 1 of the time line.
Key the “drive” channel value of “control” to 200 at frame 200 of the time line.
Make sure both these keys have linear tangents.

Change these lines of Mel in the expression editor:-

float \$turn = frame * 10;
float \$turn_R = frame * 0.25;
to:-
float \$turn = control.drive * 10;
float \$turn_R = control.drive * 0.25;

Test the animation.   It should look the same as when you last tried it.
Now select “control” and in the graph editor, change keys of the “drive” curve to flat.
When you test the animation again, the animation should start off slowly, speed up and come to a gradual standstill at frame 200.   Adding and adjusting the keys of this curve enables you control overall speed and activity of the mechanism.

Method 2: Adding a Speed Channel.
Select your NURBS curve “control” and add a floating point attribute called “speed”.
Key the “speed” channel value of “control” to zero at frame 1 of the time line.
Key the “speed” channel value of “control” to 1 at frame 25 of the time line.
Key the “speed” channel value of “control” to 1 at frame 100 of the time line.
Key the “speed” channel value of “control” to zero at frame 125 of the time line.
Make sure all these keys have flat tangents.

Change these lines of Melin the expression editor:-

float \$turn = frame * 10;
float \$turn_R = frame * 0.25;
to:-
float \$turn = frame * 10 * control.speed;
float \$turn_R = frame * 0.25 * control.speed;
Test the animation.   The mechanism should start slowly over one second and then remain constant for three seconds and slow down to a stop over one second.

This site and all the learning materials are the copyright of Henry Lutman.   The sole purpose of the site and downloads are to aid the teaching of 3D Computer Animation and related topics.   Please do not reproduce any of the content of this site, or any of the downloads for purposes other than to use as a guide to learning, without the written permission of Henry Lutman.
Web Site Author: Henry Lutman.     Web Site Editor: Martin Capey