Aearon

05-12-2007, 09:00 PM

I sat down this weekend and tried to figure out a formula for countering IK-pop, the effect of an IK joint chain ‘snapping’ into position when approaching full stretch, using a function that would work for any joint chain consisting of two bones, without fine-tuning any set driven keys or reactions, as I’ve seen it in some rigs and used to do it myself.

I just want to share the following solution that i came up with. it works for any chain length as far as i've tested and also with uneven joint lengths.

Basically it counters the exponential speed increase of the middle joint by exponentially stretching the two joints as the chain approaches full stretch.

You can see the effect of this function here, the red line is the trajectory of the middle joint when the IK goal moves away from the start joint at constant speed. The spacing between the keys gives you an idea of it's speed. Without the function applied, the speed of the joint increases exponentially, resulting in the familiar snapping effect. With the function applied the motion is much smoother.

http://www.aearon.de/files/public/smoothik.gif

The code

initLenA = 50.0 -- initial length of the first bone

initLenB = 50.0 -- initial length of the second bone

startDist = 0.965 -- the normalized distance at which the stretch will start

endDist = 1.059 -- the normalized distance at which the stretch will end

mult = 0.0295 -- multiplier for the stretch effect

exp = pi/2 -- exponent for the stretch effect

-- momentary distance between first bone and ik goal

dist = distance ikGoal firstBone

-- divide distance by sum of initial bone lengths (so dist equals 1 when chain is just fully stretched)

dist /= initLenA+initLenB

-- scale dist from [startDist,endDist] to [0,1] so we can apply an exponent to it and use it as a multiplier for the stretch function

blendVal = dist - startDist

blendVal /= (endDist - startDist)

if blendVal < 0.0 then blendVal = 0.0

if blendVal > 1.0 then blendVal = 1.0

-- stretch function

return ((initLenA+initLenB) * mult * blendVal^exp)

The resulting value is added to the initial length of both bones.

Note that this is not an auto-stretch solution, it only stretches the chain as far as it needs to achieve smooth motion. Automatic stretching can be implemented on top of this. The stretching of the chain is practically invisible in motion. the stretching is fairly subtle so it hardly changes the proportions of a character.

I just want to share the following solution that i came up with. it works for any chain length as far as i've tested and also with uneven joint lengths.

Basically it counters the exponential speed increase of the middle joint by exponentially stretching the two joints as the chain approaches full stretch.

You can see the effect of this function here, the red line is the trajectory of the middle joint when the IK goal moves away from the start joint at constant speed. The spacing between the keys gives you an idea of it's speed. Without the function applied, the speed of the joint increases exponentially, resulting in the familiar snapping effect. With the function applied the motion is much smoother.

http://www.aearon.de/files/public/smoothik.gif

The code

initLenA = 50.0 -- initial length of the first bone

initLenB = 50.0 -- initial length of the second bone

startDist = 0.965 -- the normalized distance at which the stretch will start

endDist = 1.059 -- the normalized distance at which the stretch will end

mult = 0.0295 -- multiplier for the stretch effect

exp = pi/2 -- exponent for the stretch effect

-- momentary distance between first bone and ik goal

dist = distance ikGoal firstBone

-- divide distance by sum of initial bone lengths (so dist equals 1 when chain is just fully stretched)

dist /= initLenA+initLenB

-- scale dist from [startDist,endDist] to [0,1] so we can apply an exponent to it and use it as a multiplier for the stretch function

blendVal = dist - startDist

blendVal /= (endDist - startDist)

if blendVal < 0.0 then blendVal = 0.0

if blendVal > 1.0 then blendVal = 1.0

-- stretch function

return ((initLenA+initLenB) * mult * blendVal^exp)

The resulting value is added to the initial length of both bones.

Note that this is not an auto-stretch solution, it only stretches the chain as far as it needs to achieve smooth motion. Automatic stretching can be implemented on top of this. The stretching of the chain is practically invisible in motion. the stretching is fairly subtle so it hardly changes the proportions of a character.