夜風のMixedReality

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

HoloLens 2で手のジェスチャー判定を行う。 手の向きを検知する。

本日はHoloLens 2の表現の調査枠です。

昨日指の伸びを検知するジェスチャー判定の機能を作成しました。

本日はさらに改造して手の平の向きに合わせてイベントを発動できるようにします。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

〇手の向きを検知する

今回はHandTrackingで検知できるJointの中からPalm(手のひら)を使用します。

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

Palmは手のひらを検知しているため、Palmのもつ開店情報はそれすなわち手自体の向きに相当します。

昨日のコードを編集しました。

  void Update()
    {
        handdetected = HandJointUtils.FindHand(handType)?.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose PalmPose);
        if ( handdetected != null&&  handdetected==true && HanddirDetected())
        {
            if (indexfingerDetected())
            {
                IndexFingerDetectEvent.Invoke();
            }
            else
            {
                Debug.Log("b");
                IndexFingerLostEvent.Invoke();
            }

            if (middlefingerDetected())
            {
                Debug.Log("c");
                MiddleFingerDetectEvent.Invoke();
            }
            else
            {
                Debug.Log("d");
                MiddleFingerLostEvent.Invoke();
            }   
        }
    }

    private bool HanddirDetected()
    {
        var jointedHand = HandJointUtils.FindHand(handType);
        if (jointedHand.TryGetJoint(TrackedHandJoint.Palm,out MixedRealityPose palmPose))
        {
            if (Vector3.Angle(palmPose.Up, CameraCache.Main.transform.forward) < facingThreshold)
            {
                return true;
            }
        }

        return false;
    }

Vector3.Angleは二点間のベクトルの角度をfloat型で返します。ここではPalmの鉛直軸と実行中のカメラ(=ユーザー)の角度を求め、facingThresholdよりも小さい角度である場合Trueを返します。

つまり、Palmのup(鉛直軸)というのはそのまま手の向きに相当するので、手を向けている場合Trueになるという処理に相当します。

以上でジェスチャー判定に手の向きという条件を追加できました。

MixedRealityPoseは複数個所に当たって使用するため読みやすいようにコードを整理する必要がありそうです。

〇コード全文

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


public class FingerDitected : MonoBehaviour
{
    [SerializeField,Header("Target"),Tooltip("Serect Detect Hands")]
    Handedness handType;
    
    [SerializeField,Range(0,90),Tooltip("Index Finger")]
    private float indexThreshold = 5;

    [SerializeField,Range(0,90)]
    private float middleThreshold = 5;

    [SerializeField, Range(0, 90)] 
    private float facingThreshold;

    [SerializeField,Header("Events")] 
    UnityEvent IndexFingerDetectEvent;

    [SerializeField] 
    UnityEvent IndexFingerLostEvent;

    [SerializeField] 
    UnityEvent MiddleFingerDetectEvent;

    [SerializeField] 
    UnityEvent MiddleFingerLostEvent;

    private bool?  handdetected;
    // Start is called before the first frame update

    // Update is called once per frame
    void Update()
    {
        handdetected = HandJointUtils.FindHand(handType)?.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose PalmPose);
        if ( handdetected != null&&  handdetected==true && HanddirDetected())
        {
            if (indexfingerDetected())
            {
                IndexFingerDetectEvent.Invoke();
            }
            else
            {
                Debug.Log("b");
                IndexFingerLostEvent.Invoke();
            }

            if (middlefingerDetected())
            {
                Debug.Log("c");
                MiddleFingerDetectEvent.Invoke();
            }
            else
            {
                Debug.Log("d");
                MiddleFingerLostEvent.Invoke();
            }   
        }
    }

    private bool HanddirDetected()
    {
        var jointedHand = HandJointUtils.FindHand(handType);
        if (jointedHand.TryGetJoint(TrackedHandJoint.Palm,out MixedRealityPose palmPose))
        {
            if (Vector3.Angle(palmPose.Up, CameraCache.Main.transform.forward) < facingThreshold)
            {
                return true;
            }
        }

        return false;
    }
    private bool indexfingerDetected()
    {
        var jointedHand = HandJointUtils.FindHand(handType);
        if (jointedHand.TryGetJoint(TrackedHandJoint.Palm,out MixedRealityPose PalmPose))
        {
            //各関節のpose
            MixedRealityPose indexTipPose,indexDistalPose,IndexKnucklePose,indexMiddlePose; 
            if(jointedHand.TryGetJoint(TrackedHandJoint.IndexTip,out indexTipPose)&& jointedHand.TryGetJoint(TrackedHandJoint.IndexDistalJoint,out indexDistalPose)&&jointedHand.TryGetJoint(TrackedHandJoint.IndexMiddleJoint,out indexMiddlePose)&& jointedHand.TryGetJoint(TrackedHandJoint.IndexKnuckle,out IndexKnucklePose))
            {
                Vector3 hoge = IndexKnucklePose.Position - PalmPose.Position;
                Vector3 hogege = indexMiddlePose.Position - IndexKnucklePose.Position;
                Vector3 hogegege = indexDistalPose.Position - indexMiddlePose.Position;
                Vector3 ho = indexTipPose.Position - indexDistalPose.Position;
                
            float c = Vector3.Angle(PalmPose.Position, hoge);
            float d = Vector3.Angle(hoge, hogege);
            float e = Vector3.Angle(hogege, hogegege);
            float f = Vector3.Angle(hogegege, ho);

            float aba = (Mathf.Abs(d) + Mathf.Abs(e) + Mathf.Abs(f)) / 3;

                if (aba < indexThreshold)
                {
                    return true;
                }
            }
        }
        return false;
    }

    private bool middlefingerDetected()
    {
        var jointedHand = HandJointUtils.FindHand(handType);
        if (jointedHand.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose PalmPose))
        {
            MixedRealityPose middleTipsPose,middleDistalPose, middleKnucklePose,middleMiddlePose;
            if (jointedHand.TryGetJoint(TrackedHandJoint.MiddleTip, out middleTipsPose) &&
                jointedHand.TryGetJoint(TrackedHandJoint.MiddleDistalJoint, out middleDistalPose) &&
                jointedHand.TryGetJoint(TrackedHandJoint.MiddleKnuckle, out middleKnucklePose)&&jointedHand.TryGetJoint(TrackedHandJoint.MiddleMiddleJoint,out middleMiddlePose))
            {
                Vector3 hoge = middleKnucklePose.Position - PalmPose.Position;
                Vector3 hogege = middleMiddlePose.Position - middleKnucklePose.Position;
                Vector3 hogegege = middleDistalPose.Position - middleMiddlePose.Position;
                Vector3 ho = middleTipsPose.Position - middleDistalPose.Position;
                
                float c = Vector3.Angle(PalmPose.Position, hoge);
                float d = Vector3.Angle(hoge, hogege);
                float e = Vector3.Angle(hogege, hogegege);
                float f = Vector3.Angle(hogegege, ho);

                float aba = (Mathf.Abs(d) + Mathf.Abs(e) + Mathf.Abs(f)) / 3;

                if (aba < middleThreshold)
                {
                    return true;
                }
                
            }
        }

        return false;
    }
}