Category: rigging

Problem of followAlign

I’m animating my character doing a somewhat like somersault action, with cog control rotating over 360º forward. Also I’m having followAlign ON so that I can adjust the upper body without affecting the arms orientation. Unluckily my character’s arms flip when the body is about to turn over 180º. Stewart of AM has the same problem, though.

Having a look, I see one of the rotation values of the orient-constrained joint jump suddenly, either from 180º to -179º or -180º to 179º. Interestingly it doesn’t jump visually. But sure it will if you are using the value directly in your setup. So my solution is to use the rotation channels of the actual control ( the upper arm FK controls in my case ), not the orient-constrained joint.

My case is not very common actually. It’s great that the fix is simple. Having too many compromises while animating a character could be frustrated and not fun at all. Moreover, this is not something crazy to do to a rig yet.


Soft IK

If you haven’t heard of soft IK before, please read http://www.softimageblog.com/archives/108. Andy Nicholas explains the problem very clearly. Essentially it adds a “soft” distance and slow down the movement causing the pop with a formula. Andy showed this in Softimage but the idea works anywhere.

Below are some lines of expression showing the ideas in maya. They are running node-based in my final rig but making the setup works in expression first is faster for me.

// -----------------------------------------------------------
//     $d : current distance betw ends
//     $D : initial distance betw ends
//     $S : IK softness
//
//     softJ_start & softJ_end
//         a 2-joint chain with it's IK parented under e.g. foot ctrl
//         the main IK is point constrainted to softJ_end
// -----------------------------------------------------------

float $S = ctrl.soft;
float $D_soft = $D - $S;
float $new_d = $d;

if ( $d > $D_soft ) {
    float $x = $d - $D_soft;
    $new_d = $D_soft + $S *( 1-exp(-$x) );
}

softJ_end.ty = $new_d;

Pole vector maths

In my old rig, the lower limbs rotate in single plane only. That simplifies the story. Just put a locator under the FK lower limb, having the same world position as the pvCtrl at initial pose. Snapping to FK means snapping the pvCtrl to this locator because the rotate plane is always correct.

But I want rig like Stewart, where the lower limbs can rotate sideway. This involves simple vector maths.

global proc vector calcPvWPos( string $P1, string $P2, string $P3 ) {
 
     vector $a = `xform -q -ws -t $P1`;
     vector $b = `xform -q -ws -t $P2`;
     vector $c = `xform -q -ws -t $P3`;
 
     vector $AC = $c - $a;
     vector $AB = $b - $a;
 
     // projV = (|b|cos@) ^AC = (a.b/|a|) ^AC
     vector $projV = ( dotProduct($AC,$AB,0) / mag($AC) ) * `unit $AC`;
 
     vector $pvDirV = unit($AB - $projV);
 
     // move it out a bit
     return ( $b + mag($AB) * $pvDirV );
}

Pose mirror/flipping

I have seen a few “intelligent” scripts which are able to mirror/flip controls of arbitrary setup. They are great if you have to use other people’s rig. I’m now making my own rig so I prefer a simpler way.

I add a string attribute named “mirrorCode” to every control to be mirrored/flipped. e.g. “100011”. The order is for tx ty tz rx ry rz and a “1” means negation. My scripts can scan through this attribute and know which axis to negate. Nothing to detect and easy to debug !

global proc float[] getMirrorXform ( string $ctrl, string $code ) {
 
    vector $t = `getAttr ($ctrl + ".t")`;
    vector $r = `getAttr ($ctrl + ".r")`;
    float $tr[] = { $t.x, $t.y, $t.z, $r.x, $r.y, $r.z };
 
    for ($i=1; $i<=6; $i++) {
       if (`substring $code $i $i` == 1) {
          $tr[$i-1] *= -1;
       }
    }
    return $tr;
}

Better space switching

I learned about space switching years ago. I did’t think there was problem until recently …

How about having a prop control, that can drive the hand or the other way round ?

Of course I’m not setting each other as their “space” target. The evil cycle warning still shows because the target is having connections to all the space groups, no matter active or not. My solution is to add an extra loop of SetDrivenKey in space switching codes, setting nodeState of unused space groups to “block“.

// ----------------------------------------------
//   Block unused space groups
// ----------------------------------------------
for ($i=0; $i<`size $space`; $i++) {
     for ($j=0; $j<`size $spaceG`; $j++) {
         string $state = ($i == $j) ? 0 : 2;
         setDrivenKeyframe -cd "ctrl.space" -dv $i -at "nodeState" -v $state $spaceG[$j];
     }
 }

Space switching + fk/ik snapping

Finally, space switching and fk/ik snapping work using scriptJob. Mel procedures are stored in scriptNode and called by scriptJob once the file is loaded. This is the method I learned by breaking Stewart of Animation Mentor.

The trickest part is “keyable” space switching. Since I’m using scriptJob’s “attributeChange” event, if the “space” attribute is directly keyed, scrubbing the timeline will change the value and unexpectedly invoke the proc.

My solution is to move the keys to another attribute.

  1. Create the space switching attribute, “space”, as non-keyable and hidden.
  2. Create another attribute, “spaceNow”, which is keyable, driving original “space” ( as a space indicator and not to be changed directly by user ).
  3. Create one more attribute, “spaceSwitch”, which is non-keyable, used to change space non-pop, and used by attributeChange event.

Having attributes in single control I could key the transform and space at once. This avoids missing selection or keys if I want to adjust timing later.

By the way, you still need to use the copy and paste worldspace fix if the position of control changes before or after the switching frame.


Rotate Order

Arrrr . . . it’s been a while doing bunch of various stuff. Finally I got sth to share while scripting my autorig system.

Usually I don’t care about gimbal lock since I discovered the “euler filter” button in graph editor. And I always thought that better rotate order means cleaner animation curves only. Recently I found another case showing the importance of proper rotate order.

Imagine a standard 3-joint IK arm (say, left arm) with simple pole vector setup. When the character moves his arm ( ikHandle ) forward and about to the right, the upper arm joint’s rotation would pop from (0, -89.x, 0) to crazy values like (180, -89.x, -180). It took me a while to think about it . . .

A better rotate order seems to help.

Here is the best gimbal lock explanation I’ve seen https://www.youtube.com/watch?v=zc8b2Jo7mno.



Fatal error: Out of memory (allocated 127926272) (tried to allocate 256 bytes) in /home/nickyliu/www/www/wp-content/plugins/wp-statistics/vendor/browscap/browscap-php/src/phpbrowscap/Browscap.php on line 769