[Maya]Rigging 04 - Controller
Keywords: Maya, Rig Control Curve, Control Rig, Layered Controls, Animation Layers
Maya Rigging series of articles:
- [Maya]Rigging Overview
- [Maya]Rigging 01 - Joint
- [Maya]Rigging 02 - Skinning
- [Maya]Rigging 03 - Visualization
- [Maya]Rigging 04 - Controller
- [Maya]Rigging 05 - Attributes
- [Maya]Rigging 06 - IK & FK (WIP)
- [Maya]Rigging 07 - Keyframe (WIP)
- [Maya]Rigging 08 - Common Tricks (WIP)
Summary
Why we need the Layered Controls? two reasons:
- We want to prevent the animator from touching the skeleton, because we don’t want others to add or remove joints which will lead to potential issues.
- If we add other nodes(Curve, Locator, etc.) directly into skeleton hierarchy, it will cause issues when it comes to export to the Unreal Engine.
So we need a top layer to drive joints, that’s Layered Controls!
Create Controller Method 1st: Parent Constraints (Recommended)
Take shoulder joint as example.
1, Create Curve: Create -> NURBS Primitives -> Circle
2, Scale the curve.
3, Freeze the transfrom and delete history:
- Modify -> Freeze Transformations.
- Edit -> Delete by Type -> History. (Alt + Shift + D)
4, Match Transforms.
Select shoulder joint and curve together, Modify -> Match Transformations -> Match All Transforms.
Another way to snap Control to Joint: Hold V and drag Control to target joint.
5, Tweak the curve’s rotation.
6, Parent Constraints.
Select both shoulder joint and curve, Hold Space -> Constrain -> Parent.
Now you can drive shoulder joint using controler.
More control curve templates: Control Icons
Create Controller Method 2nd: Merge Curve’s Transform Node
1, Create a curve and tweak the transform. Which axis is modified depends on the target joint coordinate axis.
2, Freeze the transfrom and delete history:
- Modify -> Freeze Transformations.
- Edit -> Delete by Type -> History. (Alt + Shift + D)
3, Display the transform node: Right click hierarchy viewport -> Shapes.
4, Parent the curve to the target joint:
parent -r -s
5, Delete curve’s transform node, and hide the Shapes, now you can drive the joint using curve which likes Handle.
Controller Tweaking
Change the display color:
Change the line width:
Hide Joint for Controler
In the process of rigging, we can hide the joints to highlight the controllers: Show -> Viewport -> Uncheck Joints
.
But it causes to hide controllers when the visibility of joint was off.
Q: As mentioned before, to prevent animator from touching skeleton, so we need to hide the joint, is there any way to display the controllers while joint was hidden?
A: Change the joint’s draw sytle.
We can change only one joint at a time on GUI, but can do it in batch using script.
Hide all joints:
string $target = "root";
select -r $target;
string $joints[] = `ls -type joint`;
for($joint in $joints)
{
setAttr ($joint + ".drawStyle") 2;
//print($joint + "\n");
}
Show all joints:
//change drawStyle from 2 to 0
setAttr ($joint + ".drawStyle") 0;
Transform Offset Method 1st: Group
As the Create Controller Method 1st say, when you tweaked the transform of controller, Translate and Rotation are non-Zero, thus it’s not friendly for animator.
Solution:
1, Create an empty Group. (shortcut: Ctrl + G)
2, Select Group first, then select Controller, then Match All Transforms. Then you can see the Group’s transform changed.
3, Drag the Controller into Group, then you can see the Controller’s transform was zeroed.
Transform Offset Method 2nd: Offset Parent Matrix
Take Create Controller Method 1st as an example again.
From Maya 2020, it provide a new feature named Offset Parent Matrix to offset transform.
You can just copy the transform from Transform Attributes to Offset Parent Matrix, then zero the transform from Transform Attributes.
Now you can found that the controller’s transform was zeroed.
Script to copy Offset Parent Matirx and zero Transformation (credits to Muream):
import maya.api.OpenMaya as om
import maya.cmds as cmds
TRANSFORM_NODETYPES = ["transform", "joint"]
def has_non_default_locked_attributes(node):
locked_attributes = []
for attribute in ["translate", "rotate", "scale", "jointOrient"]:
default_value = 1 if attribute == "scale" else 0
for axis in "XYZ":
if cmds.attributeQuery(attribute + axis, node=node, exists=True):
attribute_name = "{}.{}{}".format(node, attribute, axis)
current_value = cmds.getAttr(attribute_name)
if cmds.getAttr(attribute_name, lock=True) and current_value != default_value:
return True
def reset_transforms(node):
for attribute in ["translate", "rotate", "scale", "jointOrient"]:
value = 1 if attribute == "scale" else 0
for axis in "XYZ":
if cmds.attributeQuery(attribute + axis, node=node, exists=True):
attribute_name = "{}.{}{}".format(node, attribute, axis)
if not cmds.getAttr(attribute_name, lock=True):
cmds.setAttr(attribute_name, value)
def bake_transform_to_offset_parent_matrix(node):
if cmds.nodeType(node) not in TRANSFORM_NODETYPES:
raise ValueError("Node {} is not a transform node".format(node))
if has_non_default_locked_attributes(node):
raise RuntimeError("Node {} has at least one non default locked attribute(s)".format(node))
local_matrix = om.MMatrix(cmds.xform(node, q=True, m=True, ws=False))
offset_parent_matrix = om.MMatrix(cmds.getAttr(node + ".offsetParentMatrix"))
baked_matrix = local_matrix * offset_parent_matrix
cmds.setAttr(node + ".offsetParentMatrix", baked_matrix, type="matrix")
reset_transforms(node)
def bake_transform_to_offset_parent_matrix_selection():
for node in cmds.ls(sl=True):
bake_transform_to_offset_parent_matrix(node)
if __name__ == "__main__":
bake_transform_to_offset_parent_matrix_selection()
Q: why don’t we zero transform offset using Freeze Transformations before Parent Constraints?
A: Freeze Transformations will change the axis direction of pivot.
References
Character Rigging for Beginners: 03 Primary Controls
https://www.youtube.com/watch?v=m37fhS9MNSI&list=PLbvsJz5ZcmxHEPiw_kF3vHjR023rIjR05&index=3
Character Rigging for Beginners: 04 Secondary Controls
https://www.youtube.com/watch?v=tsOXYOoGBNY&list=PLbvsJz5ZcmxHEPiw_kF3vHjR023rIjR05&index=4
Realtime Creature Rigging Workshop (7 / 19) : Control creation
https://www.youtube.com/watch?v=6jO9jQQfSL8
Plugins
Maya control curve UI
https://peerke.gumroad.com/l/WRtX
紫光阁名录:多拉尔·海兰察
海兰察(满语:ᡥᠠᡳ᠌ᠯᠠᠨᠴᠠ,穆麟德转写:Hailanca;1739—1793年),多拉尔氏,索伦部(今鄂温克族)人,后入满洲镶黄旗,世居黑龙江,生于呼伦贝尔阿荣旗霍尔奇镇,乾隆中后期名将,因屡立战功,官至正一品领侍卫内大臣,爵封一等超勇公;卒谥武壮。清朝惯例,阵亡者方能入祀昭忠祠,乾隆御准海兰察加恩入祀,旌扬战功。