Rig Module 2018

  • as primary deformation of geometry is deformed by a set of bones
  • secondary deformation set of bones is deforming the geometry in different way,
  • combination of this 2 type of deformation by linking with blendshapes.

My Rigging Workflow

The rigging workflow is important, as there are so many ways and steps to do the rig.

So my workflow is this:

  • build binding structure (build model into blocks[group], use locator or bone as structure)
  • build ctrl structure (orientate ctrl)
  • build mechanic structure (how each block interact with each other)

Rigging guideline

  • Rig stage from start to finish
    • mockup rig: simple ctrl and rig script to make it work
    • script rig: guide objects and build script
  • time frame for each version
    • mockup rig: made up with only exisiting modules and simple script, no custom module to use
    • script rig; more detail and variation coming in during this version


  • “you cannot modify the set membership of a skinCluster to add additional skins. Each skin must have its own skinCluster”. - smooth skinning
    • that is why, it is good to combine all the “screw and parts” into one mesh, easy to skin and manage parenting.
  • methods of saving weights
    • method a: maya save weights on UV based weight maps
    • method b: vertex based vertex-to-joint weight table (like in component editor's smooth binding tab) (like my script - wMap_jMap_GUI)
    • method c: use binded mesh itself as 3D space weight info model (then transfer weight based on mesh-mesh distance)

My Rig building blocks

Date operation

  • multDivid node
  • PlusMinusAve node
  • Reverse node

Data measurement and monitor

  • arcLen node
  • distance node
  • condition node

Module Build Function

  1. build batch modules
  2. custom individual module settings

Rigging solution

  • Spline IK replacement solution: locator-based controlled CV-point curve dual rail motionPath with up vector object array with bone-parentConstraining locators following path with U offset.
    1. it has segment twist
    2. it has no-flipping spline bones, can rotate any direction even upside down.
  • dynamic chain with motion delay solutions
    • solution 1: getAttr with -time offset driven method (also some noise(time))
    • solution 2: hair dynamic system driven
    • solution 3: softbody particle + spring system driven
    • solution 4: spring alone driven
    • solution 5: particle goal weight alone driven
    • solution 6: jiggle deform with vari weighting driven

  • ribbon setup solution
    1. ctrl_bones skin-driving nurbsurface –> on-surface center-line follicles –> weight_bones
    2. ctrl_scaleInfo_bones skin-driving scaleInfo nurbsurface –> on-surface edge-line scaleInfo follicles –> per transformZ value = per result scaling factor =⇒ on-surface center-line follicles scale value
    3. ctrl_bones – scale link –> ctrl_scaleInfo_bones
  • ref:
  • circular hole, (eye, mouth)
    1. ring of bones for deformation
    2. ring of locators for driving bone aiming with bone length maintained
    3. upper curve and lower curve driving aim-target locator-on-curve
    4. curve bones driving deformation of locator-drive curve
    5. Upper/Lower curve-driven-blendshape middle-close-shape curve (with inbetween position ctrl)
    6. middle-close-shape curve become target curve shape of upper curve and lower curve for closing.
  • ref:
  • Mouth rig: addition notes:
    • there are methods separate lips and lip corner in 2 different system,
    • as with this separate, lip corner change will not affect center lip shape, and center lip movement will not affect lip corner shape (ref: Gumroad - Expressive Facial Rigging by Josh Sobel)

Bone Theory

  • Joint: a transform node with extra attributes affecting IK solving, such as
    1. rotation lock (degree of freedom)
    2. Ik solving parameter
      • stiffness: overall ratio of IK rotation affection on current bone across the bone chain
      • limit: hard limit of when it become full stiffness based on rotation value
      • dampness: more like ramp mapping of IK rotation affection, a ramp like value rato
  • when an object is under a Parent, the Rotate tool will generate different values in channels depending on the order of each rotate action.
    • case example

Rigging Standard A001

  • “Global Ctrl” on rootCtrl (w. RgMod tool)
  - Geometry
  - Ctrls
  - Deformers (geo_deformer)
  - Bones
  - Modules
  - Version_tracking?
  • note:
    • nothing should be inside geometry hierarchy (except constraints)

For pose_man start,

  1. ctrl pose to match new Model (animation library tool: mirror limb tool from table)
  2. locPose for all bones
  3. locPose for all attach bones on Mesh (RigMod: mirror locPose tool)
  4. Process
    1. For pose_man, duplicate pose_man mesh, and export pose_man weight
    2. From pose_man to new model, shift attach bone (RigMod: shift attach bone tool, geo-follicle connect)
      • locPos attach bones → closest point → uv → new mesh to follicle connect
    3. For pose_man, go to guide_pose, re-define guide bones
      • locPose all bones → guide bone position
  5. rebuild pose_man rig, and now it is at new model bind_pose
  6. pickup new model, and duplicated-matching pose_man
  7. apply back pose_man weight, and weight transfer to new model
    • optional re-generate attach bone auto-weight
  8. use Rig_pickup_process to set zero_pose

For blank start or zero_pose creation,

  1. pose to bind_pose,
    • (for start) rebuild rig, store world-space bind_pose
    • (for update) drop-off (unskin) geos
  2. go to (build_)guide_pose, show guide bones
  3. zero guide bones (arm: 10deg elbow bend, leg: 10deg)
  4. rebuild rig at guide_pose
  5. apply world-space bind_pose
  6. pickup (bind) geos

For regional weight fix after weight transfer,

  1. from fixed-weight model to new model parts, transfer-bind new model parts
  2. regional weight fix process
    1. pose to a better transfer_pose, duplicate new part at transfer_pose
    2. sculpt-deform-average the duplicated-copy of new part for better weight transfer catching
    3. from fixed-weight model to new clone part, and store new clone part weight
    4. apply clone part weight back to original new part
  • global_ctrl: guide_pose, binding_pose, zero_pose
    1. guide_pose: for building the automatic rig system,
      • for now, it is same as zero pose, as current 3rd-party rig builder only allow zero pose at guide pose
      • for now best, 0deg hands down w. 10deg z-axis elbow forward, and leg 0deg best
      • ideally, it is same as bind pose, but current 3rd-party rig builder don't allow zero pose different from guide pose
    2. binding_pose: for building the geometry, (catching geometries)
      • best, the arm 45deg outside, and leg split 45deg for best initial auto weight
    3. zero_pose: for publishing character at same zero pose, to fit universal animation library
      • everything straight out and 0 everything, use global offset ctrl to lift or lower for shoe height compensate
  • other utility script:
    • global_offset_ctrl: asMatch() - FK IK matching switch script

Function Library for Rigging

  • description: a procedure and module based rigging system, with all improved and re-implemented features of system like big in-house vfx rig systems
  • current complete list
    • modules:
      • path module
        • chain module

3rd Party tool to study


Commercial tools

Craft Director Studio http://www.craftanimations.com/

video ref

  • vimeo 32220149
  • youtube 4DyO_VS_3Gk

Human Rig

  • Human Rig
    # Human Rig 
    spine_chain = ["root", "spine1", "spine2", "spine3", "neck", "head", "skull"]
    arm_chain = ["clavicle", "shoulder", "elbow", "wrist", "palm"]
    leg_chain = ["hip", "knee", "ankle", "ball", "toe"]
    finger_names = ["thumb", "index", "middle", "ring", "pinky"]
    face_chain = ["jaw", "mouth"]
    face_names = ["eye", "eye_lid_upper", "eye_lid_lower"]
    # - position and joint local rotation value input
    # bind jnt for full feature
    finger_jnts = [name+str(num) for name in finger_names for num in (1,2,3) ] # 4th joint not for bind
    mirror_jnt_in_use = arm_chain[:-1] + leg_chain[:-1] + finger_jnts + face_names
    bindJnt= spine_chain[:-1] + face_chain[:-1] + [side+each for each in mirror_jnt_in_use for side in ('L_','R_') ] # cnt: 59
    # bind jnt for body feature
    mirror_jnt_in_use_body_only = arm_chain[:-1] + leg_chain[:-1] + face_names
    bodyJnt= spine_chain[:-1] + face_chain[:-1] + [side+each for each in mirror_jnt_in_use_body_only for side in ('L_','R_') ] # cnt: 29

Facial Rig for creatures

Rigging a Growing curve

  • possible method:
    • a motion path driven ctrls that driving the curves CV
      • bads: curve shape is changing even with a lot of driven cvs
    • Bezeir Curve math buidling methods
      • bads: complex curves requires a lot of calculation with more amount of CVs
  • detail of bezeir curve math method
    • a primary curve driven by curve defining Ctrls
    • a secondary curved with CVs driven by math of how curve plotted based on primary curves CVs with attribute controlling percentage of the plotting.
  • Nurbs curve, which is a kind of B-Spline curve, behave like bezeir curve when its degree is set to the highest, which also means its span=1.

Extra: Research on Knots and Knots Vector in Nurbs curve

  • A Non-Uniform Rational B-Spline curve is defined by three things:
    • Control points
    • The curve's order.
    • A knot vector : count = numberOfPoints(CV) + degree(order) - 1
  • Curves like Nurbs and Beziers are parametric curves. The curve is a function P(u) that returns a point P on the curve for a particular value of the parameter u. As u varies from initial value umin - towards umax the curve is drawn. Knots are defined in the parameter space of a curve. We’ll use the notation u-i to refer to a particular knot. The collection of knots for a particular curve is called the knot vector.
  • The knot vector determines where in the parameter range these polynomials start and stop as the curve is drawn. (They’re called “knots” because the values “tie together” the polynomials.)
  • magnitude of the knots doesn't make any difference. while ratios of the values to each other matter.
  • The knots define how the polynomial pieces are blended together with the proper smoothness
  • Common knot vector types
    • Pinned Uniform knot vector: The curve passes through the first control point, and ends up at the last control point, like [0 0 0 0 1 2 3 3 3 3]
    • Piecewise Bézier knot vector: arcs, lines or simple curve segments are strung together into a single

large curve, pass each order-number-th CN point, like [0 0 0 1 1 2 2 3 3 3]


Back to topics

  • code to generate grow curve and curve ctrl based on input curve.
    // mel
    global proc string[] shi_rig_cvToLocCtrlGrow(string $tmpC){
        /** curve to loc ctrl, and create up grow curve based on bezier function */
        /** nurbsCurve, aka b-spline behave like bezier when degree is set at highest, which means achieve span=1 */
        string $gcs[]=`duplicate -n ($tmpC+"_grow") $tmpC`;
        string $gc=$gcs[0]; // grow curve
        string $posLs[]; // pos cv locators
        string $growLs[]; // grow cv locators
        int $span=`getAttr ($tmpC+".spans")`;
        if($span!=1) print "\nNote: Best Fitting when working with Span=1 curve. Means Degree=CV_count - 1.\n";
        int $deg=`getAttr ($tmpC+".degree")`;
            string $t_posLs[]=`spaceLocator`;
            string $t_posL=$t_posLs[0];
            string $t_growLs[]=`spaceLocator`;
            string $t_growL=$t_growLs[0];
            float $pos[]=`xform -q -ws -t ($tmpC+".cp["+$i+"]")`;
            xform -ws -t $pos[0] $pos[1] $pos[2] $t_posL;
            xform -ws -t $pos[0] $pos[1] $pos[2] $t_growL;
            connectAttr ($t_posL+".worldPosition[0]") ($tmpC+".cp["+$i+"]");
            connectAttr ($t_growL+".worldPosition[0]") ($gc+".cp["+$i+"]");
            $t_posL=`rename $t_posL ($tmpC+"_posLoc_"+$i)`;
            $t_growL=`rename $t_growL ($tmpC+"_growLoc_"+$i)`;
        // expression linkage
        if(!objExists($tmpC+".grow")) addAttr -ln "grow" -k 1 -min 0 -max 1 -dv 0.5 $tmpC;
        string $exp="$g="+$tmpC+".grow;\n";
            $exp+="// vector for cv "+($i)+"\n";
            $exp+="vector $v_"+($i)+"_d_0= <<"+$posLs[$i]+".tx,"+$posLs[$i]+".ty,"+$posLs[$i]+".tz>>;"+"\n";
            for ($j=1;$j<=$i;$j++){
                $exp+="vector $v_"+($i)+"_d_"+($j)+"=($v_"+$i+"_d_"+($j-1)+"-$v_"+($i-1)+"_d_"+($j-1)+")*$g+$v_"+($i-1)+"_d_"+($j-1)+";\n";
        //print $exp;
        expression -s $exp  -o "" -n ($tmpC+"_GrowExp") -ae 1 -uc all ;
        string $growLocGrp=`group -em -n ($tmpC+"_growLocGrp")`;
        parent $growLs $growLocGrp;
        return {$gc,stringArrayToString($posLs,","),stringArrayToString($growLs,",")};
  • use Maya native node, subCurve node
    • as its name, it create subCurve of the whole curve based on start, end parameter

Demos of rig

Book rig:

Character rig:

Airplane rig:

Tank Track:

Car rig:

Robot rig:

Bird rig:

Worm rig:

Gear rig:

Hardware Dynamic


Lego soft: http://sr3dbuilder.altervista.org/

FX design soft: http://coral-app.com/

Rigging in real life

Problem and Solution

  • solution: make sure the initial placement of bones have a angle pointing to the pole vector direction.

  • group motion path and locator (ideally not the object direct, just parent constrain the locator to your following object, so model and follow system are seperate)
  • Turn off the following-locator's “Inherits Transform” off in Attribute editor
    int $i=1;
        setAttr ("yourFollowLocArray_"+$i+".inheritsTransform") 0;
  • then when you scale the group, path scales but locator position on the path stay the same, so no more double position scaling on the path

auto delay follow rig

  • the solution I used in work in expression
    float $delay=system_ctrl.offsetLegMove; // delay control as a attribute in main ctrl curve
    // delay the 2nd leg with ref to 1st leg
    leg_L_IK_2_ctrl.translateX=`getAttr -t (frame-$delay*1) leg_L_IK_1_ctrl.tx`;
    leg_L_IK_2_ctrl.translateY=`getAttr -t (frame-$delay*1) leg_L_IK_1_ctrl.ty`;
    leg_L_IK_2_ctrl.translateZ=`getAttr -t (frame-$delay*1) leg_L_IK_1_ctrl.tz`;
  • spline ik flipping issue with motion path ctrl:
    • “The movement should be free of unexpected flipping. However, flipping is unavoidable if the path is very complex.” -Maya doc

Resource and Tools


Joint position related

  • knee

Character rig

Curve related rig

  • related nodes:
    • rebuildCurve node, to dynamically cleanup curve

Book rig

Notes when Rigging For Game

Top checklist

  • less bones are better
  • single top node hierary
  • classic linear skinning method
  • per vertex weight max is 1
  • max influence is 1 for initial, set 1 for default binding
  • don't lock to max influence count, as some vertex need share between 2 bones

Feature List

  • Arm: FK, IK
  • Leg: FK, IK, Foot Roll
  • Head: follow, stay
  • Spine: IK

Construction Steps

  • build bone and skin
    • Joint setting:
      1. degree of freedom: x,y,z
      2. symmetry: x-axis if symmetric
      3. no scale compensate, no joint limit, no create IK handle
      4. orientation: xyz, secondary axis world orientation: +y
      5. bone radius setting: all same radius as 1
    • orient joint setting:
      1. orientation: xyz
      2. secondary world orientation: +y
      3. orient children as well
      4. reorient local scale axis
    • freeze setting:
      • T, R, S, uncheck joint orient, check normal
    • mirror joint setting:
      • YZ mirror
      • mirror by behavior

Important: the default maya joint tool and orient joint tool never get the orientation right if not in most ideal position

  1. Create Spine [root, spine1, spine2, spine3, neck, head, skull]
    • make sure only non-zero value is Tx, by orient the joint axis (pointing to its child)
    • for above, use orient joint tool
    • Note: X axis point to next bone, Root: like world; Spine: y axis point to -z (LefRig); Neck: y axis to +x (frobac)
  2. Create leg [hip, knee, ankle, ball, toe]
    • make sure, hip-knee-ankle align in 1 line in X axis, rotate hip to aim for ankle position
    • then rotate ankle to make foot align to ground
    • freeze joints to clear rotate value,
    • orient joint tool
    • Note: Left leg: z axis point to +z, y axis point to +x


  • spline IK setting:
    1. root on curve
    2. auto create curve, 2 span (5 cvs)
    3. linear twist
  • the spine Ik starts from spine1 (not root),


  • IK handle settings: (for leg)
    1. ikRPsolver
    2. solver enable
    3. snap enable
    4. 1, 1, 1
  • IK handle settings: (for foot)
    1. single chain solver


Rig Modules

  • To do
    • FK module
    • Spline module
    • Arm module
    • Leg module
    • Head module
    • Tail module
    • Wing module
  • Utility
    • speed
    • wheel

quick Mel Python codes in Rigging

  • basically a re-collection of mel tools that are more frequently used in rigging.

Basically, everything related to outliner.

  • get parent node
    each_parent = cmds.listRelatives(each_geo, p=1)[0] 
  • get all nodes you need
  • get master node from parentConstraint node (each_ps, each parentConstraint node)
    src = cmds.listConnections(each_ps+'.target[0].targetTranslate', d=0, s=1)[0]
  • get slave node from parentConstraint node
    tgt = cmds.listConnections(each_ps+'.constraintTranslateX', d=1, s=0)[0]

Toggle Switch

  • animation curve driven/setDrivenKey
    # toggle dmg/normal geo visibilty with main_ctrl.damaged switch
    cmds.setDrivenKeyframe( each_dmg +'.v', cd=main_ctrl+'.damaged', dv=0, v=0 )
    cmds.setDrivenKeyframe( each_dmg +'.v', cd=main_ctrl+'.damaged', dv=1, v=1 )
    cmds.setDrivenKeyframe( each_normal +'.v', cd=main_ctrl+'.damaged', dv=0, v=1 )
    cmds.setDrivenKeyframe( each_normal +'.v', cd=main_ctrl+'.damaged', dv=1, v=0 )
  • setRange node based
    each_range = cmds.createNode('setRange', n=each_damage+'_vis_setRange')
    cmds.connectAttr(main_ctrl+'.damaged', each_range+'.vx', f=1)
    cmds.connectAttr(main_ctrl+'.damaged', each_range+'.vy', f=1)
    cmds.connectAttr(each_range+'.ox', each_damage+'.v', f=1)
    cmds.connectAttr(each_range+'.oy', each_normal+'.v', f=1)
    cmds.setAttr(each_range+'.omx', 1)
    cmds.setAttr(each_range+'.mx', 1)
    cmds.setAttr(each_range+'.omy', 1)
    cmds.setAttr(each_range+'.ny', 1)
  • reverse node based
    cmds.connectAttr(main_ctrl+'.damaged', each_damage+'.v', f=1)
    each_reverse = cmds.createNode('reverse', n=each_damage+'_vis_reverse')
    cmds.connectAttr(main_ctrl+'.damaged', each_reverse+'.ix', f=1)
    cmds.connectAttr(each_reverse+'.ox', each_normal+'.v', f=1)
  • condition node based
    cmds.connectAttr(main_ctrl+'.damaged', each_damage+'.v', f=1)
    each_condition = cmds.createNode('condition', n=each_damage+'_vis_condition')
    cmds.connectAttr(main_ctrl+'.damaged', each_condition+'.ft', f=1)
    cmds.connectAttr(each_condition+'.ocr', each_normal+'.v', f=1)
    cmds.setAttr(each_condition+'.st', 1)
  • plusMinusAverage node based (same like reverse node)
    cmds.connectAttr(main_ctrl+'.damaged', each_damage+'.v', f=1)
    each_pma = cmds.createNode('plusMinusAverage', n=each_damage+'_vis_pma')
    cmds.setAttr(each_pma+'.input1D[0]', 1)
    cmds.connectAttr(main_ctrl+'.damaged', each_pma+'.input1D[1]', f=1)
    cmds.connectAttr(each_pma+'.o1', each_normal+'.v', f=1)
    cmds.setAttr(each_pma+'.op', 2)
  • expand selection by shell and vertex id, good for those dense geo with mult-geo combine, and you want to select a group of shells quickly.
    # select a vertex first, 
    # and run this 3 lines to convert selection into a shell selection 
    # and expand shell selection to next shells and continue 30 times.
    sl=expandSelectionByVid(cur[0], cur[1], 30)
    import maya.cmds as cmds
    def getBaseVid():
        return [vid, geo]
    def nextVid(vid, geo):
        return [vid+1, selected]
    def expandSelectionByVid(vid, geo, level):
        for i in range(level):
            next=nextVid(start_vid, geo)
        return selection

Maya Rigging and Character Setup

FK control means: you can only rotate those controls;
IK control means: you drag those controls.

situation solution
A control B, and B can move freely put B into a group as “bGrp”, then select A and bGrp, constrain > parent constrain with offset

To create

  1. only select the control curves that you want to animate
  2. go to Character menu > Create character set (check the box) > choose all keyable, give a name

To view

  1. select the character set in the Outliner
  2. go to Window > HyperGraph : Connection