【Oculus Quest 開発TIPS】テレポートやGUI操作を簡単に解決する


要約

Oculus Quest での開発初期に、こういうのとりあえず実装したいみたいになりませんか?

  • テレポートしたい
  • 水平移動したい
  • レーザーでGUIを操作したい
  • バーチャルキーボードで入力したい
  • 3Dオブジェクトを選択したい

Oculus Integration に含まれているサンプルを利用することで簡単に解決できます。
解決方法だけでなく、ある程度の範囲が調整できるので、それらも含めた紹介です。

前提

Name Version
Unity 2019.4.9f1
Oculus Integration 25.0
Oculus Quest 1 or 2

テレポートしたい

いきなり他の方の実装方法の紹介になりますが、
Oculus Integration を用いた テレポート / ワープ の実装方法 [Oculus Quest] が詳細でわかりやすいです。

操作方法

  • 右手のスティックを倒すとテレポート後のポイントが表示され、スティックを離すとテレポートします。
  • 右手のスティックを倒している方向で、テレポート後の向きが決まります。

サンプルでこんな調整もできます

  • テレポートできる最大距離を設定することが可能です。
    • TeleportAimHandlerLaser の Range を変更してください。単位はメートルです。
  • 直線レーザーだけでなく、釣り竿式の間がレーザーも出力できます。
    • TeleportAimHandlerLaser の代わりに、TeleportAimHandlerParabolic を設定してください。
  • テレポート後の回転はなくすこともできます。
    • TeleportOrientationHandlerThumstic の Thumbstick に None を設定してください。

補足

  • 上記手順で実行すると正常に動いているように見えますが、裏で NullReferenceException が出ていました。
    CharacterCameraConstraint で OVRScreenFade の参照がないので出ているエラーでした。同じオブジェクトに OVRScreenFade を追加して参照を入れてあげれ解決されます。

水平移動したい

テレポートの設定方法 がされている前提です。
SimpleCapsuleWithStickMovment の Speed を0より大きい値で設定してあげてください。
左手のスティックで移動できるようになります。

操作方法

  • 左手のスティックを倒すと、前後左右に水平移動します。

サンプルでこんな調整もできます

Speed と書いてある通り、値を大きくすると移動スピードが大きくなります。
水平移動はVR酔いしやすいので取扱注意です。
個人的には Speed=1 とか遅すぎても酔いやすい気がしています。

おまけ

  • デフォルトの設定では SimpleCapsuleWithStickMovement の RotationAngle に 45 が設定されています。これは右手のスティックを左右に倒すと回転する角度です。0 にすることでオフにすることができます。

レーザーでGUIを操作したい

  1. 操作したい uGUI のキャンバスに OVRRayCaster を設定します。
  2. Oculus/SmapleFramework/Core/DebugUI/Prefabs/UIHelpers を操作したい手に入れます。
  3. UIHelpers を展開するとその下に EventSystem が含まれています。これが VR 用の EventSystem となります。
  4. EventSystem に設定されている OVRInputModule に以下設定を入れます。
  5. 既存の EventSystem は削除します。

操作方法

  • OVRRayCaster を設定したキャンバス上に、通常の uGUI のつもりでボタン等を設置していくだけです。
  • UIHelpers だけでレーザーも出るようになっています。
  • 右手から出ているレーザーでキャンバス上のボタンを指し示した状態で、右手のトリガーをひけば、ボタンをクリックできます。

サンプルでこんな調整もできます

  • 右手に入れたUIHelpersを左手に入れれば左手で操作できます。
  • Secondary -> Primary に変更すれば左手で決定できます。

おまけ

  • Canvas を左手、あるいは頭と連動させることで、移動してもついてくるよなUIも作れます。(サンプルにはありませんが・・・)

バーチャルキーボードで入力したい。

レーザーでGUIを操作したいができている前提です。

  1. OVRCameraRig に設定されている、OVRCameraManagaer にある以下設定のチェックボックスを ON にします。 InputField への Text 入力は超簡単

以上!!

操作方法

  • uGUIにインプットフィールドを作っておいて、レーザー選択(トリガーを押す)とバーチャルキーボードが表示されます
    • 私が実行した限り Go とかのボタンは効かず、元に戻るときは一番下のキーボードみたいなボタンを押していました

3Dオブジェクトを選択したい?

VRPhyisicsRaycaster を利用して選択する方法も

Oculus が準備している方式で、サンプルにも含まれています。ただ以下理由から私自身は採用するのをやめました。

  • 基になっている UnityEngine.EventSystems が Unity 2019.4 版からドキュメントがありません。これ以上伸びないかもしれないAPIを利用するのは負債にしかならない気がしました。
  • Ray がヒットされるほうにイベントを書くので、GUI 的な使い方なら問題ないかなと思いますが、ヒットさせたほうで何かしたい時にはコードが歪になるかなと思いました。

それでもやるなら

レーザーでGUIを操作したいができている前提です。

  1. OVRCameraRig が入っているコンポーネントのころに、OVRPhysicsRaycaster を追加します。
    • OVRPhysicsRaycaster が OVRCameraRig を前提としています
  2. 以下コードを書いて、レイキャスト されるほう(するほうじゃなくてされるほう) に設定します。
public class PointerButton : MonoBehaviour, IPointerEnterHandler, IPointerClickHandler, IPointerExitHandler
{
    [SerializeField] private TextMeshProUGUI text1;
    [SerializeField] private TextMeshProUGUI text2;

    public void OnPointerEnter(PointerEventData eventData)
    {
        text1.text = "Raycast hit :) at Plane";
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        text1.text = "Raycast out :( at Plane";
    }
    public void OnPointerClick(PointerEventData eventData)
    {
        var obj = eventData.pointerCurrentRaycast.gameObject;
        var pos = eventData.pointerCurrentRaycast.worldPosition;
        text2.text = $"{go.name}({obj}) is Clicked!";
    }
}

参考

How to check if Oculus Go controller on OVRInputModule is clicking on GUI object or not

Furthermore, whatever "Event Mask" you select for your OVRPhysicsRaycaster in the camera rig, any normal (non-UI) 3D object that is in that layer will detect the same IPointerEnterHandler and IPointer...Handler events just like a UI button, so you can use the same code for those objects as well, not just the UI objects.

他の方法で選択したい

こちらの Oculus Goでコントローラ操作(3DオブジェクトとuGUI) を参考にすればとわかりやすいかと思います。

他参考