Search code examples
pythonanimationmaya

Driving constraint weights from user-editable start and end keyframes in Maya


I'm trying to drive a constraint's 0-1 via particular start and end keyframes set on another object. These start and end keyframe positions can be changed by the animator.

For example if the first key on the object is frame 10 and the last is frame 100, the constraint would be at strength 0 on frame 10, and then strength 1 at frame 100.

Likewise, if the first key on the object is at 0 and the last is at 20, the constraint would be at strength 0 on frame 0, and then strenth 1 at frame 20.

Ideally the constraint could read in the anim curve, too so it could be a linear transition, slow-in, etc.

The main problem I'm having is how to get the start and end keyframes read in dynamically so that if the user changes their times, the constraint weights updates. It seems like expressions might be the way to go, but I get the sense they would be slower to playback. I'm not a fan of script jobs but that might be a way to go as well. I guess what I'm looking for at the end of the day is the output values of the start and end keyframes from an animCurve.


Solution

  • This one is a bit tricky because the usual methods - expressions or driven keys -- won't work properly: the 'start' and 'end' of an animation curve are not attributes that can be accessed in the usual way.

    You can try it with an expression that uses getAttr to grab the key times. Here's a basic example:

    float $start = `getAttr pCube1_translateX.keyTimeValue[0].keyTime`;
    float $end =  `getAttr pCube1_translateX.keyTimeValue[1].keyTime`;
    float $pct = (frame - $start) / ($end - $start);
    $pct = clamp(0, 1, $pct);
    float $lerp =  linstep(0, 1, $pct);
    pCube2.translateZ = $lerp;
    

    That will move pCube2 along Z between 0 and 1 during the interval between the first and second keys on pCube1's translateX channel.

    This works -- but it's super fragile unless you want to extend it to get the number of keys and update the index value in $end every frame.

    I'd suggest flipping the problem on it's head and driving both item off a 3rd, artificial parameter somewhere. Then you can use more conventional expressions or SDKs.