Unit Conversions In Maya

Contents

Maya supports four distinct types of numerical values: linear values
are used to measure distances and are specified in centimeters, feet, etc;
angular values are used to measure angles and are specified in degrees or
radians; time values are used to measure time and are specified in seconds,
minutes, etc; and dimensionless values are simply values (e.g. float, int,
double) which have no units associated with them.

For any particular attribute, you can determine the type of value that
it contains by using the getAttr -type command:

Command

Result

getAttr -type sphere1.translateX

doubleLinear

getAttr -type sphere1.rotateY

doubleAngle

getAttr -type time1.outTime

time

getAttr -type sphere1.scaleZ

double

Maya allows you to set your preferred units for the first three types
of values, either through the Options->General Preferences->Units window,
or using the currentUnit command. Thus, you can set your preferred
linear units to be feet, your preferred angular units to be radians, and
your preferred time units to be minutes.

No matter what you set your preferred units to, Maya will continue to
store values in its internal units, which are as follows:

Value Type

Maya Internal Units

linear

centimeters

angle

radians

time

0.00166667 seconds (6,000fps)

dimensionless

None

So, if Maya always stores values in its internal units, then what does
it mean when you specify preferred units which are different from those?

It means that whenever Maya displays a value to you, for example in
the Attribute Editor or as the result from a getAttr command,
it will convert the value to your preferred units before displaying it.
And whenever you give a value to Maya, for example in the Channel Box or
in a setAttr command, Maya will interpret that value as being in
your preferred units and will convert it to its internal units before storing
it.

For example, let's say that you set your preferred linear units to be
feet. You then issue the following two commands:

setAttr sphere1.translateX 2;
getAttr sphere1.translateX;

Since translateX is a linear attribute, and you have set your preferred
linear units to be feet, Maya will interpret the 2 in the first command
as 2 feet. Since Maya's internal linear units are centimeters, it will
convert this value to 60.96 centimeters before storing it in sphere1.translateX.

In the second command, the reverse process takes place. Maya retrieves
a value of 60.96 centimeters from sphere1's translateX attribute.
Since your preferred linear units are feet, Maya will convert the value
to feet, giving a result of 2, which is what it displays back to you.

So you get back the same value that you put in. That's not too exciting.
But what happens when you start connecting attributes together in the Dependency
Graph? Specifically, what happens when you connect together attributes
of different types?

For example, let's say that you want sphere1 to rotate around its Y
axis while it moves in the X direction. To do this, you connect its translateX,
which is a linear attribute, to its rotateY, which is an angular
attribute.

connectAttr sphere1.translateX sphere1.rotateY;

Keeping in mind that sphere1.translateX was set to 2 earlier, what
angle should sphere1.rotateY now contain?

Most people would think that rotateY should be 2 as well. However,
remember that that 2 was interpreted as 2 feet, and Maya converted it to
60.96 centimeters before storing it. So the value that would end up being
fed into sphere1's rotateY is 60.96, not 2. Since that would almost
certainly not be the intended result, Maya does a bit of black magic to
make the results come out the way that people would expect them to.

It does this by inserting a unitConversion node into the connection
between sphere1.translateX and sphere1.rotateY. The unitConversion
node multiplies its input value by a conversionFactor and sends
the result to its output. In our example, the conversionFactor would be
set to 0.0328084 which, when multiplied by 60.96, will give a result of
2. Thus, rotateY gets set to a value of 2 radians, as expected.

To make things even more interesting, let's assume that your preferred
angular units are currently set to degrees. If you try to look at the value
of rotateY, Maya will convert it into degrees for you, displaying
a result of 114.591559 degrees. Once again, this isn't the result that
most people would expect: they have what they think is a direct connection
between two attributes, so if they set the source side of that connection
to 2, they expect to see 2 on the destination side as well. So when Maya
creates a conversion node, it has to calculate the factor required to convert
the source value from your preferred units (feet) into internal units
for that value type (centimeters), and the factor to convert internal units
for the destination value (radians) into your preferred units (degrees),
then multiply those two factors together to get the final conversionFactor
for the unitConversion node. E.g:

0.0328084

(feet to centimeters)

*

0.01745329

(radians to degrees)

=

0.0005726146

So when you enter a value of 2 feet into sphere1.translateX, Maya
will convert that to 60.96 centimeters and store that result in translateX.
The unitConversion node will then multiply that by 0.0005726146,
giving a value of 0.034906586016 radians, which will be stored in rotateY.
When you retrieve the value of rotateY with a getAttr command,
or look at it in the Attribute Editor, Maya will convert it to degrees
for you, and you'll see the expected value of 2 degrees. Thus, you entered
2 feet into the source attribute and saw 2 degrees appear at the destination
attribute.

It is important to note that unitConversion nodes are set up to convert
between the preferred units that were in force at the time that you made
the connection. If you subsequently change your preferred units, any
new unitConversion nodes you create will use conversion factors
which make the results come out right for your new preferred units. But
any existing unitConversion nodes will continue to use their old
conversion factors, meaning that the results will not look right under
the new preferred units. In the example above, if you changed your preferred
angular units to radians, then looked at the values of sphere1.translateX
and sphere1.rotateY again, you would still see a value of 2 feet
displayed for translateX, but now rotateY would show a value
of 0.034906586016 radians. There really isn't anything that Maya can do
to get around this: if it changed the conversion factors of existing unitConversion
nodes every time you changed your preferred units, then the real, internal
values of the attributes that they are connected to would suddenly change
as well, and your geometry would get all screwed up.

So as a general rule, pick your preferred units when you begin a new
scene and then stick with them. Otherwise you could end up with unexpected
results.

One other thing to note is that Maya does not always insert unitConversion
nodes into Dependency Graph connections. It only does so when the following
conditions are all true:

The connection is between two numeric attributes.

The source and the destination are of different types (e.g. one is linear
and the other angular).

The current preferred units for at least one of the types involved in the
connection are different from Maya's default units for that type.

If any one of these conditions is not true, then the conversion factor
would end up being 1.0, so Maya just makes a straight connection between
the two attributes without any intervening unitConversion node.

If you're trying to walk the Dependency Graph, the uncertainty of whether
a unitConversion node is or is not present in any given connection
can prove annoying. Fortunately, Maya provides a way to sidestep this uncertainty
by providing the listConnections command with the -skipConversionNodes
flag. By setting this flag to true, you can skip right over the unitConversion
node, if it's there, and get to the attribute on the other side, which
is generally what you're after. E.g:

Time is handled a bit differently from the other numerical values. First of all, instead of using the same unitConversion nodes as for the other numerical values, time values have their own timeToUnitConversion nodes.

Second, the internal units that Maya uses for time -- 0.00016666667 seconds, equivalent to
a frame rate of 6,000fps -- are not available for you to use as your preferred units. This means
that connections between time and non-time attributes will always have timeToUnitConversion
nodes in them.

One other confusion about time units should be cleared up here. When you look at the list of
available time units, you'll see hours, minutes and seconds, which all make sense, but also
film, game, pal and others which are all frame rates. How can a frame rate represent a unit of time?

The trick here is that the units are really the time for a single frame at the given rate. Thus, if
your preferred time units are set to pal, then a time value of 4 would represent four frames
at the PAL rate of 25fps, which gives you 0.16 seconds of time.

All of the above might work quite nicely if it were not for a number of
bugs in Maya's handling of units. Most of these are the result of node
attributes which have been given the incorrect value type. To see an example
of this, create an arcLengthDimension node and check the type of
its arcLength attribute:

Since the arcLength attribute represents a distance, it should return
a type of doubleLinear. But instead, it returns the dimensionless
type of double. This means that no matter what you set your preferred
linear units to, Maya will always display the arcLength value in
centimeters.

You might think that nothing more than an annoyance, but more insidious
errors can result from it. Consider the following fragment of a MEL script:

Let's say that arc1.arcLength is currently 5 centimeters. If your
preferred linear units are centimeters, then $length will be set
to 5 and sphere1.translateX will in turn be set to the same value.
All is well.

But watch what happens if your preferred linear units are feet. Since
arc1.arcLength has the dimensionless type of double, Maya
will just retrieve its value straight up, without any conversion. So $length
will still be set to 5. In the setAttr command, sphere1.translateX
is of a linear type, so Maya will interpret the value in $length as being
in your preferred linear units. Thus, sphere1.translateX ends up
being set to 5 feet, or 304.8 centimeters.

So the script will generate different results depending upon the current
setting for your preferred linear units. This is nasty because it means
that you can test your script out using Maya's default units and find everything
working fine. Then suddenly, one day, a user decides to change her linear
units to something different and the script begins generating erroneous
results.

Below is a table listing some of the known errors in Maya's attribute
types. This listing is not exhaustive, it merely represents those errors
which Gooroos Software has run into so far. If you encounter any others,
please let us know and we will add them to the table.

Node

Attribute

Actual Type

Correct Type

arcLengthDimension

arcLength

double

doubleLinear

arcLengthInV

double

doubleLinear

motionPath

uValue

doubleLinear

double

Gooroos Software's freely available unitCorrection node can be used to adjust for these errors. It gives you the ability to convert a value from one type to another, without introducing any unitConversion nodes or otherwise changing the value.

Looking at our earlier example, a unitCorrection node could be used to eliminate the errors as follows: