FinalIK+LeapMotion Core Assets v4.1.1でMMDの指を動かす

# FinalIK+LeapMotion Core Assets v4.1.1でMMDの指を動かす

えぇ [afjkさん](http://qiita.com/afjk/items/e2c9617e937528feba6e#_reference-763434dc21485fa31833)の真似です。
LeapMotionのCore Assets v4.1.1になってからなんか色々とnamespaceや関数が微妙に変わってる気がするのですが如何でしょうか？
（気のせいかなぁ。。。ちゃんと調べろと。。。）
めんどくさいのでFinalIKを直接叩いて動かしてしまえーってのが趣旨です。
指を動かす時の手順やパラメータが複雑なのでメモ書きも兼ねてこの記事です。

### 1.準備

- [mmd4mecanim](http://stereoarts.jp/)をいれる
- [FinalIK](https://www.assetstore.unity3d.com/jp/#!/content/14290)をいれる
- [LeapMotion Core Assets v4.1.1](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を扱えるスクリプトの作成

こんな感じで継承して作成（かなり適当）

```csharp:FinalIKOrionLeapHandController.cs
/**
FinalIKを使ったLeapMotion Orion用HandController

Author: MiyuMiyu
*/

using UnityEngine;
using Leap.Unity;
using Leap;
using System.Collections.Generic;
using RootMotion.FinalIK;

public class FinalIKOrionLeapHandController : LeapHandController
{

    [SerializeField]
    private FullBodyBipedIK fullbodyIK;

    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(fullbodyIK == null)
        {
            fullbodyIK = gameObject.transform.root.GetComponent<FullBodyBipedIK>();
        }
        if(fullbodyIK == 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()
    {
        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>();
        }

    }

    void Update()
    {
        if (graphicsEnabled)
        {
            UpdateHandRepresentations();

            if (ikActive)
            {

                if (leftActive && leftHand != null)
                {

                    RiggedHand l = leftHand as RiggedHand;

                    fullbodyIK.solver.leftArmMapping.weight = 1.0f;
                    fullbodyIK.solver.leftArmMapping.maintainRotationWeight = 1.0f;

                    fullbodyIK.solver.leftHandEffector.positionWeight = 1.0f;
                    fullbodyIK.solver.leftHandEffector.rotationWeight = 1.0f;
                    fullbodyIK.solver.leftHandEffector.position = leftHand.GetPalmPosition();
                    fullbodyIK.solver.leftHandEffector.rotation = leftHand.GetPalmRotation() * l.Reorientation();
                    fullbodyIK.solver.leftArmChain.bendConstraint.weight = 1.0f;

                }
                else
                {
                    fullbodyIK.solver.leftArmMapping.weight = 0.0f;
                    fullbodyIK.solver.leftArmMapping.maintainRotationWeight = 0.0f;
                    fullbodyIK.solver.leftHandEffector.positionWeight = 0.0f;
                    fullbodyIK.solver.leftHandEffector.rotationWeight = 0.0f;
                    fullbodyIK.solver.leftArmChain.bendConstraint.weight = 0.0f;
                }

                if (rightActive && rightHand != null)
                {

                    RiggedHand r = rightHand as RiggedHand;

                    fullbodyIK.solver.rightArmMapping.weight = 1.0f;
                    fullbodyIK.solver.rightArmMapping.maintainRotationWeight = 1.0f;
                    fullbodyIK.solver.rightHandEffector.positionWeight = 1.0f;
                    fullbodyIK.solver.rightHandEffector.rotationWeight = 1.0f;
                    fullbodyIK.solver.rightHandEffector.position = rightHand.GetPalmPosition();
                    fullbodyIK.solver.rightHandEffector.rotation = rightHand.GetPalmRotation() * r.Reorientation();
                    fullbodyIK.solver.rightArmChain.bendConstraint.weight = 1.0f;

                }
                else
                {
                    fullbodyIK.solver.rightArmMapping.weight = 0.0f;
                    fullbodyIK.solver.rightArmMapping.maintainRotationWeight = 0.0f;
                    fullbodyIK.solver.rightHandEffector.positionWeight = 0.0f;
                    fullbodyIK.solver.rightHandEffector.rotationWeight = 0.0f;
                    fullbodyIK.solver.rightArmChain.bendConstraint.weight = 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を入れる

モデルにFinalIKのFullBodyBipedIKを入れます
（コンポーネントをそのままドラック＆ドロップでOK）
![a13347b4a7dbbd1b4b433116417d786c.png](https://qiita-image-store.s3.amazonaws.com/0/79067/ace46bcf-bdc1-0919-9cdf-ce6d7aeceba4.png)

### 4.モデルの目（頭のあたり）にLeapMotion関連のスクリプトを置く

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

![648a4d1c839e072451c481d406241e5a.png](https://qiita-image-store.s3.amazonaws.com/0/79067/48a1cc30-cbdd-5551-fd7c-f96434f8389f.png)

LeapSpacerのポジションは若干前に出して、ローテションは図の通りになります。
![2c2ee76790c5f8fbc553bc1e545a31a7.png](https://qiita-image-store.s3.amazonaws.com/0/79067/c9bf6ef3-c112-ea37-aa6a-3f81624bcbcf.png)

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

![63316525f003b5a69476deb0f11f76ae.png](https://qiita-image-store.s3.amazonaws.com/0/79067/e4d36bd9-6d19-5988-4ced-4983d6f6be85.png)

FinalIKOrionLeapHandControllerのAvater 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)

左手（RightWrist)
![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)

### 設定完了
これでたぶん動くはず
（アニメーションとかそのあたりの兼ね合いもありますので、動かなかったらごめんなさい）