8
\$\begingroup\$

I'm curious about how this sort of animation is typically done code-wise.

A few examples:

\$\endgroup\$
4
\$\begingroup\$

This is called inverse kinematics. Google is probably your best friend on this one as it can get complex.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I get it, I have to calculate the motions necessary to achieve a desired position. In this case, I would only calculate the motions for the desired bone. \$\endgroup\$ – Gerstmann Jul 25 '11 at 9:59
  • \$\begingroup\$ Indeed, the video description says "...an animation system based entirely on inverse kinematics..." \$\endgroup\$ – MichaelHouse Jul 25 '11 at 22:43
0
\$\begingroup\$

Original Article: How to Code an IK System

Sometimes the IK that is built into Unity is not enough. I’m going to show you how to build your own IK script for Unity. You can apply this IK to any articulated body — fingers, hands, or feet. The IK that I’m going to review is currently used by Unity, Unreal, Panda, and several other game engines. It is called FABRIK.

FABRIK is an iterative method. An iterative method is a method that does not get the solution right away. An iterative method gets closer and closer to the correct solution with more iterations of the method — in other words, iterations of a loop.

Any IK problem has a given articulated body (a set of connected limbs with lengths and angles). The end effector (the position of the endpoint of the final limb) has a start position with a goal position. It might have other goals, such as angles.

Each FABRIK iteration has two main parts.

void FABRIK() {
    while( abs(endEffectorPosition — goalPosition) > EPS ) {
        FinalToRoot(); // PartOne
        RootToFinal(); // PartTwo
    }
}

The first part iterates from the final limb to the root limb. For the final limb, you need to change the angle/rotation of the limb to point at the goal position (keeping the inboard position anchored, and letting the outboard position be translated by the angle change). Next, you translate the final limb along the updated angle towards the goal position, until the limb’s outboard position equals the goal position (maintaining the angle, but letting the limb’s inboard position change). That’s pretty much it for the final limb, except that you now need to update the current goal position. The current goal position is now set to the updated inboard position of the final limb.

For each consecutive inboard limb, you do the same thing. To be clear I will outline it. For the current limb, you need to change the angle/rotation of the limb to point towards the current goal position. Next, you translate the current limb along the updated angle towards the current goal position, until the limb’s outboard position equals the current goal position. Finally, you update the current goal position to be equal to the updated inboard position of the current limb.

Repeat these operations until you’ve completed these operations on the root limb. After that, the first part has been completed.

/* Part One */
void FinalToRoot() {
    currentGoal = goalPosition;
    currentLimb = finalLimb;
    while (currentLimb != NULL) {
        currentLimb.rotation = RotFromTo(Vector.UP,
            currentGoal — currentLimb.inboardPosition);
        currentGoal = currentLimb.inboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

The second part iterates in the reverse direction: from the root limb to the final limb. For the root limb, you need to update its inboard position to the root position. This should translate the whole limb (without stretching). That’s pretty much it for the root limb, except that you now need to update the current inboard position. The current inboard position is now set to the updated outboard position of the root limb. For each consecutive outboard limb, you do the same thing. To be clear I will outline it. For the current limb, you need to update its inboard position to the current inboard position. This should translate the whole limb. That’s pretty much it for the current limb, except that you now need to update the current inboard position. The current inboard position is now set to the updated outboard position of the current limb.

Repeat these operations until you’ve completed these operations on the final limb. After that, the second part has been completed.

/* Part Two */
void RootToFinal() {
    currentInboardPosition = rootLimb.inboardPosition;
    currentLimb = rootLimb;
    while (currentLimb != NULL) {
        currentLimb.inboardPosition = currentInboardPosition;
        currentInboardPosition = currentLimb.outboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

Once the first part and the second part have been completed, you have completed the first iteration of the FABRIK method. Continue iterating on part one and two until the end effector is as close as you need it to be to the goal position, defined by some EPS (epsilon value).

That’s it! That’s the FABRIK method. Part One iterates backwards from the final limb. Part Two iterates forward from the root limb. The FABRIK method iterates Part One and Part Two until the end effector is close enough to the goal position.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.