Supporting Additional Joints

If your character’s skeleton possesses one or more joints that are not directly mapped in the list of supported Nodes within HumanIK, you can still use HumanIK to control that character, as long as the character contains at a minimum all of the Nodes required by HumanIK. Your character may contain any number of these unknown additional joints. However, because the HumanIK solvers base their calculations on a built-in knowledge of how certain pre-defined joints of biped and quadruped skeletons function, and your character’s unsupported joints fall outside the range of joints that HumanIK understands, the solvers will be unable to translate or rotate the unsupported joints directly.

The consequences of this depend on whether you use global space or local space to exchange animation data between HumanIK and your game engine.

Using global space

When you use global space to exchange animation data between HumanIK and your game engine, you can support additional unknown joints by taking the positions and rotations calculated by the HumanIK solvers for the Nodes they understand (i.e. those listed in the HIKNodeId enumeration), and calculating new positions and rotations for your additional unknown joints based on those values.

Using local space

Local space expresses each Node’s translation, orientation and scaling data relative to its parent Node. Although HumanIK works internally in a normalized global space, it allows you to use local space transformations when using a data set to set or retrieve the translation, rotation and scaling of Nodes in an HIKCharacterState. See Data Set Functions for HIKCharacterState Data.

If your character’s skeleton contains joints unknown to HumanIK, the translation and rotation of those unknown joints will affect the local space of its child joints in the skeleton. For example, if your character is a robot with an extra arm joint between the shoulder and the elbow, the rotation of that extra joint will affect the position and rotation of the elbow Node (which in turn will affect the global position and orientation of the wrist Node, the hand Node, and all fingers).

If your unknown joints are at the end of a joint chain, you may be able to support them transparently simply by applying the HIKCharacterState generated by the HumanIK solvers back to your game character using local space transformations. For example, consider a character that has a series of tail joints unknown to HumanIK, whose ultimate parent is the HumanIK waist Node. If a HumanIK solver moves or rotates the waist Node, applying the local space transformation of the waist Node back to the game character will likely allow the tail to move and rotate along with the waist Node, even though it is not directly controlled by HumanIK.

However, if your unknown joint lies in between two HumanIK joints, such as the robot with the extra elbow described above, you need to define a parent offset for the HumanIK Node that is the child of the unknown joint. This parent offset defines the effect of the unknown parent joint on the local rotation, translation and scaling of the Node. For example, to continue the scenario introduced above, the robot’s elbow joint would need to have a parent offset defined, whose rotation, translation and scaling matches the local space of the extra joint just above the elbow in the skeletal hierarchy. The translation, rotation and scaling values you set for this parent offset should be defined relative to the next HumanIK joint up the skeletal hierarchy from the unknown joint.

Step 1: Setting up the HIKCharacterDefinition

To set up a parent offset for a Node, you must first indicate in your HIKCharacterDefinition at initialization time that the Node has an unknown parent. Set the value of the mUsedNode element corresponding to each desired Node to HIKNodeParentOffset. This causes HumanIK to allocate extra memory in which to store the parent offset of the designated Node in each HIKCharacter created from the HIKCharacterDefinition. For details, see Initialization.

Note that this is only necessary for Nodes that do not have Degrees of Freedom assigned. Assigning Degrees of Freedom to a Node by setting the value of its mUsedNode element to HIKNodeLimits automatically allocates memory for a parent offset. See Degrees of Freedom.

Step 2: Setting up the HIKCharacter

The parent offset of the Node is maintained in your HIKCharacter. If the offset changes (e.g. the extra joint extends or compresses, or moves to a different translation relative to its own parent), you must update the parent offset. This will effectively result in moving all the HumanIK Nodes below the parent offset in the skeletal hierarchy.

To set the parent offset for a Node that has a parent joint unknown to HumanIK, call the HIKSetParentOffsetfv() function. For details on the parameters expected by this function, see the API Reference.

For example:

HIKSetParentOffsetfv(MyHIKCharacter, RightElbowNodeId,
                                     lParentTOffset.mData,
                                     lParentQOffset.mData,
                                     lParentSOffset.mData);