本日はHoloLens 2の表現調査の記事です。
HoloLens 2ではHandTrackingによってユーザーの手を取得できます。
これは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;
public class FingerDitected : MonoBehaviour
{
[SerializeField,Header("Target")]
Handedness handType;
[SerializeField,Range(0,90)]
private float indexThreshold = 5;
[SerializeField,Range(0,90)]
private float middleThreshold = 5;
[SerializeField]
UnityEvent IndexFingerDetectEvent;
[SerializeField]
UnityEvent IndexFingerLostEvent;
[SerializeField]
UnityEvent MiddleFingerDetectEvent;
[SerializeField]
UnityEvent MiddleFingerLostEvent;
private bool? handdetected;
void Update()
{
handdetected = HandJointUtils.FindHand(handType)?.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose PalmPose);
if (handdetected != null&& handdetected==true)
{
if (indexfingerDetected())
{
IndexFingerDetectEvent.Invoke();
}
else
{
IndexFingerLostEvent.Invoke();
}
if (middlefingerDetected())
{
MiddleFingerDetectEvent.Invoke();
}
else
{
MiddleFingerLostEvent.Invoke();
}
}
}
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 f1 = IndexKnucklePose.Position - PalmPose.Position;
Vector3 f2 = indexMiddlePose.Position - IndexKnucklePose.Position;
Vector3 f3 = indexDistalPose.Position - indexMiddlePose.Position;
Vector3 f4 = indexTipPose.Position - indexDistalPose.Position;
float c = Vector3.Angle(PalmPose.Position, f1);
float d = Vector3.Angle(f1, f2);
float e = Vector3.Angle(f2, f3);
float f = Vector3.Angle(f3, f4);
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 f1= middleKnucklePose.Position - PalmPose.Position;
Vector3 f2 = middleMiddlePose.Position - middleKnucklePose.Position;
Vector3 f3 = middleDistalPose.Position - middleMiddlePose.Position;
Vector3 f4 = middleTipsPose.Position - middleDistalPose.Position;
float c = Vector3.Angle(PalmPose.Position, f1);
float d = Vector3.Angle(f1, f2);
float e = Vector3.Angle(f2, f3);
float f = Vector3.Angle(f3, f4);
float aba = (Mathf.Abs(d) + Mathf.Abs(e) + Mathf.Abs(f)) / 3;
if (aba < middleThreshold)
{
return true;
}
}
}
return false;
}
}
〇使い方
MRTKが導入されている適当なゲームオブジェクトを作成し、[FingerDetector]をアタッチします。

●HandType
右手、左手、どちらをtrackingするかを指定します。

●indexThreshold 、middleThreshold
人差し指、中指の検知閾値です。
値が小さいほどしっかりと人差し指を伸ばす必要があります。 逆に値が大きいほど完全に指を伸ばしていなくても検知されます。

● IndexFingerDetectEvent,MiddleFingerDetectEvent
人差し指、中指が伸ばされたときに発火するイベントになります。

● IndexFingerLostEvent。MiddleFingerLostEvent
人差し指、中指が曲げられたときに発火するイベントです。

このindexFingerDetectEvent,MiddleFingerDetectEventとIndexFingerLostEvent。MiddleFingerLostEventに任意のアクションを設定します。
次回細かい解説を行います。