以下操作过程使用在 HumanIK API 中提供的函数,以编程方式创建新的 HIKCharacter 并设置其角色化。
在您尝试在自己的代码中执行该角色化过程之前,应先阅读并理解本文档以下部分中的内容:
必须为角色创建 HIKCharacterDefinition:即确定根据该定义创建的所有 HIKCharacter 中存在的节点或关节的蓝图。
该类包含一个主要成员:mUsedNode,它是一个整数阵列,其中包含在 HIKNodeId 枚举中列出的每个可能预先确定的关节的元素。必须创建 HIKCharacterDefinition 类的实例,然后设置 mUsedNode 阵列中每个元素的值,以指示是否应在 HIKCharacterDefinition 中使用相应的节点 ID。
要将节点 ID 标记为将在 HIKCharacterDefinition 中使用,请将 mUsedNode 阵列中相应元素的值设置为 HIKNodeUsed。要将节点 ID 标记为在 HIKCharacterDefinition 中未使用,请将 mUsedNode 索引中相应元素的值设置为 HIKNodeNotUsed。
例如,以下代码示例显示一种典型方法,用来创建 HIKCharacterDefinition 并初始化要用于根据该定义创建的所有 HIKCharacter 的节点。
// 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; }
在特定情况下还会使用 HIKNodeUsed 和 HIKNodeNotUsed 的两个备选方法:
您的 HIKCharacterDefinition 必须至少启用 HumanIK 所需的全部十五个节点。请参见将关节映射到 HumanIK 节点和效应器。
要根据在初始化步骤中创建的 HIKCharacterDefinition 来创建 HIKCharacter,请调用 HIKCharacterCreate() 函数。此函数需要以下参数:
HIKCharacter * MyChar = HIKCharacterCreate(&MyDef, &malloc, AutodeskCustomerString, AutodeskCustomerKey); if (MyChar == 0) { // the character could not be created. Handle the error here. }
新创建的 HIKCharacter 仅包含在 HIKCharacterDefinition 中设置了 HIKNodeUsed、HIKNodeLimits 或 HIKNodeParentOffset 标志的关节。
如果 HIKCharacterCreate() 函数返回空指针,则最有可能是许可证密钥或角色定义出现问题。请参见疑难解答以获取帮助。
此时,您已经具有一个已初始化一组关节(如踝部、膝部、肘部等)的角色。但是,您必须进一步定义角色的骨架,方法是在角色以默认 T 形站姿站立时提供每个关节的平移、旋转和缩放。有关该 T 形站姿的详细信息,请参见默认 T 形站姿。
通过为角色使用的每个节点调用 HIKSetCharacterizeNodeStateTQSfv() 函数,您可以提供这些默认位置和旋转。此函数需要以下参数:
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); } }
作为 HIKSetCharacterizeNodeStateTQSfv() 的备选方法,您可以调用 HIKSetCharacterizeNodeStatefv() 函数,它接受以 4x4 变换矩阵表示的平移、方向和缩放值。有关该矩阵的详细信息,请参见变换矩阵。
如果要设置角色节点的自由度,以限制其旋转到不适当的或不切实际的外形,则必须在此时设置限制。
请注意,只能为通过在 HIKCharacterDefinition 中向其指定 HIKNodeLimits 标志而指定的那些节点设置自由度。请参见上面的步骤以编程方式角色化 HIKCharacter。
要设置角色的自由度,请对每个所需的节点调用 HIKSetLimitsfv() 函数。有关接受的参数的详细信息,请参见 API 参考中的函数说明。请注意,自由度始终在局部空间中指定,并且必须以弧度而非度为单位。
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);
有关详细信息,请参见自由度。
为 HIKCharacter 使用的每个节点提供适当的平移、旋转和缩放值后,必须通过调用 HIKCharacterizeGeometry() 函数,并将指针传递到 HIKCharacter 来完成角色的几何体。
bool result = HIKCharacterizeGeometry(MyChar); if (result == false) { // The characterization was unsuccessful; handle the error. }
完成角色化后,HIKCharacter 即可供使用。继续执行在初始化中列出的步骤,以设置您的角色所需的其他 HumanIK 对象。
如果 HIKCharacterizeGeometry() 函数返回 false,则最有可能是角色的 T 形站姿出现问题。请参见疑难解答以获取帮助。