🍰

XR Handsパッケージ 1.2.1について

2023/07/28に公開

XR Handsのドキュメントが英語なので、メモとして読んだポイントを列挙。
この先Vision Proがでてきたり、ハンドトラッキングを使う機会はあるはずなので学習してます。

XR HandsパッケージはハンドトラッキングのAPIを提供するけど、機能自体は実装していない。ターゲットプラットフォームでハンドトラッキングを利用するには、XRHandSubsystemにハンドトラッキングのデータを渡してくれるプラットフォームに適したplug-in パッケージの追加が必要です。
※今のところOpenXR packageが唯一のハンドトラッキングをサポートするplug-inです。
他のplug-inのハンドトラッキングのサポート状況については各パッケージの情報を参照すること。

XR Hands 1.2.1はUnity 2021.3以降に対応しているけど、Unity 2023.1以前だとPackage ManagerのUnity Registryから入れるのではなくて、Add package by nameから com.unity.xr.hands を直接指定する。

シーンを作成するときはCreate > XR > XR Originで追加する、とチュートリアルには書いてあるけど、XR Interaction Hands SetupのプレハブがあるのでそれをヒエラルキーにつっこんでもOKだった。

Hand tracking data

XR Handパッケージを使ってアクセスできるデータについて。

  • Hand data model:ユーザーの手の手首から上の関節位置26個所の位置、向き、動きを提供する。親指は中間骨がないので、他の指よりも1か所少ない。
    hand APIが返す情報は空間と相対的な情報で、距離の単位はm。
    XRHand.rootPoseは手の位置情報、XRHandJointは関節の情報、XRHandDeviceはつまんだり、握ったりの情報。これらがあれば手の軌道とかは取れそうです。
    Hand

  • Access hand data:XRHandSubsystemをサブスクライブしているXRHandTrackingEventsを利用してPose Updated、Joints Updated、Tracking Acquiredなどのタイミングで処理を実行させることができる。実際にはこちらの方でHand data modelの情報を取得する感じ。

  • Hand visuals:手のデータは手首を親として指先までの階層構造になっている。

    • Wrist:手首
    • Palm:手のひら
    • Metacarpal:手首から指の間の骨
    • Proximal:こぶしの部分
    • Intermediate:第2関節
    • Distral:第一関節
    • Tip:指先
      ※Thumbが親指、Indexが人差し指、Middleが中指、Ringが薬指、Littleが小指

OpenXR機能

  • Hand Tracking:OpenXR向けのHand tracking dataを利用するための機能
  • Meta Aim Hand:OpenXRで利用するためのMeta Aim Hand extensionを実装
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Hands;

public class HandsExample : MonoBehaviour
{
    XRHandSubsystem m_HandSubsystem;

    void Start()
    {
        var handSubsystems = new List<XRHandSubsystem>();
        SubsystemManager.GetSubsystems(handSubsystems);

        for (var i = 0; i < handSubsystems.Count; ++i)
        {
            var handSubsystem = handSubsystems[i];
            if (handSubsystem.running)
            {
                m_HandSubsystem = handSubsystem;
                break;
            }
        }

        if (m_HandSubsystem != null)
            m_HandSubsystem.updatedHands += OnUpdatedHands;
    }

    void OnUpdatedHands(XRHandSubsystem subsystem,
        XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags,
        XRHandSubsystem.UpdateType updateType)
    {
        switch (updateType)
        {
            case XRHandSubsystem.UpdateType.Dynamic:
                // Update game logic that uses hand data
                break;
            case XRHandSubsystem.UpdateType.BeforeRender:
                // Update visual objects that use hand data
                break;
        }
    }
}

Discussion