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]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/aed836da-bb5e-c370-0267-30e333e3d994.png)


# 手を追加

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/7829056d-fe52-8bc9-acc4-e6d2d9956ba5.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/7dfeacb7-6d24-2590-b7b4-1b7fbfa7f0ea.png)

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

OVRHandPrefab の OVR Skeleton Renderer にチェック

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

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


# ビルド確認

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

![v1nh4-ulwxs.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/6a9f4d0b-07cb-ff8b-6e9d-0a6877dbe420.gif)

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

![com.qvtecCompany.OculusQuestHandTracking-20200115-234849.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/d3f386ed-d3b0-3bc6-4c8f-ef529f1b1bc5.jpeg)


# 衝突イベント

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

**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にするとピンチする指の指定ができます。
中指と親指をくっつけると青、離すと白にマテリアルを更新しています。

# 完成

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

![gumhj-05rps.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536619/4edc281d-13e6-8d55-4b62-892c47b1c163.gif)


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

# さいごに

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

→ [UnityでOculus IntegrationのSampleFrameworkを使ってOculus Questのハンドトラッキングを試す](https://qiita.com/qvtec/items/9e45b6bdad17a940a236)