Springheadでは,IKに使用する各関節をアクチュエータと呼びます.IKは,アクチュエータを駆動させて剛体を目標位置に到達させます.
<オブジェクト関係図>
IKエンジンはアクチュエータを複数保持し,各アクチュエータが各関節を保持します.アクチュエータオブジェクト一つにつき,関節が一つ対応します. アクチュエータオブジェクトの具体的な役割は,関節の状態をIKエンジンに伝え,IKの計算のうち関節ヤコビアンの計算など関節ごとに行う部分を実行し,IKの計算結果に従って関節を動かす事です.
本稿執筆時点では,IK用アクチュエータとして使用できるのはヒンジとボールジョイントのみです. それぞれに対応したアクチュエータクラスがあります.
PHIKHingeActuatorはPHHingeJointに対するアクチュエータです.ヒンジジョイントの1自由度を駆動に用います.
PHIKBallActuatorはPHBallJointに対するアクチュエータです.ボールジョイントは3自由度の関節ですが,後述するエンドエフェクタの姿勢制御を行わない(エンドエフェクタの位置のみを制御する)場合は,エンドエフェクタの位置を変化させることのできる2自由度のみを駆動に用います(使用する2自由度の軸は1ステップごとに更新されます).
// given PHSceneIf* phScene PHIKHingeActuatorDesc descIKActuator; PHIKHingeActuatorIf* ikActuator = phScene->CreateIKActuator(descActuator);
アクチュエータを作成するには,PHSceneIfのCreateIKActuator関数を用います.引数はアクチュエータのディスクリプタです.PHIKHingeActuatorDesc型のディスクリプタを渡すとヒンジ用のアクチュエータが作成され,PHIKBallActuatorDesc型のディスクリプタを渡すとボールジョイント用のアクチュエータが作成されます.
作成された時点では,アクチュエータは関節と対応付けがされていません.アクチュエータの子要素に関節を登録することで対応付けが行われます.
// given PHHingeJointIf* joint ikActuator->AddChildObject(joint);
次のように二股に分岐したリンクを例にとります:
計算上,IKで駆動する関節系は木構造でなければなりません. Springheadでは,アクチュエータの親子関係を作ることで関節の木構造を設定します.
// given PHIKActuator ikActuator1, ikActuator2 ikActuator1->AddChildObject(ikActuator2);
AddChildObjectを呼び出すと,アクチュエータに対し「子要素」となるアクチュエータを登録することができます. これを全てのアクチュエータに対して行うことでアクチュエータの木構造が設定されます.このときアクチュエータの親子関係は,前出の図の右側のようになります.
関節の運動は,IK機能によって計算された目標関節角速度を関節にSetTargetVelocityすることで実現します. 目標速度に関する関節の振る舞いは,関節のdamperパラメータによって変化します.一般にdamperが大きいほど関節は固くなり,外乱の影響を受けづらくなります.この性質はそのままIKの振る舞いにも受け継がれます.
通常,IKは全ての関節を可能な限り均等に使用して目標を達成するよう計算されます. 一方,キャラクタの動作に用いる場合などで,手先を優先的に動かし胴体はあまり動かさない,といった重み付けが要求される場面があります.
SpringheadのIKには,このような重み付けを設定することができます.
// given PHIKActuator ikActuator1, ikActuator2 ikActuator1->SetBias(2.0); ikActuator2->SetBias(1.0);
SetBiasは,指定した関節をあまり動かさないように設定する関数です.Biasには以上の値を設定します.大きな値を設定した関節ほど,IKによる動作は小さくなります.デフォルトではどのアクチュエータもとなっており,全関節が均等に使用されます.