FinalIK(VRIK)+LeapMotion Core Assets v4.1.4でMMDの指を動かす

[前回の記事](http://qiita.com/miyumiyu/items/94faaabac4eeab975a0d)からしばらく時間がたって、LeapMotionのCoreAssetsもバージョンが上がりこの通りやっても動かない上に[FinalIK](https://www.assetstore.unity3d.com/jp/#!/content/14290)もVRIKという便利なコンポーネントが追加されましたのでこちらを使ってMMDの指を動かすのをやりたいと思います。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">操作が難しい・・・<br>上目遣いで上を見る→画面が見えない<br>VRじゃないけどVRIKを使ってみました <a href="https://t.co/Z0toVGk3dp">pic.twitter.com/Z0toVGk3dp</a></p>&mdash; みゅみゅ (@miyumiyuna5) <a href="https://twitter.com/miyumiyuna5/status/807170592042459136">2016年12月9日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

こんな感じに指を動かします。

### 1.準備

- [mmd4mecanim](http://stereoarts.jp/)をいれる
- [FinalIK](https://www.assetstore.unity3d.com/jp/#!/content/14290)をいれる
- [LeapMotion Core Assets v4.1.4](https://developer.leapmotion.com/unity)を入れる
- LeapMotion Add-on Modulesで[Hands Module v1.0.0](https://developer.leapmotion.com/unity)を入れる  
※この中で必要なのは
 - RiggedFinger
 - RiggedHand  
この２つのスクリプトだけです。
- 好きなモデルを入れてUnityで扱える状態にしておきます

### 2.LeapHandcontrollerでFinalIKを扱えるスクリプトの作成

前回はFullBodyIKコンポーネントを使いましたが今回はVRIKコンポーネントを使います。

```csharp:FinalIKOrionLeapHandController.cs
/**
FinalIKを使ったLeapMotion Orion用HandController
 (VRIKバージョン)
Author: MiyuMiyu
*/

using UnityEngine;
using Leap.Unity;
using RootMotion.FinalIK;

public class FinalIKOrionLeapHandController : LeapHandController
{
    [SerializeField]
    private VRIK vrIK;

    public bool ikActive = true;
    public bool leftActive = false;
    public bool rightActive = false;

    public GameObject avatarLeftHand;   //keeps track of the left hand gameobject for IK
    public GameObject avatarRightHand;  //keeps track of the right hand gameobject for IK
    [HideInInspector]
    public HandModel leftHand;
    [HideInInspector]
    public HandModel rightHand;

    protected virtual void Awake()
    {
        if (vrIK == null)
        {
            vrIK = gameObject.transform.root.GetComponent<VRIK>();
        }
        if (vrIK == null)
        {
            Debug.LogError("FinalIKOrionLeapHandController:: no FullBodyBipedIK found on GameObject or any of its parent transforms. ");
        }

        if (leftHand == null && avatarLeftHand != null)
            leftHand = avatarLeftHand.GetComponent<RiggedHand>();
        if (rightHand == null && avatarRightHand != null)
            rightHand = avatarRightHand.GetComponent<RiggedHand>();

        if (leftHand == null)
            Debug.LogError("IKOrionLeapHandController::Awake::No Rigged Hand set for left hand parameter. You have to set this in the inspector.");
        if (rightHand == null)
            Debug.LogError("IKOrionLeapHandController::Awake::No Rigged Hand set for right hand parameter. You have to set this in the inspector.");

        // Physic Handは使用しないのでDisableにする
        physicsEnabled = false;
    }

    //    protected override void Start()
    protected virtual void Start()
    {
        provider = GetComponent<LeapProvider>();
        if (provider == null)
        {
            Debug.LogError("IKOrionLeapHandController::Start::No Leap Provider component was present on " + gameObject.name);
            Debug.Log("Added a Leap Service Provider with default settings.");
            gameObject.AddComponent<LeapServiceProvider>();
        }
    }

    public void FixedUpdate()
    {
        if (graphicsEnabled)
        {
            UpdateHandRepresentations();

            if (ikActive)
            {
                if (leftActive && leftHand != null)
                {
                    RiggedHand l = leftHand as RiggedHand;

                    vrIK.solver.leftArm.IKPosition = leftHand.GetPalmPosition();
                    vrIK.solver.leftArm.IKRotation = leftHand.GetPalmRotation() * l.Reorientation();
                    vrIK.solver.leftArm.positionWeight = 1.0f;
                    vrIK.solver.leftArm.rotationWeight = 1.0f;
                }
                else
                {
                    vrIK.solver.leftArm.positionWeight = 0.0f;
                    vrIK.solver.leftArm.rotationWeight = 0.0f;
                }

                if (rightActive && rightHand != null)
                {
                    RiggedHand r = rightHand as RiggedHand;

                    vrIK.solver.rightArm.IKPosition = rightHand.GetPalmPosition();
                    vrIK.solver.rightArm.IKRotation = rightHand.GetPalmRotation() * r.Reorientation();
                    vrIK.solver.rightArm.positionWeight = 1.0f;
                    vrIK.solver.rightArm.rotationWeight = 1.0f;
                }
                else
                {
                    vrIK.solver.rightArm.positionWeight = 0.0f;
                    vrIK.solver.rightArm.rotationWeight = 0.0f;
                }
            }
        }
    }

    /// <summary>
    /// Tells the hands to update to match the new Leap Motion hand frame data. Also keeps track of
    /// which hands are currently active.
    /// </summary>
    void UpdateHandRepresentations()
    {
        leftActive = false;
        rightActive = false;
        foreach (Leap.Hand curHand in provider.CurrentFrame.Hands)
        {
            if (curHand.IsLeft)
            {
                leftHand.SetLeapHand(curHand);
                leftHand.UpdateHand();
                leftActive = true;
            }
            if (curHand.IsRight)
            {
                rightHand.SetLeapHand(curHand);
                rightHand.UpdateHand();
                rightActive = true;
            }
        }
    }
}

```

### 3.モデルにFinalIKのVRIKコンポーネントを入れる

モデルにFinalIKのVRIKを入れます
（コンポーネントをそのままドラック＆ドロップでOK）
![fa1.png](https://qiita-image-store.s3.amazonaws.com/0/79067/9d5744b9-6c79-e9be-800b-ace91bf655e5.png)

その際に、手を前に出した時に勝手に歩かれると困るのでLocomotionのWeightを0にするのがよろしいかと
![fa2.png](https://qiita-image-store.s3.amazonaws.com/0/79067/abfdaabd-acc8-7d5d-0f94-f4e5747d431c.png)


### 4.モデルにLeapMotion関連のスクリプトを置く

LeapMotion関係のコンポーネントを置いていくのですが
ヘッドマウントディスプレイにLeapMotionを置く　→　モデルのheadあたり
机の上にLeapMotionを置く　→　モデルのTorso、Torso2あたり

そのあたりに子オブジェクトしてLeapMotion関連のコンポーネントを作成していきます

※今回は机の上にLeapMotionを置く設定となります。

モデルのTorso2の子オブジェクトになるようの空のゲームオブジェクトを作成
そのゲームオブジェクトの名前を【LeapSpacer】という名前にしてその子供にもう一つ空のゲームオブジェクトを作成し名前を【LeapMotion】として、その中に必要なスクリプトを置きます。
（場所の微調整は【LeapSpacer】で行います）

![fa3.png](https://qiita-image-store.s3.amazonaws.com/0/79067/fef7b3ba-ace9-fe84-dd11-275aba840e48.png)

LeapSpacerのポジションは若干前に出して、ローテションはすべて0です。

![fa4.png](https://qiita-image-store.s3.amazonaws.com/0/79067/d2f326e5-77ca-5c7a-796b-32f250cd38fe.png)

LeapMotionに必要なスクリプト
- LeapServiceProvider
- FinalIKOrionLeapHandController（さっき作ったやつ）
- HandPool  
を入れます

![fa5.png](https://qiita-image-store.s3.amazonaws.com/0/79067/7d6701e3-19e0-bfc8-5c0d-6aee0a054d2d.png)

FinalIKOrionLeapHandControllerの設定は
- IK Activeにチェック
- Avatar Left Hand 、Avatar Right Handにモデルに手（Wrist）を入れる

### 5.モデルの手と指を地道に設定する

モデルの手にRiggedHand、指それぞれにRiggedFingerを入れて設定していきます

右手（RightWrist)
![b65a78d90b6dbb60336f1e841c35c5cd.png](https://qiita-image-store.s3.amazonaws.com/0/79067/6d5b77ba-cbdd-2cb3-f360-78d139655dba.png)

右手の指（親指以外）
![9602bdb200e1c78bf3488f4d6adffb62.png](https://qiita-image-store.s3.amazonaws.com/0/79067/c07cfe58-293f-11eb-f923-2becb43e3d1a.png)
（Jointsはいらない。　FingerTypeとElementは指に合わせて適宜変更）

右手の指（親指）
![44adcf584dfda15128a6070b6fc22ff6.png](https://qiita-image-store.s3.amazonaws.com/0/79067/85e7073d-1136-e0bc-bad8-dac5554ba846.png)

左手（LeftWrist)
![1f38d6c7ff733946118077f5b92088f8.png](https://qiita-image-store.s3.amazonaws.com/0/79067/c02120ce-c499-41b4-7c7c-c5dc57baab21.png)

左手の指（親指以外）
![5fb7d6a4da4af70f4f212f4377bf6986.png](https://qiita-image-store.s3.amazonaws.com/0/79067/9c2c471d-2844-6def-10f6-0e25c5e25aa9.png)
（Jointsはいらない。　FingerTypeとElementは指に合わせて適宜変更）

左手の指（親指）
![994df4d5485d12e2dfcabc3d63afbcd0.png](https://qiita-image-store.s3.amazonaws.com/0/79067/6631df93-7670-e209-648f-c34780f45783.png)

### 設定完了
これでたぶん動くはず
ちゃんと動けばこんな感じに動きます

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LeapMotionの方が楽！<br>口の形をまじめに反映させてみました。 <a href="https://t.co/EvGSQ3OluF">pic.twitter.com/EvGSQ3OluF</a></p>&mdash; みゅみゅ (@miyumiyuna5) <a href="https://twitter.com/miyumiyuna5/status/807081410678820864">2016年12月9日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

この例では、頭の位置や回転をWebcamで取得してVRIKに反映させています。
（ついでに表情も）

VRIK使うと色々便利！