前回の記事からしばらく時間がたって、LeapMotionのCoreAssetsもバージョンが上がりこの通りやっても動かない上にFinalIKもVRIKという便利なコンポーネントが追加されましたのでこちらを使ってMMDの指を動かすのをやりたいと思います。
操作が難しい・・・
— みゅみゅ (@miyumiyuna5) 2016年12月9日
上目遣いで上を見る→画面が見えない
VRじゃないけどVRIKを使ってみました pic.twitter.com/Z0toVGk3dp
こんな感じに指を動かします。
1.準備
- mmd4mecanimをいれる
- FinalIKをいれる
- LeapMotion Core Assets v4.1.4を入れる
- LeapMotion Add-on ModulesでHands Module v1.0.0を入れる
※この中で必要なのは - RiggedFinger
- RiggedHand
この2つのスクリプトだけです。 - 好きなモデルを入れてUnityで扱える状態にしておきます
2.LeapHandcontrollerでFinalIKを扱えるスクリプトの作成
前回はFullBodyIKコンポーネントを使いましたが今回はVRIKコンポーネントを使います。
/**
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)
その際に、手を前に出した時に勝手に歩かれると困るのでLocomotionのWeightを0にするのがよろしいかと
4.モデルにLeapMotion関連のスクリプトを置く
LeapMotion関係のコンポーネントを置いていくのですが
ヘッドマウントディスプレイにLeapMotionを置く → モデルのheadあたり
机の上にLeapMotionを置く → モデルのTorso、Torso2あたり
そのあたりに子オブジェクトしてLeapMotion関連のコンポーネントを作成していきます
※今回は机の上にLeapMotionを置く設定となります。
モデルのTorso2の子オブジェクトになるようの空のゲームオブジェクトを作成
そのゲームオブジェクトの名前を【LeapSpacer】という名前にしてその子供にもう一つ空のゲームオブジェクトを作成し名前を【LeapMotion】として、その中に必要なスクリプトを置きます。
(場所の微調整は【LeapSpacer】で行います)
LeapSpacerのポジションは若干前に出して、ローテションはすべて0です。
LeapMotionに必要なスクリプト
- LeapServiceProvider
- FinalIKOrionLeapHandController(さっき作ったやつ)
- HandPool
を入れます
FinalIKOrionLeapHandControllerの設定は
- IK Activeにチェック
- Avatar Left Hand 、Avatar Right Handにモデルに手(Wrist)を入れる
5.モデルの手と指を地道に設定する
モデルの手にRiggedHand、指それぞれにRiggedFingerを入れて設定していきます
右手の指(親指以外)
(Jointsはいらない。 FingerTypeとElementは指に合わせて適宜変更)
左手の指(親指以外)
(Jointsはいらない。 FingerTypeとElementは指に合わせて適宜変更)
設定完了
これでたぶん動くはず
ちゃんと動けばこんな感じに動きます
LeapMotionの方が楽!
— みゅみゅ (@miyumiyuna5) 2016年12月9日
口の形をまじめに反映させてみました。 pic.twitter.com/EvGSQ3OluF
この例では、頭の位置や回転をWebcamで取得してVRIKに反映させています。
(ついでに表情も)
VRIK使うと色々便利!