MRが楽しい

MRやVRについて学習したことを書き残す

UnityでMetaQuestProアプリを作成する(ボディトラッキングを利用する)

本日は MetaQuestPro の開発手順枠です。
UnityでMetaQuestProアプリを作成する手順を記事にします。
今回は MetaQuestPro のボディトラッキングを利用する手順です。

事前準備

テストプロジェクトに以下で作成したプロジェクトを利用します。
bluebirdofoz.hatenablog.com

ボディトラッキングを有効化する

Config ファイルでハンドトラッキングとボディトラッキングを有効化します。
Assets/Oculus/OculusProjectConfig.assets を開き、以下の通り設定を変更します。
・[Hand Traking Suport]を[Controllers And Hands]に変更する
・[Body Tracking Support]を[Required]に変更する

次に起動時に自動でボディトラッキングの権限要求が実行されるよう設定を行います。
[OVRCameraRig]を選択して[OVR Manager]コンポーネント内の以下の設定を変更します。
・[Permission Requests On Startup -> Body Tracking]にチェックを入れる

ボディトラッキングの結果を表示する

実際にボディトラッキングで取得できる各関節の状態を可視化してみます。
Hierarchy に適当なオブジェクトを新規作成します。

作成したオブジェクトに[OVR Body]コンポーネントを追加します。
コンポーネントからボディトラッキングの各ジョイント情報を取得することができます。

以下のような OVR Body コンポーネントから取得した各ジョイントの状態をオブジェクトとして配置して表示するサンプルスクリプトを作成しました。
・BodyTrackingSample.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BodyTrackingSample : MonoBehaviour
{
    /// <summary>
    /// ジョイント部表示プレハブ
    /// </summary>
    [SerializeField]
    private GameObject TrackPointPrefab;

    /// <summary>
    /// OVRBodyの参照
    /// </summary>
    private OVRBody OvrBody;

    /// <summary>
    /// 各ジョイント部に配置するゲームオブジェクトの参照
    /// </summary>
    private GameObject[] TrackingPointObjects;

    /// <summary>
    /// 各インデックスのジョイントの名前
    /// </summary>
    private enum JointName
    {
        Root = 0,
        Hips = 1,
        SpineLower = 2,
        SpineMiddle = 3,
        SpineUpper = 4,
        Chest = 5,
        Neck = 6,
        Head = 7,
        LeftShoulder = 8,
        LeftScapula = 9,
        LeftArmUpper = 10,
        LeftArmLower = 11,
        LeftHandWristTwist = 12,
        RightShoulder = 13,
        RightScapula = 14,
        RightArmUpper = 15,
        RightArmLower = 16,
        RightHandWristTwist = 17,
        LeftHandPalm = 18,
        LeftHandWrist = 19,
        LeftHandThumbMetacarpal = 20,
        LeftHandThumbProximal = 21,
        LeftHandThumbDistal = 22,
        LeftHandThumbTip = 23,
        LeftHandIndexMetacarpal = 24,
        LeftHandIndexProximal = 25,
        LeftHandIndexIntermediate = 26,
        LeftHandIndexDistal = 27,
        LeftHandIndexTip = 28,
        LeftHandMiddleMetacarpal = 29,
        LeftHandMiddleProximal = 30,
        LeftHandMiddleIntermediate = 31,
        LeftHandMiddleDistal = 32,
        LeftHandMiddleTip = 33,
        LeftHandRingMetacarpal = 34,
        LeftHandRingProximal = 35,
        LeftHandRingIntermediate = 36,
        LeftHandRingDistal = 37,
        LeftHandRingTip = 38,
        LeftHandLittleMetacarpal = 39,
        LeftHandLittleProximal = 40,
        LeftHandLittleIntermediate = 41,
        LeftHandLittleDistal = 42,
        LeftHandLittleTip = 43,
        RightHandPalm = 44,
        RightHandWrist = 45,
        RightHandThumbMetacarpal = 46,
        RightHandThumbProximal = 47,
        RightHandThumbDistal = 48,
        RightHandThumbTip = 49,
        RightHandIndexMetacarpal = 50,
        RightHandIndexProximal = 51,
        RightHandIndexIntermediate = 52,
        RightHandIndexDistal = 53,
        RightHandIndexTip = 54,
        RightHandMiddleMetacarpal = 55,
        RightHandMiddleProximal = 56,
        RightHandMiddleIntermediate = 57,
        RightHandMiddleDistal = 58,
        RightHandMiddleTip = 59,
        RightHandRingMetacarpal = 60,
        RightHandRingProximal = 61,
        RightHandRingIntermediate = 62,
        RightHandRingDistal = 63,
        RightHandRingTip = 64,
        RightHandLittleMetacarpal = 65,
        RightHandLittleProximal = 66,
        RightHandLittleIntermediate = 67,
        RightHandLittleDistal = 68,
        RightHandLittleTip = 69,
    }

    /// <summary>
    /// ジョイントの総数
    /// </summary>
    private int JointNumber => System.Enum.GetValues(typeof(JointName)).Length;

    void Start()
    {
        OvrBody = GetComponent<OVRBody>();
        TrackingPointObjects = new GameObject[JointNumber];

        // 各ジョイント部のゲームオブジェクトを生成する
        for (int index = 0; index < JointNumber; index++)
        {
            var gameObject = Instantiate(TrackPointPrefab, this.transform);
            gameObject.name = ((JointName)index).ToString();
            gameObject.transform.localScale = new Vector3(0.01f, 0.005f, 0.005f);
            TrackingPointObjects[index] = gameObject;
        }
    }

    void Update()
    {
        if (OvrBody == null) return;

        if (OvrBody.BodyState != null)
        {
            OVRPlugin.BodyState bodyState = OvrBody.BodyState.Value;
            OVRPlugin.BodyJointLocation[] jointLoacations = bodyState.JointLocations;

            // 各ジョイント部のゲームオブジェクトをボディトラッキングの情報を基に移動・回転する
            for (int index = 0; index < JointNumber; index++)
            {
                OVRPlugin.Posef posef = jointLoacations[index].Pose;
                TrackingPointObjects[index].transform.localPosition = new Vector3(
                    posef.Position.x,
                    posef.Position.y,
                    posef.Position.z
                    );
                TrackingPointObjects[index].transform.localRotation = new Quaternion(
                    posef.Orientation.x,
                    posef.Orientation.y,
                    posef.Orientation.z,
                    posef.Orientation.w
                    );
            }
        }
    }
}

作成したサンプルスクリプトをオブジェクトに追加します。

[TrackPointPrefab]にはジョイント部に表示したい適当なプレハブを割り当てます。
今回は Cube オブジェクトをそのままプレハブ化したオブジェクトを指定しました。

これでボディトラッキングを表示できるようになりましたが、このまま再生するとボディトラッキングの結果は鏡写しの状態で表示されます。
今回は体に重なるように表示したかったのでオブジェクトの Scale:Z の値を -1 に変更しました。

これで準備は完了です。
以下の手順を参考にプロジェクトをビルドして MetaQuestPro にインストールしてください。
bluebirdofoz.hatenablog.com

動作確認結果

MetaQuestPro でアプリを起動すると体の各ジョイント位置にオブジェクトが表示されます。
手を前に出すと以下のように手の各ジョイントの位置と回転が取得できていることが分かります。

参考ページ

note.com