OVRGrabbableに使いやすいSnapPointを実装する

Unity

以前,OVRGrabbableについてご紹介しました. この時, SnapPointは非常に使いにくいので使わないように設計しましょうという話をしました.

SnapPointを使わない場合, オブジェクトの座標(原点)は下の画像のように設定します.

これが銃なら大した違和感はないのですが(z軸を銃口の向きと一致させるため), 剣や刀の場合はこのようにオブジェクトの見た目の向きとは異なる方向をオブジェクト座標系は向いています.これでは剣を並べたり, 剣を飛ばしたりする時の設計が非常に面倒なことになってしまいます.

そこで今回は直感的に使えるSnapPointを実装していきます.

では実際にどうすればいいのかということですが, 要はオブジェクトを掴んだ時と掴んでいない時でメッシュとコライダーの位置を変えてしまえばいいのです.

次の3つのスクリプトをダウンロードしてUnityのプロジェクトに追加してください. これらのスクリプトはそれぞれ次の機能を持っています.

  • CustomOVRGrabbable.cs: OculusのOVRGrabbableに使いやすいSnapOffsetを実装したもの. さらにCustomOVRGrabberから掴んでいる手(右手か左手か)を取得してコントローラの状況を取得できるようにしている.
  • CustomOVRGrabber.cs: OculusのOVRGrabberにコントローラの情報をCustomOVRGrabbableに送れるようにしたもの.
  • IfGrabbable.cs: CustomOVRGrabbable.cs用のインターフェース

Grabbable側からコントローラの情報を取得する方法については, Kohki Nakajiさんの記事を参考にさせていただきました.

【Oculus Quest】OVRGrabbableでかっこよく銃を実装する - Qiita
はじめに以下の記事の中で、「Individualなキーマッピングは左右を区別しないため、モノ自体にトリガーを持たせる場合に活躍をする」という話をしました。この記事では、その思想に則ってキー入力を必…

これらのスクリプトの使い方は次の通りです.

  1. OVRGrabberCustomOVRGrabberに置き換えます, CustomOVRGrabbableのパラメータはOVRGrabberと同じにします.
  2. OVRGrabbableCustomOVRGrabbableに置き換えます,
  3. CustomOVRGrabbableをアタッチしたオブジェクトを次のような構成にします.

  1. BodyTrans に持ちたいオブジェクトを設定します. 今回は剣です.
  2. GrabTrans に持った時にGrabberのGrab TransformにスナップさせるTransformを設定します. 内部的には GrabTransGrab Transformが一致するように持った時にGrabTransBodyTransを移動させています.

別の刀剣になりますが, 実際に使用したのが次の動画です.

左の刀がOVRGrabbableで右の剣がCustomOVRGrabbableを使用したものです. 大きい矢印がそれぞれの原点と座標系を表しています. 剣についている小さい矢印がGrabTransです. 掴んでいる時にGrabTrans(とBodyTrans)が移動していることがわかります.


2020/1/24追加

CustomOVRGrabbale.csを更新しました.
Start()を削除.
GrabBegin()GrabEnd()内のオブジェクトの移動をそれぞれSetGrabbedArrangement(), SetUngrabbedArrangement()というメソッドに移行.
GrabBegin()GrabEnd()にコールバックを追加することができるようになる.
– プロパティにcontrollerを追加. 別のスクリプトからでもコントローラの状態にアクセルすることが可能に.
– メソッドMoveInHand()を追加.Grabberのgrabpointの位置と姿勢を渡すことで,オブジェクトを手元に移動させることができる.

OVRGrabber.csとの間に起こるバグを確認しました.
CustomOVRGrabbaleを持ったオブジェクトが持っている間に破壊された後,掴んでいた手でものが掴めなくなることがあります(おこらないこともあるが詳細不明).
OVRGrabber.csBeginGrab()grabbableCollidernullになっておりnullの例外エラーが発生しています.対処療法ですが,grabbableColliderのnullチェックを行ってください.具体的にはfor (int j = 0; j < grabbable.grabPoints.Length; ++j){}の中でCollider grabbableCollider = grabbable.grabPoints[j];の次の行以降をif (grabbableCollider != null){}で囲ってください. 

コメント

タイトルとURLをコピーしました