View Full Version : knee popping, possible fix?

06 June 2011, 01:02 AM
Hey guys,

While doing a walk cycle I notice that the rig I made knee's are popping, and it's a pain to try and go in to smooth it. I've asked a few of my animator friends, and they said that Bishop had something that helped with this, and "soft IK". Seeing as I can't get bishop, and I'm not finding too much stuff on soft IK, is there a way to help with the popping of this? Not sure if this helps, but I do have stretchy legs made with an expression.

06 June 2011, 01:36 PM
You can create your own soft IK by taking the output rotations from the IK solver and using a function curve to slow them down as they approach the max extension values... basically making the IK controlled items not reach to the goal as solidly at angles approaching full extension.

You can also set up another lil trick to limit (clamp) the rotations to make the IK "stop" at a point of extension before the pop occurs, and then constrain the end item to the goal so it pulls away (positionally) from its parent, giving the effect of a full reach.... or perhaps forget the constraint and use a shape tied to the IK roations to make the geo appear to have reached full extension even when the IK controlled items haven't done so.

Either method is ofc an imperfect cheat, and can take a bit of tweaking to make it appear natural and correct, but that's the basic idea for you.

Cactus Dan
06 June 2011, 12:50 AM

The way I like to do it is add just a little squash to the IK joints as the leg is pushing back, and use a slider to smoothly blend between normal and squash:

I'm not sure how you'd set that up in your application, though, because I use my CD Character Rigging plugins for Cinema 4D that I've developed, and I've built that right into the IK. ;)

Cactus Dan

06 June 2011, 01:02 AM
I actually have squash and stretch in my legs. So, I need to find some way to blend them. Thanks!

Cactus Dan
06 June 2011, 01:15 AM

You're welcome. ;)

Normally, it'll only need to squash about 3.5% (0.035) of the total length to get rid of the popping, so it's not noticeable at all.

Cactus Dan

06 June 2011, 08:52 AM
How I solved it, is by having two different methods for interpolating the joints. One is traditional (letting the IK figure them out, with or without soft-IK), and the other is to have the angles in the joints fixed (and animatable). This way, the animator is controlling how the joints bend, and not the IK. It is not ideal (fidling with attributes), but I think it is a very solid method for the times when soft-IK doesnt give a satisfying result.


06 June 2011, 02:29 AM
I started using motionbuilder as a way of avoiding this problem-although I ended up working with mo cap walks mostly so havent put it to the test-but you can rotate the joints freely so I would think one could get that pendulum foot swing effect which is what one needs for a good walk. When I did my first animation the popping knee was very annoying-I wasnt sure if I was imagining a problem or not.

06 June 2011, 12:48 PM
A user on here was kind enough to share a maya file containing a soft-IK node-based setup with me, which I delved through & converted to a python script. Unfortunately I don't have the original message, so I can't give credit where it's due, but I believe it was based on this (

Since this forum wont let me attach .zip or .py files, I'll paste it in here. *angry face*

import maya.cmds as cmds
import math

def doIt(prefix, joints, control, twistAxis):

prefix - Prefix string attached to all nodes
joints - List of joints in chain. e.g. ['Shoulder_Joint', 'Elbow_Joint', 'Wrist_Joint']
control - ...
twistAxis - Axis pointing down the joint chain. Setup requires this. Typically x, but y, z will work.

import softIK
softIK.doIt('left_arm', ['joint1', 'joint2', 'joint3'], 'left_arm_control', 'x')

Attributes (added to control):
Stretch - Toggles stretching
Soft - Adjusts amount of softness, adjust as required


# Find the full length of all joints
length = 0
for i in range(1, len(joints)):
length += abs(cmds.getAttr(joints[i]+'.t'+twistAxis))

cmds.addAttr(control, longName='stretch', defaultValue=0, minValue=0, maxValue=1, keyable=True)
cmds.addAttr(control, longName='soft', at='double', defaultValue=0.001, minValue=0.001, maxValue=10, keyable=True)

# Create distance node & locators

startLocator = cmds.spaceLocator(name=prefix+'startDistLoc')
cmds.pointConstraint(joints[0], startLocator)
cmds.setAttr(startLocator[0]+'.visibility', 0)

endLocator = cmds.spaceLocator(name=prefix+'endDistLoc')
cmds.pointConstraint(control, endLocator)
cmds.setAttr(endLocator[0]+'.visibility', 0)

distLocGroup =, name=prefix+'distLoc_grp')
cmds.parent(startLocator, endLocator, distLocGroup)

distanceNode = cmds.createNode('distanceBetween', name=prefix+'distanceBetween')
cmds.connectAttr(startLocator[0]+'.translate', distanceNode+'.point1')
cmds.connectAttr(endLocator[0]+'.translate', distanceNode+'.point2')

defaultDist = cmds.getAttr(distanceNode+'.distance')

# Build node network

mdn1 = cmds.createNode('multiplyDivide', name=prefix+'soft_IK_01_mult_mdn')
cmds.connectAttr(control+'.soft', mdn1+'.input1X')
cmds.setAttr(mdn1+'.input2X', -1)

pma1 = cmds.createNode('plusMinusAverage', name=prefix+'soft_IK_plus_pma')
cmds.setAttr(pma1+'.input1D[0]', length)
cmds.connectAttr(mdn1+'.outputX', pma1+'.input1D[1]')

pma2 = cmds.createNode('plusMinusAverage', name=prefix+'soft_IK_01_minus_pma')
cmds.setAttr(pma2+'.operation', 2)
cmds.connectAttr(pma1+'.output1D', pma2+'.input1D[0]')
cmds.connectAttr(distanceNode+'.distance', pma2+'.input1D[1]')

mdn2 = cmds.createNode('multiplyDivide', name=prefix+'soft_IK_01_div_mdn')
cmds.setAttr(mdn2+'.operation', 2)
cmds.connectAttr(pma2+'.output1D', mdn2+'.input1X')
cmds.connectAttr(control+'.soft', mdn2+'.input2X')

mdn3 = cmds.createNode('multiplyDivide', name=prefix+'soft_IK_pow_mdn')
cmds.setAttr(mdn3+'.operation', 3)
cmds.setAttr(mdn3+'.input1X', math.e)
cmds.connectAttr(mdn2+'.outputX', mdn3+'.input2X')

mdn4 = cmds.createNode('multiplyDivide', name=prefix+'soft_IK_02_mult_mdn')
cmds.connectAttr(control+'.soft', mdn4+'.input1X')
cmds.connectAttr(mdn3+'.outputX', mdn4+'.input2X')

pma3 = cmds.createNode('plusMinusAverage', name=prefix+'soft_IK_02_minus_pma')
cmds.setAttr(pma3+'.operation', 2)
cmds.setAttr(pma3+'.input1D[0]', length)
cmds.connectAttr(mdn4+'.outputX', pma3+'.input1D[1]')

cdn1 = cmds.createNode('condition', name=prefix+'soft_IK_cdn')
cmds.setAttr(cdn1+'.operation', 4)
cmds.connectAttr(distanceNode+'.distance', cdn1+'.firstTerm')
cmds.connectAttr(distanceNode+'.distance', cdn1+'.colorIfTrueR')
cmds.connectAttr(pma1+'.output1D', cdn1+'.secondTerm')
cmds.connectAttr(pma3+'.output1D', cdn1+'.colorIfFalseR')

mdn5 = cmds.createNode('multiplyDivide', name=prefix+'soft_IK_02_div_mdn')
cmds.setAttr(mdn5+'.operation', 2)
cmds.connectAttr(distanceNode+'.distance', mdn5+'.input1X')
cmds.connectAttr(cdn1+'.outColorR', mdn5+'.input2X')

for i in range(1, len(joints)):
mdn = cmds.createNode('multiplyDivide', name=prefix+'soft_IK_multiply_0%s_pma' % i)
translateValue = cmds.getAttr(joints[i]+'.t' + twistAxis)
cmds.setAttr(mdn+'.input1X', translateValue)
cmds.connectAttr(mdn5+'.outputX', mdn+'.input2X')
b2a = cmds.createNode('blendTwoAttr', name=prefix+'soft_IK_0%s_b2a' % i)
cmds.setAttr(b2a+'.input[0]', translateValue)
cmds.connectAttr(mdn+'.outputX', b2a+'.input[1]')
cmds.connectAttr(control+'.stretch', b2a+'.attributesBlender')
cmds.connectAttr(b2a+'.output', joints[i]+'.t' + twistAxis)

return distLocGroup

06 June 2011, 03:03 AM
Didn't have my computer for a few days, so sorry for the delay.

Thank you to everyone that has given me suggestions. You guys rock!


CGTalk Moderation
06 June 2011, 03:03 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.