今回はOculus Questの開発ネタをやっていきます。
内容的にはOculus Rift Sなどにもそのまま応用できるかと思います。
Oculus Touchコントローラーで離れた場所にあるものを掴む方法について解説します。
プレイエリアが狭い時や、座ったままプレイさせたい時など自由に動き回るのが困難な時に役立ちます。
他にも、机から床に落ちてしまったオブジェクトを拾う時などプレイヤーの負担を軽減できます。
- 開発環境
- 先行研究
- セットアップ
- サンプルシーンの確認
- 主要コンポーネント
- DistanceGrabber
- DistanceGrabbable
- GrabManager
- 実際に掴めるオブジェクトを置いてみる
- まとめ
- 参考文献
開発環境
Windows 10
Unity 2018.4.1f
Oculus Integration ver1.37
Oculus Quest
先行研究
セットアップ
前回の記事をあらかじめ見ておいてください。
前提として、Project内にAssetStoreからOculus Integrationをインポートしておく必要があります。
サンプルシーンの確認
Assets/SampleFramework/Usageに様々なサンプルシーンがあります。
離れた物を掴むサンプルシーンはDistanceGrabになります。
学習や挙動の確認にとても有益です。見てみましょう。
実行してみるとこんな感じになります。
Oculus Integration 1.42で修正されました
ちなみにこのサンプルシーンには深刻なバグが存在しています。
それは物を掴んだ時にPlayerが吹き飛ばされることです。
原因はGrabbableとPlayerの衝突のようです。
QuestでアプリインストールとChromeCastを試した
— イシヤマ@xR (@IshiyamaTokina) June 3, 2019
Oculus公式SDKのDistanceGrabすごく良いんだけど、ものを掴もうとすると衝撃を受けたように後ろに吹っ飛んで落下するのはなんなんだ?#OculusQuest pic.twitter.com/L2i6VLehht
サンプルシーンのバグ修正
このバグを修正する方法を載せておきます。
PlayerにはCharacterControllerがくっついています。
このColliderとGrabbableのColliderが接触しないようレイヤーを分けます。
[Player][Grabbable]レイヤーを新しく作成します(名前はなんでもいいです)
シーン内にあるOVRPlayerControllerはPlayerレイヤーにしましょう。
この時、子オブジェクトのレイヤーは変えないでください(理由は後述)
その後、サンプルシーンの中にあるDistanceGrab~~~と名前のつく掴みたいオブジェクトを全てGrabbableレイヤーにします。
最後にProjectSettingのPhysicsからPlayerとGrabbableのチェックを外しておきます。
これでPlayerが吹き飛ばされることなくシーンが動きます。
他には、CharacterControllerを切ってしまうという手段もあります。
主要コンポーネント
こちらもOVR Grabber&Grabbable同様Oculus側でコンポーネントが用意されています。
そちらを使っていきましょう。
これらはインポートしたOculus Integrationの
Assets/Oculus/sampleFramework/Core/DistanceGrab/Scriptsにあります。
DistanceGrabber
こちらは物を掴む側、つまり手につけるコンポーネントになります。
DistanceGrabbable
こちらは物を掴まれる側、つまりオブジェクト側につけるコンポーネントになります。
Grab Manager
こちらは物を掴む範囲を決めるコンポーネント、DistanceGrabberを使うのに必須です。
DistanceGrabber
DistanceGrabのシーンにある、DistanceGrabを見てみましょう。
OVR Grabberコンポーネントがついているのがわかります。
手にあたるオブジェクトにはこのコンポーネントが必要です。
(Rigitbodyも必要)
このコンポーネントはOVR Grabberを継承して作られています。
そのため使い方やインスペクターはOVR Grabberに規準しています。
インスペクターパラメーター(追加分)
とても多いです。掴める対象物のことをターゲットと呼称します。
FocusColor
掴むオブジェクトをアウトラインする機能、色を指定できる。
Spherecasrt Radius
ターゲットを見つけるSpherecastの半径。
Spherecastを使用している場合、この値が大きいほどターゲットを見つける範囲が大きくなる。
No Snap Threshhold
オブジェクトとの距離がこの値より近い場合は、通常のGrabberと同じように掴みます。
この値より離れている場合は手元に引き寄せます。
Use Spherecast
Spherecastを使ってターゲットを見つけるかどうか。
Prevent Grab Through Walls
Object Pull Velocity
離れたオブジェクトを掴む時に、手元に飛んでくる速度。
例を用意しました、左手が速度2、右手が速度10です。
Max Grab Distance
掴むことのできるオブジェクトの範囲。
Grab Objects In Layer & Obstruction Layer
掴むターゲットにするレイヤーの数字。
Player
Playerのオブジェクト、子オブジェクトからGrabManagerのSphereColliderを参照するのに使う。
DistanceGrabbable
このコンポーネントはOVR Grabbableを継承して作られています。
そのため使い方やインスペクターはOVR Grabbableに規準しています。
特に変更点はありません。
通常のGrabbableと同様に、近づいて掴む機能はそのまま使うことができます。
GrabManager
これはGrabする範囲を決定するコンポーネントです。これがないとGrabberが動きません。
SphereColliderとセットで扱います。(要isTrigger)
サンプルシーンではOVRPlayerControllerの子オブジェクトになっています。
必ずプレイヤーの子オブジェクトにする必要があります。
Outline Colorから、範囲内のオブジェクトにアウトラインをつけることができます。
SphereColliderのRadiusの値を変えるだけで簡単に範囲を設定できます。
GrabManagerのスクリプト内ではCollider型で参照しているのでSphere以外のColliderも使うことができる・・・
かと思いきや、実はDistanceGrabberがSphereCollider型でGetComponentしているのでSphereしかだめみたいです。
実際に掴めるオブジェクトを置いてみる
では実際に掴むことができるオブジェクトをテーブルの上に新しく作ってみましょう。
今回もユニティちゃんを使用します。
Hierarchyビューでは、Grabbableをアタッチする用に空のオブジェクトを作り、その中にユニティちゃんを格納する構造にします。
空のオブジェクトのインスペクターはこんな感じです。
前回とほとんど同じですが注意すべき点が2つあります。
Mesh Renderer
OVR Grabbableと違い、MeshRendererコンポーネントは必須です。
Grabbableをアタッチするオブジェクトに必ずつけましょう。
すでに何らかのRendererがついていれば必要ありません。
Rigidbody Collision Detection
RigidbodyのCollision DetectionはContinuous Dynamicにしないと掴むことができません。
これだけで準備完了、実際に動かしてみましょう。
無事掴むことができ、投げることもできました。
まとめ
離れているオブジェクトを掴む時はDistanceGrabberコンポーネントを使う
手っ取り早く用意するのであれば、
Assets/Oculus/SampleFramework/Core/DistanceGrab/Prefabsにあるプレハブを使うのがおすすめ。
掴まれるオブジェクトにはDistanceGrabbableを使う
DistanceGrabberを動作させるにはシーン上にGrabManagerを設置する
参考文献
Distance Grab Sample Now Available in Oculus Unity Sample Framework | Oculus
次回は、掴みたいオブジェクトにクロスヘアを表示したり、
演出面についてやっていきます。
他間違っている箇所、不明な点、わかりにくい点がありましたらコメントにお願いします。