夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

HoloLens 2のハンドトラッキングを使用してデジタルなキャラクターと握手をする。

本日は機能に引き続きHoloLens MeetupVol.21でのLT登壇内容に関する記事です。

〇HoloLensMeetupとは?

〇ハンドトラッキングで握手をする。

 HoloLens2のHandTrackingは手の位置だけでなく間接ごとの動きでポーズや手のひらの向きを検出することができます。

 今回取り組んでいるキャラクターをよりデータではなくキャラクターとして扱うための表現の実験の一つとしてキャラクターと握手をできる仕組みに取り組みました。

〇キャラクターの手を動かす。

 VRMのキャラクターモデルはUnityHumanoidBoneを持っているためHumanoidのAnimationを使用して動かすことができます。

 今回はAnimationではなくIKを使用して動かします。 IKとは[Inverse Kinematics]の意味で、キャラクターのボーン構造を使用してアニメーションさせる手法ですが、最初に手先、頭、腰、足などの最終的な位置を決めてそれに対応するようにほかのボーンを逆算していく方法です。

 今回の場合キャラクターと握手をするためにはユーザーの手の位置があり、デジタルなキャラクターの手とユーザーの手が重なるようにすることで握手が可能です。

 この手の位置から逆算して動かすために今回は[FinalIK]のアセットを使用しました。

 FinalIKは90$ほどで販売されていますが、頻繁にセールが行われ筆者は以前45$の際に購入しました。

 FinalIKの中に[VR IK]というコンポーネントがあります。 このコンポーネントはアタッチされたオブジェクトの子オブジェクトからボーンの構造を取得します。

 [Solver]には[Target]と呼ばれる『対応する四肢や頭をどのオブジェクトの位置に移動させるか?』を指定することができます。

 ・キャラクターのゲームオブジェクトにVRIKコンポーネントをアタッチします。

 ・空のゲームオブジェクトを作成し[ShakeHands]と名付け、VRIKの[Solver]の[Right Hand]の[Target]に指定します。

f:id:Holomoto-Sumire:20200805214941j:plain

 ・Unityで実行し[ShakeHands]の[Transform]を動かすとそれに合わせてキャラクターの右手の位置が変わることが確認できます。

スクリプト

 次に[HandTarget]の位置とユーザーの手の位置を同期させます。

 次のようなスクリプトを書きました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities;

public class HandTarget : MonoBehaviour
{
    [SerializeField] bool isShakeHands;
    GameObject _rightHand;
    Vector3 _righthandpos;
    Quaternion _rigthandRot;

    // Update is called once per frame
    void Update()
    {
        if (isShakeHands)
        {
            if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
            {
               _rightHand = GameObject.Find("Wrist Proxy Transform");
                _righthandpos = _rightHand.transform.position;
                _righthandpos.z += 0.12f;
                _righthandpos.x -= 0.1f;
                _righthandpos.y += 0.02f;

                this.transform.position = _righthandpos;           
            }
            else
            {
                _rightHand = null;
                Debug.Log("hand not find");
            }
        }
    }    
}
 if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
            {
            ... 
            }
            else
            {
             ...
            }

HandJointUtils.TryGetJointPose()で右手の検出を行っています。これは以前調査したHoloLens 2でのHandTrackingの検出を応用しています。

redhologerbera.hatenablog.com

     if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
            {
               _rightHand = GameObject.Find("Wrist Proxy Transform");
                _righthandpos = _rightHand.transform.position;
                
                //手の位置とキャラクターの手の重なりのずれを補正
                _righthandpos.z += 0.12f;
                _righthandpos.x -= 0.1f;
                _righthandpos.y += 0.02f;

                this.transform.position = _righthandpos;           
            }
            else
            {
                _rightHand = null;
                Debug.Log("hand not find");
            }

 右手が検出された場合_rightHandのゲームオブジェクトに[Wrist Proxy Transform]のオブジェクトを取得して代入しています。

 この[Wrist Proxy Transform]は手首のジョイントを指します。

f:id:Holomoto-Sumire:20200805214630p:plain

microsoft.github.io

 今回の場合指ではなく手のルートの位置情報が欲しいので手首のジョイントを指定しました。

 このスクリプトを[Shake Hand]のオブジェクトにアタッチします。

 これで右手が検出された場合キャラクターの手をユーザーの右手に重ねます。

以上でキャラクターと握手する機能ができました。

〇実機で確認

実機で確認すると次のようになります。

www.youtube.com