ほとんどのアニメーションは、スケルトンにおいて事前に決められた値にジョイントを変更して、回転することで実現されます。子ジョイントの位置は、親の回転にもとづいて変化し、このため一連のジョイントの終了点は、角度および含まれる個々のジョイントの相対位置によって決定されます。このスケルトンのポージング手法は Forward Kinematics (フォワードキネマティクス)と呼ばれます。
しかし、ジョイントのポージングを行うタスクを別の視点からとらえることが、しばしば役に立ちます。空間で特定の点を決めて、そこから逆算して、終了点がその位置に到着するようにジョイントの向きを決める有効な方法を見つけます。オブジェクトをユーザーにより選択された点をタッチさせる、または平らでない地面に足をつける、といったことをキャラクターにしてほしいときに、これは便利です。このアプローチは Inverse Kinematics (IK)と呼ばれ、Mecanim で 正しく設定されたアバターのある ヒューマノイドキャラクターにおいてサポートされます。
キャラクターの IK をセットアップするためには、通常はシーンに相互作用をさせたいオブジェクトがあり、キャラクターの IK をスクリプトを通じて、具体的には次のような Animator 関数を通じて、セットアップします。 SetIKPositionWeight、 SetIKRotationWeight、 SetIKPosition、 SetIKRotation、 SetLookAtPosition、 bodyPosition、 bodyRotation
上図において、キャラクターは棒の形のオブジェクトを握っています。これをどのようにして実現するのでしょうか。
まず、有効な Avatar (アバター)を持ったキャラクターから始めます。
次に、そのキャラクター用のアニメーションを少なくとも 1 つ含んだ Animator Controller を作成します。それから Animator ウィンドウの Layers 表示枠でそのレイヤーの設定の歯車アイコンをクリックし、ポップアップメニューの IK Pass チェックボックスをチェックします。
キャラクターの Animator コンポーネントに Animator Controller が割り当てられていることを確認してください。
次に IK を実際に処理するスクリプトをアタッチします。仮にそれを IKControl と呼びましょう。このスクリプトが、キャラクターの右手の IK ターゲットと、持っているオブジェクトを見ているような視線の位置を設定します。
using UnityEngine;
using System;
using System.Collections;
[RequireComponent(typeof(Animator))]
public class IKControl : MonoBehaviour {
protected Animator animator;
public bool ikActive = false;
public Transform rightHandObj = null;
public Transform lookObj = null;
void Start ()
{
animator = GetComponent<Animator>();
}
// IK を計算するためのコールバック
void OnAnimatorIK()
{
if(animator) {
// IK が有効ならば、位置と回転を直接設定します
if(ikActive) {
// すでに指定されている場合は、視線のターゲット位置を設定します
if(lookObj != null) {
animator.SetLookAtWeight(1);
animator.SetLookAtPosition(lookObj.position);
}
// 指定されている場合は、右手のターゲット位置と回転を設定します
if(rightHandObj != null) {
animator.SetIKPositionWeight(AvatarIKGoal.RightHand,1);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand,1);
animator.SetIKPosition(AvatarIKGoal.RightHand,rightHandObj.position);
animator.SetIKRotation(AvatarIKGoal.RightHand,rightHandObj.rotation);
}
}
//IK が有効でなければ、手と頭の位置と回転を元の位置に戻します
else {
animator.SetIKPositionWeight(AvatarIKGoal.RightHand,0);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand,0);
animator.SetLookAtWeight(0);
}
}
}
}
キャラクターの手が円筒オブジェクトの内部にめりこまずに円筒の表面に置かれるための空の子オブジェクト(この例では「 Cylinder Grab Handle 」というオブジェクト)を配置し、ちょうど良く回転させます。手はその子オブジェクトをターゲットにします。
この “grab handle” ゲームオブジェクト は IKControl スクリプトの “Right Hand Obj” プロパティーとしてアサインします。
この例では、視線ターゲットが円筒オブジェクト自体に設定されているので、キャラクターの手が円筒を持つ位置に関係なくキャラクターは円筒オブジェクトの中心をまっすぐ見ています。
プレイモードに入ると、IK が動き出します。 IKActive チェックボックスをクリックすると、キャラクターがオブジェクトを掴んだり離したりするのを見ることができます。プレイモード内で円筒をいろいろ動かして、腕や手がオブジェクトを追いかけるのを見てみましょう。