Characterizing an HIKCharacter Programmatically

The following procedure creates a new HIKCharacter and sets up its characterization programmatically, using functions provided in the HumanIK API.

Before you attempt to carry out this characterization process in your own code, you should read and understand the material in the following sections of this documentation:

Step 1. Creating an HIKCharacterDefinition

You must create an HIKCharacterDefinition for your character: a blueprint that identifies which Nodes, or joints, will be present in all HIKCharacters created from that definition.

This class contains one main member: mUsedNodes, an array of integers that contains an element for each possible pre-determined joint listed in the HIKNodeId enumeration. You must create an instance of the HIKCharacterDefinition class, and set the value of each element in the mUsedNodes array to indicate whether or not the corresponding Node ID should be used in the HIKCharacterDefinition.

To flag a Node ID to be used in your HIKCharacterDefinition, set the value of the corresponding element in the mUsedNode array to HIKNodeUsed. To flag a Node ID as unused in the HIKCharacterDefinition, set the value of the corresponding element in the mUsedNode index to HIKNodeNotUsed.

For example, the following code example shows a typical method of creating an HIKCharacterDefinition and initializing the Nodes that will be used for all HIKCharacters created from that definition.

// first, create an array containing the Node IDs 
// that represent joints you want to use. This example uses only
// the mandatory Node Ids required by HumanIK, listed below. 
int gCharacterJointTotal = 15;
const int fJointIds[] = {HipsNodeId, 
                         LeftHipNodeId,
                         LeftKneeNodeId,
                         LeftAnkleNodeId,
                         RightHipNodeId, 
                         RightKneeNodeId,
                         RightAnkleNodeId, 
                         WaistNodeId,
                         LeftShoulderNodeId,
                         LeftElbowNodeId,
                         LeftWristNodeId,
                         RightShoulderNodeId,
                         RightElbowNodeId,
                         RightWristNodeId,
                         HeadNodeId};

// Next, create an HIKCharacterDefinition object, and initialize
// its memory space to 0 (or HIKNodeNotUsed). 
HIKCharacterDefinition MyDef;
memset(&MyDef, 0, sizeof(HIKCharacterDefinition));

// Finally, iterate through the array of Node IDs to be used, and 
// set the corresponding element in the mUsedNodes array to 
// HIKNodeUsed. 
int ii; 
for (ii = 0; ii < gCharacterJointTotal; ++ii) 
{ 
   MyDef.mUsedNodes[fJointIds[ii]] = HIKNodeUsed;
} 

Two alternatives to HIKNodeUsed and HIKNodeNotUsed are also used in specific situations:

Your HIKCharacterDefinition must enable at a minimum all fifteen Nodes required by HumanIK. See Mapping Joints to HumanIK Nodes and Effectors.

Step 2. Creating an HIKCharacter from the HIKCharacterDefinition

To create an HIKCharacter based on the HIKCharacterDefinition you created in step Initialization, call the HIKCharacterCreate() function. This function requires the following arguments:

For example:

HIKCharacter * MyChar = HIKCharacterCreate(&MyDef, &malloc, AutodeskCustomerString, AutodeskCustomerKey); 
if (MyChar == 0)
{
    // the character could not be created. Handle the error here.
}

The newly created HIKCharacter contains only the joints set with the HIKNodeUsed, HIKNodeLimits or HIKNodeParentOffset flags in the HIKCharacterDefinition.

If the HIKCharacterCreate() function returns a null pointer, you most likely have a problem with either your license key or your character definition. See Troubleshooting for help.

Step 3. Setting up the geometry of the HIKCharacter

At this point, you have a character initialized with a set of joints such as ankles, knees, elbows, etc. However, you must further define your character’s skeleton by providing the translation, rotation and scaling of each of its joints when the character is standing in a default T-stance. For details on this T-stance, see The Default T-Stance.

You can provide these default positions and rotations by calling the HIKSetCharacterizeNodeStateTQSfv() function for each Node used by your character. This function requires the following arguments:

For example:

float trans[4];
float quat[4];
float scale[4];
for (ii = 0; ii < LastNodeId; ++ii) 
{ 
   if (sSuccess == fJointIds.find(ii)) 
   { 
      HIKSetCharacterizeNodeStateTQSfv(MyChar, ii, trans, quat, scale); 
   }
} 

As an alternative to HIKSetCharacterizeNodeStateTQSfv(), you can call the HIKSetCharacterizeNodeStatefv() function, which accepts translation, orientation and scaling values expressed in a 4x4 transform matrix. For details on this matrix, see Transform Matrices.

Step 4. Set up Degrees of Freedom (optional)

If you want to set Degrees of Freedom on your character’s Nodes, to restrict them from rotating into undesirable or unrealistic configurations, you must set the limits at this time.

Note that you can only set Degrees of Freedom for Nodes that you have designated by assigning them the HIKNodeLimits flag in your HIKCharacterDefinition. See step Characterizing an HIKCharacter Programmatically above.

To set your character’s Degrees of Freedom, call the HIKSetLimitsfv() function for each desired Node. See the function description in the API Reference for details on the accepted parameters. Note that Degrees of Freedom are always specified in local space, and must be provided in radians, not in degrees.

For example:

const float minValues[] = {0.0f, 0.7854f, 0.0f};
const float maxValues[] = {1.571f, 1.571f, 0.0f};
const float preRot[] = {0.0f, 0.0f, 0.0f, 1.0f};
const float postRot[] = {0.0f, 0.0f, 0.0f, 1.0f};

HIKSetLimitsfv (MyCharacter1, RightKneeNodeId, minValues, maxValues, preRot, postPost, HIKActiveMinX | HIKActiveMaxX | HIKActiveMinY | HIKActiveMaxY, HIKOrderEulerXYZ);

For more information, see Degrees of Freedom.

Step 5. Finalize the characterization

Once you have provided appropriate translation, rotation and scaling values for each Node used by your HIKCharacter, you must finalize your character’s geometry by calling the HIKCharacterizeGeometry() function, and passing a pointer to your HIKCharacter.

For example:

bool result = HIKCharacterizeGeometry(MyChar);
if (result == false)
{ 
    // The characterization was unsuccessful; handle the error. 
}

Once you have finalized the characterization, your HIKCharacter is ready for use. Continue with the steps listed under Initialization to set up the other HumanIK objects required for your character.

If the HIKCharacterizeGeometry() function returns false, you most likely have a problem with your character’s T-stance. See Troubleshooting for help.