見出し画像

OpenXRを用いたハンドトラッキングで、指の動きを検知するプログラム

以下のコードを使用することで、指の動きをトラッキングして、それをVRコンテンツに反映することができます。

具体的には、3つのパターンと1つの動きを検知できます。
1.チョキ
2.グー
3.パー
4.親指と人差し指のピンチの動き
コメントが挿入されている部分に独自のプログラムを書き込めます。

using UnityEngine;

public class Hand : MonoBehaviour
{
    [SerializeField] private GameObject player;
    [SerializeField] private GameObject camera;

    [SerializeField] private Transform[] thumbBones;
    [SerializeField] private Transform[] indexBones;
    [SerializeField] private Transform[] middleBones;
    [SerializeField] private Transform[] ringBones;
    [SerializeField] private Transform[] pinkyBones;

    private Vector3 lastPinchPosition;

    void Update()
    {
        if (IsScissors())
        {
            HandleScissors();
        }
        else if (IsRock())
        {
            HandleRock();
        }
        else if (IsPaper())
        {
            HandlePaper();
        }

        if (IsPinching())
        {
            HandlePinch();
        }
    }

    private bool IsScissors()
    {
        return IsStraight(0.9f, indexBones) && IsStraight(0.9f, middleBones) && !IsStraight(0.9f, ringBones) && !IsStraight(0.9f, pinkyBones);
    }

    private bool IsRock()
    {
        return !IsStraight(0.9f, indexBones) && !IsStraight(0.9f, middleBones) && !IsStraight(0.9f, ringBones) && !IsStraight(0.9f, pinkyBones);
    }

    private bool IsPaper()
    {
        return IsStraight(0.9f, indexBones) && IsStraight(0.9f, middleBones) && IsStraight(0.9f, ringBones) && IsStraight(0.9f, pinkyBones);
    }

    private bool IsPinching()
    {
        float pinchThreshold = 0.05f;
        return Vector3.Distance(thumbBones[thumbBones.Length - 1].position, indexBones[indexBones.Length - 1].position) < pinchThreshold;
    }

    private void HandleScissors()
    {
        // チョキのロジック
    }

    private void HandleRock()
    {
        // グーのロジック
    }

    private void HandlePaper()
    {
        // パーのロジック
    }

    private void HandlePinch()
    {
        Vector3 currentPinchPosition = (thumbBones[thumbBones.Length - 1].position + indexBones[indexBones.Length - 1].position) / 2;

        if (lastPinchPosition != Vector3.zero)
        {
            Vector3 pinchMoveDelta = currentPinchPosition - lastPinchPosition;

            // プレイヤーオブジェクトやカメラを移動させるロジック
            // 例: player.transform.position += pinchMoveDelta * speed;
            // 例: camera.transform.position += pinchMoveDelta * speed;
        }

        lastPinchPosition = currentPinchPosition;
    }

    private bool IsStraight(float threshold, params Transform[] bones)
    {
        if (bones.Length < 3) return false;
        Vector3? oldVec = null;
        var dot = 1.0f;
        try
        {
            for (int index = 0; index < bones.Length - 1; index++)
            {
                var v = (bones[index + 1].position - bones[index].position).normalized;
                if (oldVec.HasValue)
                {
                    dot *= Vector3.Dot(v, oldVec.Value);
                }
                oldVec = v;
            }
            return dot >= threshold;
        }
        catch
        {
            return false;
        }
    }

}



よろしければサポートお願いします! いただいたサポートはクリエイターとしての活動費に使わせていただきます!by ゲーム開発所RYURYU