Version: 2017.3
ターゲットマッチング
ルートモーションの仕組み

IK

ほとんどのアニメーションは、スケルトンのジョイントを回転させ事前に決められた値に変更して作られます。子ジョイントの位置は、親の回転にもとづいて変化します。このため一連のジョイントの終了点は、角度および含まれる個々のジョイントの相対位置によって決定されます。このスケルトンのポージング手法は フォワードキネマティクス と呼ばれます。

ただし、ジョイントのポージングを行うタスクを別の視点からとらえることも、しばしば役に立ちます。例えば、空間で特定の点を決めてそこから逆算し、終了点が選択した位置になるように有効な方向にジョイントを向かせます。この方法は、選択した位置のオブジェクトをキャラクターにタッチさせたり、平らでない地面にキャラクターの足をつける、ということをする場合に役立ちます。このアプローチは インバースキネマティックス (IK )と呼ばれ、正しく設定されたアバターによる ヒューマノイドキャラクターの Mecanim でサポートされます。

キャラクターの IK を設定するには、通常は、キャラクターが相互作用するオブジェクトがシーンにあり、特に以下のような Animator 関数から IK を設定します。 SetIKPositionWeight, SetIKRotationWeight, SetIKPosition, SetIKRotation, SetLookAtPosition, bodyPosition, bodyRotation

上の画像で、キャラクターは円筒状のオブジェクトを握っています。どのようにしてこれを実現するのでしょうか。

まず、有効なアバターを持ったキャラクターを準備します。

次に、そのキャラクター用のアニメーションを少なくとも 1 つ含んだ Animator Controller を作成します。それから Animator ウィンドウの Layers ペインでレイヤー設定の歯車アイコンをクリックし、表示されたメニューの IK Pass チェックボックスをチェックします。

デフォルトレイヤーの IK Pass チェックボックスを設定
デフォルトレイヤーの 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 」というオブジェクト)を配置し、ちょうど良く回転させます。手はその子オブジェクトをターゲットにします。

空の ゲームオブジェクト が IK target の役割を果たすので、手はシリンダーオブジェクトの上に正しく置かれる
空の ゲームオブジェクト が IK target の役割を果たすので、手はシリンダーオブジェクトの上に正しく置かれる

ですから、この Cylinder Grab Handle ゲームオブジェクトを IKControl スクリプトの Right Hand Obj プロパティーとして割り当てます。

この例では、視線のターゲットをシリンダーに設定します。そのため、ハンドルが底の方にある場合でも、キャラクターは直接オブジェクトの中心を見ます。

再生モードにすると、IK が動き出します。 Ik Active チェックボックスをクリックすると、キャラクターがオブジェクトを握ったり離したりするのを見ることができます。再生モードで円筒をいろいろ動かして、腕や手がオブジェクトに合わせて動くのを確認してみましょう。

ターゲットマッチング
ルートモーションの仕組み