Inverse Kinematics Solving

The following sections outline the process required to calculate a new position for your character using the HumanIK inverse kinematics solver.

Step 1. Updating the HIKCharacterState

When you call the HumanIK inverse kinematics solver to alter the movements your character carries out during the course of a forward-kinematics animation, you typically take the current stance of your character at each frame as a starting point. You provide this current stance in the HIKCharacterState you created in the initialization phase.

The inverse kinematics solver takes this current stance into account when evaluating the Reach constraints set for each Effector. For example, setting a Reach Translation of 0.5 for the character’s left knee Effector will place the character’s left knee Node half-way between the translation you specify for the left knee Effector and the translation of the left knee Node contained in this HIKCharacterState. See Reach.

HumanIK provides several options for synchronizing the Nodes of your HIKCharacterState with the current FK position and rotation of the character’s joints in the game engine. For detailed information on all the available options, see Setting and Retrieving Animation Data.

One common method is to call the HIKSetNodeStateTQSfv() function for each Node in the HIKCharacterState(). This function requires the following arguments:

For example:

HIKSetNodeStateTQSfv (MyCharacter, MyCharState, RightHandNodeId,
                                             myModel.GetTranslation(RightHandNodeId), 
                                             myModel.GetQuatRotation(RightHandNodeId), 
                                             myModel.GetScaling(RightHandNodeId));

Step 2. Setting positions and rotations for Effectors

Each frame, you must set up the HIKEffectorSetState to contain the desired position and rotation of each of your character’s limbs. You do not have to set the position and rotation of all Effectors, only those that you specify as goal points by setting non-zero values for the Reach Translation or Reach Rotation constraints. Other Effectors are effectively ignored by the inverse kinematics solver; their positions and orientations have no effect upon the final solution.

You can set the position and rotations of your Effectors using either of the following approaches:

Setting positions and rotations for Effectors directly

HumanIK provides several options for setting the three-dimensional position and orientation of your Effectors. For detailed information on all the available options, see Setting and Retrieving Animation Data.

One common method is to call the HIKSetEffectorStateTQSfv() function for each Effector in the HIKEffectorSetState. This function requires the following arguments:

  • A pointer to your HIKEffectorSetState.
  • The unique ID of the Effector you want to manipulate. This Effector ID may be any value listed in the HIKEffectorId enumeration in the humanik.h file.

    Note that this Effector ID is not the same as the Node ID of the corresponding joint that you specified when creating your HIKCharacterDefinition.

  • Three separate arrays of four floating-point numbers that represent the translation, quaternion rotation and scaling values of the Effector.

The translation, orientation and scaling values you set in your HIKEffectorSetState are expected to be expressed in the normalized space used by HumanIK for its internal calculations. For Nodes that contain no rotation or scaling offsets in the character’s default T-stance, this normalized space is exactly equivalent to global space. For Nodes that do contain rotation or scaling offsets in the character’s default T-stance, you may need to call the HIKSetCharacterSpaceEffectorStateTQSfv() function instead if you are using the Effector to set a desired orientation or scaling for your character. For additional details on normalized space, see Setting and Retrieving Data in HIKEffectorSetStates.

For example:

HIKSetEffectorStateTQSfv (MyEffectorSet, RightHandEffectorId, targetTranslation,
                                                              targetQuatRotation,
                                                              targetScaling);

Initializing the Effector Set from an HIKCharacterState

You can set the positions and rotations of the Effectors in your HIKEffectorSetState to match the Nodes within an HIKCharacterState. After this initialization, you can apply an offset to the translation and rotation of selected Effectors.

This is a common approach in the following scenarios:

To initialize an Effector Set from an HIKCharacterState, call the HIKEffectorSetFromCharacter function. This function requires the following arguments:

For example:

HIKEffectorSetFromCharacter (MyChar, MyEffectorSet, MyCharState, MyPropertySet);

Once you have initialized the HIKEffectorSetState, you can modify the position and rotation of each Effector by retrieving its matrix using the HIKGetEffectorStateTQSfv() function, applying offsets to the values returned, and re-applying the modified values using the HIKSetEffectorStateTQSfv() function. For example:

const float trans[4];
const float quatRot[4];
const float scale[4];
HIKGetEffectorStateTQSfv (MyEffectorSet, RightHandEffectorId, trans, quatRot, scale);
...  // offset trans, quatRot and/or scale values here  
HIKSetEffectorStateTQSfv (MyEffectorSet, RightHandEffectorId, trans, quatRot, scale);

Step 3. Setting constraints for Effectors

You can control the Reach Translation, Reach Rotation, Pull and Resist values individually for each Effector in your HIKEffectorSetState.

By default, each of these constraints is set to a value of 0; this will cause the inverse kinematics solver to pin all of your character’s joints to the stance expressed in the HIKCharacterState you provide to the solver, which typically contains the current FK stance of the character. In order to have the inverse kinematics solver take your Effectors into account, you must set new values for these constraints using the following functions:

These functions all require the following arguments:

For example, the following lines will result in the right hand moving halfway to the position of its Effector, pulling the rest of the body if necessary, while the right elbow tends to maintain its original angle:

HIKSetTranslationActive(MyEffectorState, RightHandEffectorId, 0.5f);
HIKSetPull(MyEffectorState, RightHandEffectorId, 1.0f);
HIKSetResist(MyEffectorState, RightElbowEffectorId, 0.75f);

Step 4. Setting the solving step

The inverse kinematics solving process is broken down into several steps, each of which calculates new positions for a selected joint chain, the effect of a constraint such as Pull, or the result of a special transformation such as floor contact (see Foot and Hand Contact) or Squash ’n’ Stretch (see Using Squash 'n' Stretch).

To determine the solving steps that will performed by the inverse kinematics solver, call the HIKSetIKSolvingStep() function. This function takes two arguments:

For example:

You can specify multiple solving steps listed in the HIKSolvingStep enumeration by concatenating them with the | operator (bitwise OR). For example:

Step 5. Setting up Character Properties

You can control many different aspects of the HumanIK inverse kinematics solver by changing the configuration settings in your HIKPropertySetState.

HIKPropertySetStates are initialized with a coherent set of default values, so you do not have to change any values in order to get HumanIK working. This step is optional. However, you can often achieve better and more realistic results by setting property values appropriate to each of your characters. This is especially true of character properties that maintain scalar distance values, as the default values of these properties are sized for a character approximately 180 units tall.

For detailed information on the configuration options available for your characters, and how to set values for these options, see Character Properties.

Step 6. Launching the solver

To launch the HumanIK inverse kinematics solver, call the HIKSolveForEffectorSet function. This function requires the following arguments:

For example:

HIKSolveForEffectorSet (MyChar, MyCharState, MyEffectorSet, MyPropertySet);

Step 7. Retrieving the generated HIKCharacterState

The inverse kinematics solver stores the pose it generates for your character in the same HIKCharacterState you passed in as an argument. You must retrieve the translation, orientation and scaling of each Node in this HIKCharacterState, and apply it back to your game engine character.

HumanIK provides several options for retrieving the three-dimensional position and rotation of the Nodes in an HIKCharacterState. For detailed information on all the available options, see Setting and Retrieving Animation Data.

One common method of retrieving the pose calculated for the character is to call the HIKGetNodeStateTQSfv() function for each Node in the HIKCharacterState. This function requires the following arguments:

For example:

const float trans[4];
const float quatRot[4];
const float scale[4];
HIKGetNodeStateTQSfv (MyCharState, RightHandNodeId, trans, quatRot, scale); 
... // apply retrieved values back to game engine here 

It is up to you to re-apply the retrieved values for each Node back to the corrensponding joint of the character in your game engine.