← Back to rigging
Automate Joint Control Curves in Maya with Python (Shape Parenting Guide)
12 Sep 26 (1mo ago)
Normally, you will have separate objects for controls and joints. Sometimes, especially, if I just want to rapidly iterate or I'm animating my own scene, I prefer having just the same.
Definitely, not a standard practice but works on my usecase.
You can definitely do this though MEL with the parent -r -s command to parent shapes directly to joint.
P.S. By default you can only select the transforms. To select the shapes, in the outliner, you need to disable DAG only objects.
The Workflow
Attaching a curve shape directly to a joint transform eliminates redundant grouping nodes and keeps the Outliner clean. To automate this across multiple joints:
- Filter the active selection specifically for
jointtypes. - Duplicate the base template curve (
conCrv). - Zero out offsets by parenting the duplicate transform to the target joint.
- Reparent the curve's shape node to the joint using
shape=Trueandrelative=True. - Rename the shape node dynamically using the joint's base name (
{joint}_crv). - Delete the residual empty transform node.
Maya Python Implementation
To automate the process, see the script below:
import maya.cmds as cmds
def attach_unique_con_to_joints():
# 1. Filter selection to joints only
selection = cmds.ls(sl=True, type='joint')
if not selection:
cmds.warning("Please select at least one joint.")
return
source_curve = "conCrv"
if not cmds.objExists(source_curve):
cmds.error(f"Source curve '{source_curve}' not found.")
return
for jnt in selection:
# 2. Duplicate template curve
temp_crv = cmds.duplicate(source_curve, name="temp_con_crv")[0]
# 3. Match transform orientation and position
cmds.parent(temp_crv, jnt, relative=True)
# 4. Extract shape node
shapes = cmds.listRelatives(temp_crv, shapes=True, fullPath=True)
if shapes:
# 5. Parent shape to joint (-r -s logic) and assign unique name
target_name = f"{jnt}_crv"
new_shape = cmds.parent(shapes[0], jnt, relative=True, shape=True)[0]
cmds.rename(new_shape, target_name)
# 6. Clean up empty transform
cmds.delete(temp_crv)
print(f"Controls created and renamed for {len(selection)} joints.")
attach_unique_con_to_joints()
Why Shape Parenting Matters
- Zero Transform Clutter: The joint serves as the transform node, removing unnecessary intermediate group levels.
- Selection Speed: Animators can pick the visual curve directly in the viewport while operating on the joint's native rotation and translation channels.
- Deterministic Naming: Dynamically appending suffixes avoids Maya's automatic name-incrementing collisions across large skeleton hierarchies.