UnityでOculus Questのハンドトラッキングを使ってみる(タッチ&ピンチ)


Oculus Quest のハンドトラッキングで下記を試します。

  • 手の表示
  • キューブをタッチして色を変える
  • ピンチ操作でキューブの色を変える

環境

Unity 2019.2.17f1

事前準備

  • UnityでQuest用のビルドができること
  • Oculus Integration Assetsを追加していること

Scene作成

Hierarchy
Oculus > VR > Prefabs > OVRCameraRig を追加
(最初にあったMainCameraは削除しておく)

Inspector
OVR Manager (script) > Input > Hand Tracking Support → [Controllers and Hands]
OVR Manager (script) > Tracking > Tracking Origin Type → [Floor Level]

手を追加

Hierarchy
Oculus > VR > Prefabs > OVRHandPrefab を LeftHandAnchor と RightHandAnchor の下に追加

Inspector
OVRHand、OVRSkeleton、OVRMesh の各 HandType に Hand Left または Hand Right を選択
OVRSkeleton の Enable Physics Capsules にチェック

スケルトン表示にする場合

OVRHandPrefab の OVR Skeleton Renderer にチェック

カスタムマテリアルにする場合

OVRHandPrefab の Skinned Mesh Renderer で Materials > Element0 を好きなマテリアルに変える

ビルド確認

ハンドトラッキングされた手が表示されていればOK

左がスケルトン、右がカスタムマテリアル

衝突イベント

キューブをタッチして色を変えてみます。

Hierarchy
Cube を追加して位置と大きさを適当に調整(size:0.2, position: 0,0.5,1)

Inspector
Box Collider の Is Triggerをチェック

ChangeColor.csスクリプトを作成し、Cube に追加

ChangeColor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CubeTouch : MonoBehaviour
{
    private Renderer renderer;

    void Start()
    {
        renderer = this.gameObject.GetComponent<Renderer>();
    }

    private void OnTriggerEnter(Collider collider)
    {
        if (collider.gameObject.name == "Hand_Index3_CapsuleCollider")
        {
            renderer.material.color = Color.red;
        }
    }

    private void OnTriggerExit(Collider collider)
    {
        if (collider.gameObject.name == "Hand_Index3_CapsuleCollider")
        {
            renderer.material.color = Color.white;
        }
    }
}

ヒットしたら赤、外れたら白にマテリアルを更新しています。
colliderの名前は Hand_XXX_CapsuleCollider だったので、BoneIdから判定したいボーンを指定します。

OVRPlugin.cs
public enum BoneId
{
  Invalid                 = -1,

  Hand_Start              = 0,
  Hand_WristRoot          = Hand_Start + 0, // root frame of the hand, where the wrist is located
  Hand_ForearmStub        = Hand_Start + 1, // frame for user's forearm
  Hand_Thumb0             = Hand_Start + 2, // thumb trapezium bone
  Hand_Thumb1             = Hand_Start + 3, // thumb metacarpal bone
  Hand_Thumb2             = Hand_Start + 4, // thumb proximal phalange bone
  Hand_Thumb3             = Hand_Start + 5, // thumb distal phalange bone
  Hand_Index1             = Hand_Start + 6, // index proximal phalange bone
  Hand_Index2             = Hand_Start + 7, // index intermediate phalange bone
  Hand_Index3             = Hand_Start + 8, // index distal phalange bone
  Hand_Middle1            = Hand_Start + 9, // middle proximal phalange bone
  Hand_Middle2            = Hand_Start + 10, // middle intermediate phalange bone
  Hand_Middle3            = Hand_Start + 11, // middle distal phalange bone
  Hand_Ring1              = Hand_Start + 12, // ring proximal phalange bone
  Hand_Ring2              = Hand_Start + 13, // ring intermediate phalange bone
  Hand_Ring3              = Hand_Start + 14, // ring distal phalange bone
  Hand_Pinky0             = Hand_Start + 15, // pinky metacarpal bone
  Hand_Pinky1             = Hand_Start + 16, // pinky proximal phalange bone
  Hand_Pinky2             = Hand_Start + 17, // pinky intermediate phalange bone
  Hand_Pinky3             = Hand_Start + 18, // pinky distal phalange bone
  Hand_MaxSkinnable       = Hand_Start + 19,
  // Bone tips are position only. They are not used for skinning but are useful for hit-testing.
  // NOTE: Hand_ThumbTip == Hand_MaxSkinnable since the extended tips need to be contiguous
  Hand_ThumbTip           = Hand_Start + Hand_MaxSkinnable + 0, // tip of the thumb
  Hand_IndexTip           = Hand_Start + Hand_MaxSkinnable + 1, // tip of the index finger
  Hand_MiddleTip          = Hand_Start + Hand_MaxSkinnable + 2, // tip of the middle finger
  Hand_RingTip            = Hand_Start + Hand_MaxSkinnable + 3, // tip of the ring finger
  Hand_PinkyTip           = Hand_Start + Hand_MaxSkinnable + 4, // tip of the pinky
  Hand_End                = Hand_Start + Hand_MaxSkinnable + 5,

  // add new bones here

  Max = Hand_End + 0,
}

https://en.wikipedia.org/wiki/Phalanx_bone#/media/File:Scheme_human_hand_bones-en.svg
0から3にかけて指先になる

ピンチ操作

ピンチ操作でキューブの色を変えてみます。

手の表示で追加した OVRHandPrefab に MyHand.cs スクリプトを追加

MyHand.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyHand : MonoBehaviour
{    
    private OVRHand hand;
    private Renderer renderer;

    void Start()
    {
        renderer = GameObject.Find("Cube").GetComponent<Renderer>();
        hand = this.gameObject.GetComponent<OVRHand>();
    }

    void Update()
    {
        if (hand.GetFingerIsPinching(OVRHand.HandFinger.Middle))
        {
            renderer.material.color = Color.blue;
        }
        else if (material.color == Color.blue)
        {
            renderer.material.color = Color.white;
        }
    }
}

hand.GetFingerIsPinching でピンチしているかどうかを取得できます。
OVRHand.HandFinger.Middle をIndexやRingにするとピンチする指の指定ができます。
中指と親指をくっつけると青、離すと白にマテリアルを更新しています。

完成

ちゃんと中指以外は色が変わらない!
両手使える!

公式サイト
https://developer.oculus.com/documentation/unity/latest/concepts/unity-handtracking/

さいごに

薬指と小指は重なってしまって誤動作しやすい。
何か操作に使う場合は中指が良さそう。(人差し指は選択)
次は SDK の SampleFramework を使った方法も試してみる。

UnityでOculus IntegrationのSampleFrameworkを使ってOculus Questのハンドトラッキングを試す