OculusQuestでハンドトラッキングをしてみよう!<後編> 〜オブジェクトをつまむ〜
前回の記事ではOculusQuestでハンドトラッキングを適用して手を表示できるところまでできました。
今回はハンドトラッキングを利用してバーチャル世界のオブジェクトを手でつまめるようににしていきたいと思います。
筆者環境
- MacBookPro(2017年モデル)
- Unity バージョン2019.2.17f1
シリーズ
前提条件
1. ハンドトラッキング用プレハブの解釈
前回記事でハンドトラッキングをプロジェクトに適用して、手が表示できるところまでできました。
まずはUnityプロジェクトのヒエラルキーが以下の図のようになっているのを確認します。

確認できたらOVRCameraRig > TrackingSpace > RightHandAnchor > OVRHandPrefab
を選択してインスペクタを確認します。

インスペクタをみるといくつかのスクリプトがアタッチされています。
ざっくり解釈すると以下のようになります。
- OVRHand: トラッキングされた手の状態・描画等を管理
- OVRSkeleton: トラッキングされた手の骨組みの状態を管理
- OVRSkeletonRenderer: トラッキングされた手の骨組みの描画を管理
- OVRMesh: 描画する手のメッシュの状態を管理
- OVRMeshRenderer: 描画する手のメッシュの描画を管理
これらに補足すると、骨組みにはそれを構成するゲームオブジェクト(シリンダ型)が内包されておりこれを使ってお当たり判定などを実装している模様です。
これらを理解した上で、今回の目標であるVR内オブジェクトをつかむためにOVRHand
クラスとOVRSkeleton
クラスオブジェクトを利用して実装していきます。
またちょっとした知識で、インスペクタからOVRMeshRenderer
を無効にしてOVRSkeletonRenderer
を有効にすることで手の描画が骨組みのみにすることができます。
2. スクリプトを書く
オブジェクトを指でつまめるようにするために、つままれるオブジェクトにアタッチするスクリプトを作成します。
まずはAssets直下にScripts
フォルダを作成してその中にC#スクリプトのPinchableObject
を作成します。

作成できたら以下のプログラムを記述します。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PinchableObject : MonoBehaviour { public GameObject HandPrefab; private OVRHand hand; private OVRSkeleton skeleton; private Renderer renderer; private bool isTouching = false; private bool initialized = false; void Start() { this.hand = this.HandPrefab.GetComponent<OVRHand>(); this.skeleton = this.HandPrefab.GetComponent<OVRSkeleton>(); this.renderer = this.GetComponent<Renderer>(); this.initialized = this.hand != null && this.skeleton != null; // もし必要スクリプトがなければオブジェクトを黄色にする if(!this.initialized) this.renderer.material.color = Color.yellow; } public void OnTriggerEnter(Collider collider) { if(!this.initialized) return; this.isTouching = true; } public void OnTriggerStay(Collider collider) { if(!this.initialized) return; this.isTouching = true; } public void OnTriggerExit(Collider collider) { if(!this.initialized) return; this.GetComponent<Renderer>().material.color = Color.white; this.isTouching = false; } void Update() { if(!this.initialized) return; bool isPinching = this.hand.GetFingerIsPinching(OVRHand.HandFinger.Thumb); if(this.isTouching && isPinching){ var newPos = this.skeleton.Capsules[5].CapsuleCollider.transform.position; this.GetComponent<Renderer>().material.color = Color.red; this.transform.position = newPos; } } }
簡単に説明すると、『オブジェクトをつまむ』を実装するには手がオブジェクトに触れていて指がつまむ動作(今回は親指といずれかの指がくっついた時)を認識できれば良いので、OVRSkeleton
に内包されたシリンダ型オブジェクト群で当たり判定をして、OVRHand
クラスのGetFingerIsPinching()
メソッドで親指とその他の指がくっついているかを取得することで実装しています。
つまんでいるときのオブジェクトの位置は、骨組みのシリンダ型オブジェクトリストから最もそれらしい位置に移動させるようにプログラムしています。
まだ明確にどのインデックスにどのシリンダが格納されているか分からないので、調査が必要です。
今回はブログ用に最低限のプログラムでの実装でしたが、用意されたクラスでより厳密にプログラムすることも可能だと思われます。
3. 各種設定・アタッチ
スクリプトができたのでゲームオブジェクトの配置とアタッチや各種設定をしていきます。
まずはつまむオブジェクトを作成しましょう。
ヒエラルキーのOVRCameraRig
の外に適当なオブジェクトを作成しコライダを設定します。
オブジェクトの位置はOVRCameraRIg
にできるだけ近づけて、小さめにするとVR空間で見つけやすくなります。

次にオブジェクトに前章のスクリプトをアタッチします。
今回は右手のみでつまめるようにするため、アタッチ後にPinchableObject
スクリプトのHandPrefab
に右手のOVRHandPrefab
をドラッグ&ドロップして充てます。

ここまでできたら、つままれるオブジェクトの設定は終わりです。
次につまむ手にコライダを設定します。
手に当たり判定を与えるには手のメッシュにコライダを充てるのではなく、骨格に紐づいたゲームオブジェクト(シリンダ型)にコライダを設定します。
既にSDKのスクリプトでコライダ自体は充てられるようになっているので、設定は下の図のようにOVRHandPrefab
のOVRSkeleton
スクリプトの設定をGUIで行うだけです。

4. 動作確認
さて、ここまで来ればあとは動作確認ができます。File > Build And Run
で実機にアプリを送り以下の動画のように操作できれば実装完了です。

たまに勝手にオブジェクトを手放してしまうような挙動がありますが、手を早く動かしたり背景や角度的に手が認識できないことが多々あるようなのでその辺の対応も必要になってくるのかもしれません。
まとめ
- 既に便利なクラスが用意されていて思っていたより簡単に実装できた。
- 指のシリンダ型オブジェクトの明確な呼び出し方が知りたい。
- 手を早く動かしたりすると認識ができなくなるので注意。
コメント
コメントを投稿