ほとんどのアニメーションは、スケルトンにおいて事前に決められた値にジョイントを変更して、回転することで実現されます。子ジョイントの位置は、親の回転にもとづいて変化し、このため一連のジョイントの終了点は、角度および含まれる個々のジョイントの相対位置によって決定されます。このスケルトンのポージング手法は 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>();
}
//a callback for calculating IK
void OnAnimatorIK()
{
if(animator) {
//if the IK is active, set the position and rotation directly to the goal.
if(ikActive) {
// Set the look target position, if one has been assigned
if(lookObj != null) {
animator.SetLookAtWeight(1);
animator.SetLookAtPosition(lookObj.position);
}
// Set the right hand target position and rotation, if one has been assigned
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);
}
}
//if the IK is not active, set the position and rotation of the hand and head back to the original position
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 チェックボックスをクリックすると、キャラクターがオブジェクトを掴んだり離したりするのを見ることができます。プレイモード内で円筒をいろいろ動かして、腕や手がオブジェクトを追いかけるのを見てみましょう。