Raspberlyのブログ

Raspberlyのブログ

Unityネタをメインとした技術系ブログです。にゃんこ大戦争や日常なども。そろそろブログタイトル決めたい

【Oculus Quest開発メモ】離れた場所にある物を掴む Distance Grabber & Grabbable編【Unity】

今回はOculus Questの開発ネタをやっていきます。
内容的にはOculus Rift Sなどにもそのまま応用できるかと思います。

 

Oculus Touchコントローラーで離れた場所にあるものを掴む方法について解説します。
プレイエリアが狭い時や、座ったままプレイさせたい時など自由に動き回るのが困難な時に役立ちます。

他にも、机から床に落ちてしまったオブジェクトを拾う時などプレイヤーの負担を軽減できます。

f:id:Raspberly:20190616202258p:plain

 

 

 

開発環境

Windows 10

Unity 2018.4.1f

Oculus Integration ver1.37

Oculus Quest

 

 

先行研究

www.youtube.com

 

 

セットアップ

前回の記事をあらかじめ見ておいてください。

raspberly.hateblo.jp

前提として、Project内にAssetStoreからOculus Integrationをインポートしておく必要があります。


 

 

サンプルシーンの確認

Assets/SampleFramework/Usageに様々なサンプルシーンがあります。
離れた物を掴むサンプルシーンはDistanceGrabになります。
学習や挙動の確認にとても有益です。見てみましょう。

f:id:Raspberly:20190610220845p:plain

 

実行してみるとこんな感じになります。

f:id:Raspberly:20190610225504g:plain

 

 

Oculus Integration 1.42で修正されました

ちなみにこのサンプルシーンには深刻なバグが存在しています
それは物を掴んだ時にPlayerが吹き飛ばされることです。

f:id:Raspberly:20190615234528g:plain



原因はGrabbableとPlayerの衝突のようです。

 

 

サンプルシーンのバグ修正

このバグを修正する方法を載せておきます。

PlayerにはCharacterControllerがくっついています。

f:id:Raspberly:20190610231445p:plain

 

このColliderとGrabbableのColliderが接触しないようレイヤーを分けます。
[Player][Grabbable]レイヤーを新しく作成します(名前はなんでもいいです)

f:id:Raspberly:20190611000330p:plain

シーン内にあるOVRPlayerControllerはPlayerレイヤーにしましょう。

f:id:Raspberly:20190611000531p:plain

この時、子オブジェクトのレイヤーは変えないでください(理由は後述)

 

その後、サンプルシーンの中にあるDistanceGrab~~~と名前のつく掴みたいオブジェクトを全てGrabbableレイヤーにします。

f:id:Raspberly:20190611001104p:plain

f:id:Raspberly:20190611001140p:plain

 

最後にProjectSettingのPhysicsからPlayerとGrabbableのチェックを外しておきます。

f:id:Raspberly:20190611001453p:plain

 

これでPlayerが吹き飛ばされることなくシーンが動きます。

f:id:Raspberly:20190615234611g:plain

 

 

他には、CharacterControllerを切ってしまうという手段もあります。

f:id:Raspberly:20190616081709p:plain



 

 

 

 

 

 

 

主要コンポーネント

こちらもOVR Grabber&Grabbable同様Oculus側でコンポーネントが用意されています。
そちらを使っていきましょう。
これらはインポートしたOculus Integrationの
Assets/Oculus/sampleFramework/Core/DistanceGrab/Scriptsにあります。

DistanceGrabber

こちらは物を掴む側、つまり手につけるコンポーネントになります。

DistanceGrabbable

こちらは物を掴まれる側、つまりオブジェクト側につけるコンポーネントになります。

Grab Manager

こちらは物を掴む範囲を決めるコンポーネント、DistanceGrabberを使うのに必須です。

 

 

 

DistanceGrabber

DistanceGrabのシーンにある、DistanceGrabを見てみましょう。

f:id:Raspberly:20190611213013p:plain

f:id:Raspberly:20190611213643p:plain

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です。

f:id:Raspberly:20190616214619g:plain

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から、範囲内のオブジェクトにアウトラインをつけることができます。

f:id:Raspberly:20190616163827p:plain

 

SphereColliderのRadiusの値を変えるだけで簡単に範囲を設定できます。

f:id:Raspberly:20190616163746p:plain

GrabManagerのスクリプト内ではCollider型で参照しているのでSphere以外のColliderも使うことができる・・・
かと思いきや、実はDistanceGrabberがSphereCollider型でGetComponentしているのでSphereしかだめみたいです。

 

 

 

 

実際に掴めるオブジェクトを置いてみる

では実際に掴むことができるオブジェクトをテーブルの上に新しく作ってみましょう。
今回もユニティちゃんを使用します。

f:id:Raspberly:20190616173300p:plain

 

Hierarchyビューでは、Grabbableをアタッチする用に空のオブジェクトを作り、その中にユニティちゃんを格納する構造にします。

f:id:Raspberly:20190616172508p:plain

 

空のオブジェクトのインスペクターはこんな感じです。

f:id:Raspberly:20190616172323p:plain



前回とほとんど同じですが注意すべき点が2つあります。

Mesh Renderer

OVR Grabbableと違い、MeshRendererコンポーネントは必須です
Grabbableをアタッチするオブジェクトに必ずつけましょう。
すでに何らかのRendererがついていれば必要ありません。

Rigidbody Collision Detection

RigidbodyのCollision DetectionはContinuous Dynamicにしないと掴むことができません

f:id:Raspberly:20190616173031p:plain

 

 

 

これだけで準備完了、実際に動かしてみましょう。
無事掴むことができ、投げることもできました。

f:id:Raspberly:20190616201442g:plain

 

 

 

 

 

 

まとめ

離れているオブジェクトを掴む時はDistanceGrabberコンポーネントを使う

 手っ取り早く用意するのであれば、
Assets/Oculus/SampleFramework/Core/DistanceGrab/Prefabsにあるプレハブを使うのがおすすめ。

掴まれるオブジェクトにはDistanceGrabbableを使う
DistanceGrabberを動作させるにはシーン上にGrabManagerを設置する

 

 

参考文献

DistanceGrab Sample Scene

Distance Grab Sample Now Available in Oculus Unity Sample Framework | Oculus

 

 

 

次回は、掴みたいオブジェクトにクロスヘアを表示したり、
演出面についてやっていきます。

 

 

他間違っている箇所、不明な点、わかりにくい点がありましたらコメントにお願いします。