MEL Scripting a Character Rig in Maya: Adding Advanced Rig Controls
THIS CHAPTER SHOWS you how to take the basic IK biped rig that you just created in the last chapter to an advanced level by adding skeletons and upgrading all the controls for the major body areas. This involves writing modular scripts that incorporate all the rigging and coding techniques previously covered in this book, while enhancing the process with new techniques for connecting and refining attribute connections. By the end of this chapter, you will have a fully functional character rig with many advanced controls, ready to bind and animate.
Enhancing the IK Limb Controls
This section focuses on upgrading the basic IK rig arm and leg controls to have a variety of new skeletons and attribute connections. You'll add both FK and IK skeletons to improve skin deformations, and add custom channels to allow a greater range of icon controls, especially in the hands and feet. The process will be first shown in the interface, and then reviewed in the advanced scripts.
Creating an Advanced Arm Rig
Rigging the advanced arm involves creating skeletons in the upper arm, forearm, and fingers. Many of the FK joints in these skeletons will be connected to custom channels that you'll create on the arm icons. New methods for creating and connecting channels will be introduced, such as math expressions and setting driven keys. These techniques will allow you to create a variety of custom controls on the rig, like channels on the arm icon that drive finger rotations (see FIGURE 4.1). Once you've created all the new controls, you'll see how to clean up the channels so they are ready to animate.
Figure 4.1 Rigging the advanced arm involves creating skeletons in the forearm, hand, and fingers, and then driving the joints using custom channels added to the arm icon.
Improving Bind Deformations
When running the book scripts to create the basic rig, if you click the check box in step 8 of the setup GUI, you can test-bind the rig to see how it deforms the skin. Inevitably you will notice some deformation problems in areas where limbs or appendages attach to main body sections like the torso. For instance, moving an arm icon may produce too much movement in the neighboring chest area, causing it to cave in when the arm is lowered (see FIGURE 4.2). Or rotating the hip icon may cause the stomach skin to move too much. These are common problems for any simple character rig, because you are assigning only a minimum amount of deformers to the skin. Maya assigns points on the skin to the closest deformer or joint, and many of these areas do not even contain skeletons. Having few joints in these areas forces Maya to guess how much it should assign influence to these deformers, and frequently it assigns the wrong amount.
Figure 4.2 Test-binding the basic rig reveals some inherent deformation problems where limbs connect to the torso, such as the chest caving in when an arm is lowered.
You could fix many of these deformation problems by painting weights on the skin, but such work is time-consuming and tedious. Instead, it is often easier and faster simply to add secondary FK skeletons to these problem areas to force Maya to assign better weighting. Parenting these secondary skeletons under the closest joints in the main skeletons will force them to move correctly with the rig controls. Then when you bind the skin, the points will move indirectly with the main joints you originally intended them to move with, and you will have some extra joints to drive for additional controls. With this in mind, a major part of all the advanced scripts will involve adding such secondary skeletons.
Adding Upper Arm FK Skeletons
One problem area on the upper arm is how the shoulder deforms when the rotate plane controls the arm. In the default pose, moving the elbow icon up and down uses the Pole Vector constraints to twist the arm. This movement produces too much movement at the shoulder because it globally rotates the entire skeleton the same amount, whereas in a real arm, the shoulder area has less apparent twisting because the shoulder muscle structure hides the bone rotation.
Since the goal of rigging is to achieve realistic effects as easily as possible without resorting to complex simulations, you want to just use joints and channels to create the desired rotation falloff at the shoulder. Do this by adding another upper arm joint that is segmented to rotate the shoulder area joints less than the elbow area joints. Here's how to create such a control in the interface using a math expression to divide the rotation, and drive the joints different amounts.
To add a multi-joint upper arm skeleton to the basic rig:
- In Perspective view, create a two-joint FK skeleton on top of the left upper arm bone, going from shoulder to elbow. After activating the Joint Tool, hold down the V key to snap a joint on the left arm root joint, and then on the lower arm joint.
- Then activate the Insert Joint tool in the Skeleton menu, and hold down the Shift key as you drag a new joint out of the left root joint. Holding down the Shift key ensures that the skeleton stays straight along the bone.
- Repeat step 2 using the Insert tool until you have segmented the skeleton into three equal segments. Name the new skeleton joints something like lfNewUpArmRoot, lfNewUpArm1, and so on. Now you'll use a parent constraint to make the new segmented FK arm skeleton stay attached to the IK upper arm skeleton. Parent constraints combine the effects of point and orient constraints into one command.
- Shift-select the left arm root followed by lfNewUpArmRoot, and choose Constrain > Parent . Set the options as shown in FIGURE 4.3, being sure to deselect Rotate All, and only select the Rotate Y and Z axes.
Figure 4.3 Parent-constrain the root joint of the new upper-arm FK skeleton to the original IK arm root, but deselect the rotate X channel in the Parent Constraint Options dialog box.
This constrains all the translations and rotations except the X axis, which will be driven at different rates to twist the skeleton. The new segmented FK skeleton should remain connected to the original IK skeleton when the arm icon is moved, but it won't twist yet when you move the elbow icon.
Driving the Upper Arm Twisting
To twist the new upper arm joints at different rates, you can use math to divide the IK arm X rotation by different amounts, and have the resulting values rotate the FK joint segments. Attribute connections that involve math can be done by writing a math expression in the Expression Editor. Although expressions and MEL have some similarities, they are different languages, with different commands, syntax, and formatting.
To rotate the FK upper arm joints in X using a math expression:
- Choose Window > Animation Editors > Expression Editor to open the Expression Editor. In the Select Filter menu, switch to By Expression Name, and then type the following math expression (being sure to use the correct names for your skeleton joints):
lfNewUpArm.rotateX = 0 + (lfArmRoot.rotateX / 3); lfNewUpArm1.rotateX = 0 + (lfArmRoot.rotateX / 2); lfNewUpArm2.rotateX = 0 + (lfArmRoot.rotateX);This expression has several lines that increasingly divide the effect of the arm twisting as joints get closer to the shoulder. Notice at the end of the lines that the root joint rotation is divided by three (/ 3), the second joint rotation is divided by two (/ 2), and the third joint rotation is not divided at all. These values are then used to drive the rotationX channel of each new upper arm joint. The 0 + operation adds the divided value to the FK joints default 0 value.
- Type UpArmTwist into the Expression Name field, and click Create to assign the expression to the new joints. Notice that the driven joints X channel turns purple, indicating there is an expression connection (see FIGURE 4.4).
Figure 4.4 Using an expression to divide the X rotation of the new upper-arm joints creates a falloff on the shoulder when the arm twists, turning the constrained channel purple.
Click Close to close the Expression Editor, and move the elbow icon to test the expression. The effect of the expression on the bound skin produces an automatic falloff that smoothes out the twist deformation at the shoulder.
Math expressions are easy to understand and write, but you may need to use another method to create the same division effect. Since connecting nodes directly with a connectAttr command is the most basic kind of connection in Maya, it processes a little faster than math expressions. This may not be an issue with all animation projects, but some large productions may require the use of direct node connections to speed up scene interaction. To do the same operation manually with node connections requires that you connect the X rotation channels of the nodes through a Multiply-Divide utility node.
Although you can create and connect these types of nodes manually in the Hypergraph or Hypershade, it is easier and more reliable to use MEL. Here is how you would use MEL code to make the same type of connection to divide the new upper arm joint rotations:
//Set joint names into variables: string $limbRoot = "lfArmRoot"; string $joint0 = "lfNewUpArm"; string $joint1 = "lfNewUpArm1"; string $joint2 = "lfNewUpArm2"; //Create a Multiply-Divide utility node: string $divide = `createNode multiplyDivide -n "armDivide_util"`; //Set the operation to divide: setAttr ($divide + ".operation") 2; //Connect and divide all the input attributes: connectAttr -f ($limbRoot + ".rx") ($divide + ".i1x"); connectAttr -f ($limbRoot + ".rx") ($divide + ".i1y"); //Set the division values on the utility node: setAttr ($divide + ".i2x") 3; setAttr ($divide + ".i2y") 2; //Connect th output attributes to the joints: connectAttr -f ($divide + ".ox") ($joint0 + ".rx"); connectAttr -f ($divide + ".oy") ($joint1 + ".rx"); connectAttr -f ($limbRoot + ".rx") ($joint2 + ".rx");In this MEL code, the IK arm joint or $limbRoot is being connected to two XY input channels on the utility node (both input X rotation values even though one channel is labeled Y). Then setAttr commands set the division values on the utility node. Lastly, connectAttr commands connect the output channels containing the divided values to the new FK joints. After running this code, selecting the left arm root joint and choosing Window > Hypergraph: Connections will show you how the nodes are connected (see FIGURE 4.5).
Figure 4.5 Creating utility nodes in the Hypergraph allows editing direct node connections, such as multiplying or dividing a channel connection.
Creating Forearm Twist Controls
The forearm is extremely complex in a real body. Muscles wrap around bones, contracting and relaxing to create the twisting motion of the lower arm and hand. Rather than try to simulate this complexity, you can simply create a new FK arm skeleton that contains a joint centered in the forearm that will drive the lower arm twisting. This joint will not only drive the hand skeleton, but will also drive two IK skeletons created for the radius and ulna.
To create a left forearm rig to control the lower arm twisting:
- In Top view, draw a three-joint FK skeleton straight down the middle of the lower arm from elbow to wrist, placing the second joint midway down the forearm. Name the joints lfForearmRoot, lfArmTurn, and lfForearmEnd.
- Transform the new forearm skeleton into place so it fits well inside the skin, and is positioned between the radius and ulna polygon bones. Use the main IK arm skeleton as a guide for positioning (see FIGURE 4.6).
Figure 4.6 Create a new FK lower-arm skeleton with an extra armTurn joint in the middle of the forearm. This joint will be the main control for twisting forearm and hand skeletons.
- Make the root joint child to the lower arm joint of the main arm skeleton, creating some group nodes to be used as pads between the parented joints. Name the group nodes lfForearmPad0 and lfForearmPad1. To make sure the FK skeleton produces the correct values when the joints rotate, orient the group nodes the same as the root joint before parenting.
- Re-parent the wrist group nodes, lfWristTurn0 and lfWristTurn1, that were parented under the end joint of the IK arm skeleton in the basic rig, to the end joint of the new FK forearm skeleton. Rotating the new lfArmTurn joint in X will now rotate the hand.
- To make the forearm set up a little more realistic, add ulna and radius skeletons. Use the polygon bones as guides for drawing two-joint IK skeletons from the elbow area to the wrist area on either side of the main forearm skeleton. Name the joints lfUlnaRoot, lfUlnaEnd, lfUlnaIk, and so on.
- Parent both root joints of the ulna and radius skeletons under the root joint of the new forearm skeleton, with group nodes inserted as pads. Then make the IK handle for the radius skeleton child to the lfArmTurn joint. This will cause the radius to twist with the hand when the central forearm joint rotates in X. The ulna, however, won't be parented in the same way as the radius, which would make the elbow appear to break when the forearm rotates.
- To dampen the rotation effect, but still make the ulna move with the forearm, use a constraint rather than parenting. Create a locator positioned right on top of the ulna IK handle. Then point-constrain the ulna IK handle to the locator.
- Parent the ulna IK under the forearm root joint, and parent the locator under the lfArmTurn joint. The point constraint simulates some of the parenting effect, while filtering out the rotation, preventing the elbow from breaking. This is easy to see once you re-parent the radius and ulna polygon bones under the new Maya joints, and rotate the lfArmTurn joint to test the control. Your final hierarchy should look like the Hypergraph structure in FIGURE 4.7.
Figure 4.7 Here is how the advanced arm rig forearm controls should be parented in the Hypergraph.
After completing the left arm, repeat the entire process to complete the right arm. Although some of the individual skeletons can be mirrored to the other side, the whole hierarchy won't mirror correctly.
This setup technique has the advantage of easily creating an FK swinging control on the lower arm. To make a limb swing means that the upper limb joint stays still while the lower limb joint rotates. This is often an unconscious movement on the arms, and sometimes the legs, when walking. A slight swing can also occur on the arms after throwing something, or on a character's leg when sitting off the ground with the legs dangling. Because all the joints in an IK skeleton are constrained to rotate whenever the IK handle is moved, it is very difficult to create such a swinging effect with IK skeletons.
Since the FK forearm skeleton is child to the main arm skeleton, it will move with the IK; but you can also rotate the forearm root joint in Z to make the arm swing slightly (see FIGURE 4.8). Rotating the new lower arm skeleton will produce a minor swinging motion, but avoid animating the lower arm skeleton away from the IK arm and icon for long periods, which makes the controls less intuitive. Be aware that adding new child skeletons like this means you will not bind the parent IK arm joints. In fact, it is a good practice to rename the original arm joints to indicate that they should not be bound. For instance, in the advanced scripts covered later in this chapter, the IK arm joints are renamed with _ctrlRoot and _ctrlJoint suffixes, which causes the bind script to ignore them.
Figure 4.8 The new lower-arm setup facilitates a simple FK swinging control on the arm through the parenting; only bind the FK joints, not the original IK joints.
This type of arm setup does not use the method of constraining multiple skeletons to create IK-FK switching controls, which would really complicate the arm rig, and often have flipping problems. Unfortunately, you cannot make the IK parent skeletons and icon follow the FK child, because that sequence produces a computer cycle or never-ending loop. Computer cycles cause error messages, and make the rig unstable. Instead, use the new FK arm controls to animate minor swinging movements; later you can create IK-FK switching controls using the built-in ikBlend channel on the arm IK handle, and the IK/FK Keys in the Animate menu.
Adding FK Finger Skeletons
All the controls in the wrist and hand, including the finger skeletons, should be FK controls that will later be driven by custom channels created on the arm icon. You can create the finger controls as five-joint skeletons starting from the metacarpals in the hand, or as four-joint skeletons starting from the knuckles, depending on the amount of control you want to have over deforming the palm of the hand. Adding metacarpal joints allows you to cup the hand, and can produce minor tendon deformations on the back of the hand.
To add FK finger skeletons:
- Draw the finger skeletons in Top or Front view using the polygon bones as a guide. If your character is in a relaxed default pose, like the example character, you will have to transform the joints extensively to fit them correctly. It is often easier to draw and fit one finger skeleton, and then duplicate it to create the others. Since they are FK skeletons, you can freeze the transformations afterward.
- After positioning the joints correctly, mirror them to the other side using behavior, and then parent them individually under the appropriate hand end joint.
- Insert two group nodes as pads between the hand end joint and each finger root joint. Name them lfIndexPad0, lfIndexPad1, lfMiddlePad0, and so on. Be sure to position and orient these group nodes according to each finger root joint, which is required to generate the correct channel values for driving the finger joints in the next section (see FIGURE 4.9).
Figure 4.9 Be sure to orient the group node parents of the finger skeletons the same as the finger joints, so that the channels on the finger controls will generate correct values in a single axis.
Driving Arm Joints with SDKs
Many of the joints in the lower arms, hands, and fingers have no icons to easily animate their rotations. Since creating individual icons for all the joints would clutter up the rig, you can instead add custom channels on the existing arm icons to control the joint rotations. The easiest and most intuitive way of doing this in Maya is to use set driven keys (SDKs). This feature is a useful way of connecting channels that don't require any math computations. As the name implies, SDKs generate special keys that are independent of the animation timeline. Setting the keys defines the values of the driven channel in relation to the values of the driver channel.
To create a SDK connection in the interface, you must define a driver channel and driven channel and then set the keys that connect them in the SDK dialog box. One advantage of this method over node constraints or math expressions is that it produces animation curves that can vary the timing in the connection. Also, SDKs allow multiple drivers to control the same driven channel, without inserting any additional nodes into the connection; this simplifies the controls. For these reasons, SDKs are used for the majority of controls on most rigs.
The typical SDK has three keys to set for the minimum, default, and maximum values of the driver and driven channels. You normally set your custom driver channel limits to generic values, while the driven channel values are specific to the range of motion of the body control. You can add more or fewer than this standard amount of keys for your SDK connections, depending on your needs.
To create a custom driver channel on the arm icon and use SDKs to drive the twisting of the forearm:
- Select the left arm icon and choose Modify > Add Attribute. In the resulting dialog box, type armTurn for the custom attribute name and select the Override Nice Name option to create a label that is displayed with spaces and capitalization in the Channel Box Nice Name field. Use the default Float data type and Scalar attribute type, and set the Minimum, Maximum, and Default numeric attribute properties to –10, 10, and 0 (see FIGURE 4.10).
Figure 4.10 Creating custom attributes or channels on the icons allows you to create additional controls to manually drive any control that doesn't have a control icon of its own.
- Click OK to add the attribute to the arm icon, and test the limits by scrubbing the channel in the Channel Box.
- Choose Animate > Set Driven Key > Set. The resulting dialog box has a Driver section on the top, with a Driven section on the bottom. Load Driver and Load Driven buttons across the bottom let you load the objects to connect.
- Select the arm icon and click the Load Driver button to load the transform node and attributes. In the list of attributes on the right, select the armTurn custom attribute that is at the end of the list (see FIGURE 4.11).
Figure 4.11 Load the driver and driven nodes into the Set Driven Key dialog box, and select the channels you want to connect with driven keys.
- In the 3D or Hypergraph view, select the lfArmTurn joint, and click the Load Driven button, selecting rotateX in the attribute list.
- With both driver and driven channels at their default values, click the Key button to set a driven key. You should see the X rotation channel in the Channel Box turn orange to indicate that a key is set.
- Select the arm icon in 3D view or double-click the icon name in the SDK dialog box. In the armTurn channel, type a value of 10, and then double-click the lfArmTurn joint name in the SDK dialog box to select the joint; manipulate the rotation value to about 40 degrees. Click the Key button again.
- Select the icon again and set the driver channel to –10, select and rotate the joint in the other direction to about –70 degrees, and set the final driven key.
- When you have finished, set the icon driver channel back to 0, which should set the arm back to the default rest position. Then select the driver channel in the Channel Box and scrub it using the middle mouse button in the 3D views to see the arm twisting (see FIGURE 4.12).
Figure 4.12 Always test the SDK controls to ensure that they are working correctly, such as scrubbing the armTurn channel in the Channel Box to twist the arm.
Be sure to look at your own joints to see how the controls should work, and how far to set limits on custom channels. For instance, on the lower arm twist control, you keyed the rotation of the lfArmTurn joint at –70 and 40 degrees because that is the range of motion without moving the elbow. To twist the arm further, you translate the elbow icon, which rotates the entire arm around the rotate plane.
Once you get used to switching between driver and driven channels when creating SDK controls, the process is easy and fast. In addition to the armTurn channel, the advanced arm controls should include driver channels for the lower arm FK swing, as well as for the wrist rotations, and all the finger joint movements.
Also, if you are going to connect the same type channels to a single driver, you can load multiple driven nodes into the driven field of the SDK dialog box. This can speed up the process of using a single-finger channel to drive multiple-finger joints to rotate in Z. Just Shift-select the finger joints to load them together into the driven section of the SDK dialog box (see FIGURE 4.13).
Figure 4.13 Use the Shift key to load and simultaneously key multiple driven nodes in the Set Driven Key dialog box, such as setting keys on the rotate Z channels of several finger joints.
Cleaning Up the Arm Icon Channels
One of the final rigging tasks when creating advanced controls is to clean up the icons that will be used by the animator. Cleaning up the icons streamlines the controls, and makes them harder to break by preventing the animator from easily manipulating unintended transformations. The task involves setting default manipulators for each icon, and setting limits on the main transform channels. It also involves hiding and locking channels that should not be animated, such as most scaling and constrained channels.
After you've cleaned up the channels, it is a good practice to set a key at frame 0 on the timeline for all the icons at their default positions. Doing this makes it easy to return the rig to the default T-pose whenever needed, such as for binding, by simply clicking the timeline at 0.
To clean up the channels on the left arm icon:
- Select the left arm icon. In the main toolbox, turn on the Show Manipulator tool by clicking the tool button at the bottom of the main transform toolbox. Notice that no manipulator is displayed with the arm icon selected.
- Choose Modify > Transformation Tools > Default Object Manipulator > Move, and notice that the Move tool appears whenever the arm icon is selected.
Try assigning some of the other choices in the Default Object Manipulator menu, including the transform manipulator, which assigns a tool that has all three transform functions (see FIGURE 4.14). However, since an arm icon is only meant to translate the arm IK handle, reassign the Move tool as the permanent default manipulator.
Figure 4.14 A good way to streamline iconic controls is to set default manipulators and activate the Show Manipulator tool. The transform manipulator allows moving, rotating, and scaling the icon.
- Set the default manipulators on all the icons depending on how each icon should be transformed. For instance, the torso icon requires both translation and rotation, so set the transform manipulator. The head icon, on the other hand, only requires to be rotated, not translated, so set the rotate manipulator. Do not be concerned about scaling at this point, as you will be locking and hiding the scaling channels on most icons.
To set limits on transform channels that will be animated, right-click the icon to open the Attribute Editor, and click the Limit Information tab under Transform Attributes. Setting limits on all the icons is necessary to make the character GUI sliders generate correctly later. If you don't want to limit a particular control, then just set the limits on that icon to well beyond the normal values.
For instance, for an arm icon that will only be translated, setting a limit of 50 grid units on the translation channels will be more than enough to allow for a free range of motion on most normal sized characters. Or setting a rotation limit of 720 on the Char icon will allow the animator to completely turn the character twice, which is more than most scenes require.
- Click the arrow button next to Limit Information to display the limit options, and select the check boxes for the attributes you want to limit (see FIGURE 4.15). Either type limit values manually, or manipulate the icons in the 3D interface, and click the arrows to set the limits.
Figure 4.15 Set transform limits in the Attribute Editor on icon channels that will be animated.
To remove channels from view that you do not want to be animated, lock and hide them. Choose Window > General Editors > Channel Control. Notice the resulting dialog box has tabs for Keyable and Locked channels, with the visible and hidden keyable channels displayed.
To hide transform channels, select them in the left Keyable list, and click Move to move them to the middle Nonkeyable Hidden list (see FIGURE 4.16).
Figure 4.16 A big part of cleaning up icons is to hide and lock icon channels that the animator should never manipulate, such as the scaling channels on the arm icon.
- Click the Locked tab in the dialog box, and select the same channels you just hid, and then move them to the left Locked field. Now notice when activating the Rotate or Scale tools that the manipulators are grayed out and not available.
- When you have finished hiding and locking all channels, click Close to exit the Channel Control editor.