【Oculus Quest2】レーザーポインターでUIと物理オブジェクトを操作する 

![写真 2022-06-23 15 56 56.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/26406cc4-0b0d-8d10-4358-913c4655724c.gif)

UnityのUIシステム(UGUI)には2種類のレイキャスターがあります。
UI操作に使用するGraphicRaycasterと、Colliderを検知してイベント発火するPhysicsRaycasterです。
VRアプリ開発で使うにはどちらもVR用に置き換える必要がある為、その手順を解説します。

古い記事しか見つからずハマったので、当記事は下記リンクをもとに最新情報に書き換えた形の備忘録です。

### 環境
Windows 11
Unity 2021.3.4f1
Oculus Integration 40.0
Oculus Quest 2

### 参考にさせて頂きました

[Oculus Goでコントローラ操作(3DオブジェクトとuGUI)](https://qiita.com/okyk/items/efca6be5bc874333e8eb)
[Oculus GoのコントローラからレーザーポインタによりUIを操作するまで](https://scrapbox.io/oculusgogo/Oculus_Go%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%81%8B%E3%82%89%E3%83%AC%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E3%81%AB%E3%82%88%E3%82%8AUI%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A7)
[Unity’s UI System in VR](https://developer.oculus.com/blog/unitys-ui-system-in-vr/)

# UnityにおけるRaycaster
ざっくり説明すると「コントローラーから出る光線で何かを操作する機能」です。
レーザーポインターを出し、その当たり判定を行い、何らかの処理を行うために使用します。

UnityのRaycasterには UI用の`GraphicRaycaster`と 物理オブジェクト用の`PhysicsRaycaster`の2種類がありますが、VR用に実装する場合はそのままでは使えません。
Oculus Integrationに含まれるVR用のRaycasterに置き換える必要があります。

>**`OVRRaycaster`**
　VR用の、GraphicRaycasterに相当するもの
**`OVRPhysicsRaycaster`**
>　VR用の、PhysicsRaycasterに相当するもの


# 準備
準備の手順は簡略化して記述します。不明点があれば他の記事をご参照下さい。
### VR用の環境準備
- Oculus Integration をインポート
- Planeをシーン上に配置
- **MainCameraを削除、OVRCameraRig を配置、左右のコントローラーを導入**
CustomHand や OVRControllerPrefab を OVRCameraRig の HandAnchor に配置。お好みの設定に調整します。


### レイキャスターのテスト用オブジェクトを準備
- **Cube をシーン上に配置**
物理オブジェクトのイベント発火を実装します。Colliderが付いていれば何でもOK

- **Button をシーン上に配置**
ボタンのクリックによるイベント発火を実装します。
Buttonオブジェクトは「クリック操作のできる土台の Button に Text が乗っている」という構成になっており、ImageコンポーネントからButtonの見た目を変えられます。
　
簡単に手順を解説します。

> 1. ヒエラルキービューで右クリック、 UI > Button-TextMeshPro を新規作成
> 2. 下記画像を参考に、Canvas の設定を整える
> 3. Button と Text(TMP) が小さすぎるので、WidthやScaleをお好みで大きくする
![スクリーンショット (30).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/a79401e8-b3a4-0e35-6be3-81c9fa93d89b.png)


# VR用に部品を入れ替える
Canvasを作成すると自動的にEventSystemが作成されますが、このままではVRで利用できません。
StandaloneInputModuleコンポーネントが、マウスのクリックや画面タップに対応するものだからです。
VRに対応するEventSystemに入れ替える必要があります。

## UIHelpers の導入
下記の手順でEventSystemを入れ替え、レーザーポインターを用意しましょう。


> 1. 自動生成されたEventSystem を削除
> 2. Oculus Integrationのプレハブアセット `UIHelpers`をヒエラルキービューにD&D
> 3. UIHelpers > LaserPointer の LineRenderer のチェックボックスをONにする

UIHelpers に含まれるEventSystemには`OVR Input Module`コンポーネントが付いており、これがVR対応に必要となります。

LaserPointer の LineRendererコンポーネントは、レーザーポインターを視覚的に表示するための部品です。
Materialsから色を変えたり、Widthから太さを変えたりして調整できます。


# UI用のレイキャスターをVRで使う
Buttonをレイキャスターでクリックし、イベント発火する手順を解説します。
## OVRRaycaster に入れ替える
Canvasを見ると、GraphicRaycaster コンポーネントが付いています。
これもマウスのクリックや画面タップに対応する部品である為、VR用のものに入れ替えましょう。
> 1. CanvasのGraphicRaycasterを削除
> 2. Canvasに`OVRRaycaster`コンポーネントをアタッチ


## Buttonにスクリプトをアタッチ
今回はButton自身に ButtonTest というスクリプトを付けて動作をテストします。
下記のようにスクリプトを作成・アタッチしましょう。
OnClick関数の中身はお好みで書き換えて下さい。
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ButtonTest : MonoBehaviour
{
    public void OnClick()
    {
        Debug.Log("Buttonをクリックしました");
    }
}
```
## OnClick を設定
Buttonのインスペクターを見ると、**OnClick()** という項目があります。
ここの＋を押し、スクリプトの関数やコンポーネントのプロパティ値を登録することで、ボタンがクリックされた際にその処理が行われるようになります。
先程のスクリプトがButtonのクリックで発火するように、Buttonのインスペクターを設定しましょう。

下の画像を参考にしてください。

> 1. OnClick() の＋を押す
> 2. クリックによりイベントを発火させたいオブジェクトをD&Dする(今回はButton自身)
> 3. ドロップダウンリストから、クリックにより発火させたい処理を選択する(今回はButtonTestスクリプトのOnClick関数)

![スクリーンショット (32).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/d5a081c3-91e4-d721-81c0-77bbfe130fc6.png)


以上でUI用レイキャスターが使用できるようになりました。

# 物理オブジェクト用のレイキャスターをVRで使う
Colliderのあるオブジェクトをレイキャスターでクリックし、イベント発火する手順を解説します。
古い記事しか見つからず大変苦戦した部分なので、筆者にとってはここからが本題です。笑

## OVRPhysicsRaycaster の導入
OVRCameraRig に `OVRPhysicsRaycaster`コンポーネントを追加します。
EventMask の項目でレイキャスターでクリックできるレイヤーを指定できるので、レイヤーを新規作成して設定しておくと良いです。

> 1. レイヤーを新規作成
> 2. OVRPhysicsRaycaster の EventMask に作ったレイヤーを設定
> 3. クリックしたい物理オブジェクト(今回はCube)のレイヤーを、作ったレイヤーに設定

## Cubeにスクリプトをアタッチ
今回はCube自身に CubeTest というスクリプトを付けて動作をテストします。
下記のようにスクリプトを作成・アタッチしましょう。
OnPointerClick関数の中身はお好みで書き換えて下さい。

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CubeTest : MonoBehaviour
{
    public void OnPointerClick()
    {
        Debug.Log("Cubeをクリックしました");
    }
}
```

## EventTrigger を設定
Cube に`EventTrigger`をAdd Componentします。
このコンポーネントには **PointerClick()** が設定できるようになっており、先程のButtonの OnClick() と同じように使用することができます。
スクリプトの関数やコンポーネントのプロパティ値を登録することで、物理オブジェクトがクリックされた際にその処理が行われるようになります。

先程のスクリプトがCubeのクリックで発火するように、Cubeのインスペクターを設定しましょう。
> 1. Add New Event Type をクリックし、PointerClickを追加
> 2. PointerClick() の＋を押す
> 3. クリックによりイベントを発火させたいオブジェクトをD&Dする(今回はCube自身)
> 4. ドロップダウンリストから、クリックにより発火させたい処理を選択する(今回はCubeTestスクリプトのOnPointerClick関数)

![スクリーンショット (33).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/65eaa611-21d1-ff6d-036e-bf05de3f7b32.png)
以上でColliderを検知するレイキャスターが使用できるようになりました。

<br>
<br>

## おまけ

![写真 2022-06-23 15 56 56.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/a0168f1d-92b4-8405-2a02-46b3949cf21d.gif)


こちらのGIF画像では、クリックによりTextの内容が変わるようにスクリプトを書いています。
それぞれ、下記の内容です。

```:Button
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//UI系の部品を使う際に必要
using UnityEngine.UI;
//TextMeshProを使う際に必要
using TMPro;

public class ButtonTest : MonoBehaviour
{
    public TextMeshProUGUI text;
    public void OnClick()
    {
        text.text = "ボタンをクリックしました";
    }
}
```


```:Cube
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//UI系の部品を使う際に必要
using UnityEngine.UI;
//TextMeshProを使う際に必要
using TMPro;

public class CubeTest : MonoBehaviour
{
    public TextMeshProUGUI text;
    public void OnPointerClick()
    {
        text.text = "Cubeをクリックしました";
    }
}

```

お疲れ様でした。