オリジナルのハンドジェスチャーを実装する

こんにちは。HoloLensチームの老田です!

今回はHoloLens2でオリジナルのハンドジェスチャーの実装についてです。

そもそもどんなハンドジェスチャーがあるの?

  • AirTap
  • ホーム画面を出すジェスチャー (手首に人差し指をあてる)
  • ホーム画面を出すジェスチャー (手首に視線を合わせて人差し指と親指を合わせる)
    詳しくは下記を参照してください。

https://docs.microsoft.com/ja-jp/hololens/hololens2-basic-usage

https://docs.microsoft.com/ja-jp/windows/mixed-reality/system-gesture

オリジナルのジェスチャーを実装することができるのか?

かなり泥臭い方法になってしまいますが、実装することは可能なようでした。

今回は以下のようなジェスチャーを認識するように実装していきたいと思います。

実装のしかた

考え方としては指一つ一つを手のひらに対して同じ向きかどうか、そうでないかを判断することで指を曲げているかどうかを認識することができます。

using UnityEngine;
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities;

public class GestureTest : MonoBehaviour
{

    [SerializeField, Range(0.0f, 90.0f)] private float flatHandThreshold = 45.0f;
    [SerializeField, Range(0.0f, 90.0f)] private float facingThreshold = 80.0f;
    [SerializeField] GameObject sphere = null;
    [SerializeField] TextMesh textMesh = null;


    private void Update()
    {

        if (CheckHandSgin())
        {
            sphere.SetActive(true);
        }
        else
        {
            sphere.SetActive(false);
        }

    }

    private bool CheckHandSgin()
    {
        // 右手のみ判定したいので右手を取得
        var jointedHand = HandJointUtils.FindHand(Handedness.Right);

        // 手のひらが認識できているか
        if (jointedHand.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose palmPose))
        {
            MixedRealityPose thumbTipPose, indexTipPose, middleTipPose, ringTipPose, pinkyTipPose;

            if (jointedHand.TryGetJoint(TrackedHandJoint.IndexTip, out indexTipPose) && jointedHand.TryGetJoint(TrackedHandJoint.PinkyTip, out pinkyTipPose))
            {
                var handNormal = Vector3.Cross(indexTipPose.Position - palmPose.Position, pinkyTipPose.Position - indexTipPose.Position).normalized;
                handNormal *= (jointedHand.ControllerHandedness == Handedness.Right) ? 1.0f : -1.0f;
                if (Vector3.Angle(palmPose.Up, handNormal) > flatHandThreshold)
                {
                    return false;
                }
            }

            // 中指と薬指の情報を取得
            if (jointedHand.TryGetJoint(TrackedHandJoint.MiddleTip, out middleTipPose) && jointedHand.TryGetJoint(TrackedHandJoint.RingTip, out ringTipPose))
            {
                var handNormal = Vector3.Cross(middleTipPose.Position - palmPose.Position, ringTipPose.Position - indexTipPose.Position).normalized;
                handNormal *= (jointedHand.ControllerHandedness == Handedness.Right) ? 1.0f : -1.0f;
                if (Vector3.Angle(palmPose.Up, handNormal) < flatHandThreshold)
                {
                    return false;
                }
            }
        }
        // 手のひらを向けているか確認
        return Vector3.Angle(palmPose.Up, CameraCache.Main.transform.forward) < facingThreshold;
    }

}

適当なオブジェクトにアタッチしてsphereにオブジェクトを割り当ててあげれば以下のGIFように動作すると思います。

最後に

注意点としてUnityエディタ上ではデバッグできませんのでそこそこつらいです。

今回は右手だけ反応するように実装しましたが、どちらかの手や左手だけ反応するようにも実装できます。