UnityでOculus Integrationを使わずにOculus TouchやHMDのパラメータを取得する方法(for Oculus Quest)

###最初に
Oculus Questアプリの開発においてはOculus Integrationを使うのが正しい手法だとは思いますが、マイノリティな方法として表に出ていない気がしたのでメモしておきます。メリットとしては入力系の処理を通常のUnityアプリと同じ肌感覚で実装でき、Unityのバージョンアップ時にアセット側のアップデートを待たなくて良い点があります。デメリットとしてはGrabやMoveやuGuiの入力処理など、ライブラリに依存している部分の処理を自前で実装しなくてはいけない点です。

ビルド環境については先人の知恵を参考にしましょう。
[Unity＋Oculus Quest 開発メモ - フレームシンセシス](https://framesynthesis.jp/tech/unity/oculusquest/)
[Oculus Quest に Unity で開発したアプリをいれる方法（Mac/Win） - Qiita](https://qiita.com/Tomoyuki_Mikami/items/be9b3bf605a5d953be1b)

###開発環境
Unity 2019.1.5f1 Personal

###Oculus Touchの入力をInputManagerで設定する
参考 : [OpenVR コントローラーの入力](https://docs.unity3d.com/ja/2019.1/Manual/OpenVRControllers.html)

`Edit` > `Project Settings` > `Input`から設定していきます。サンプルについては以下のスクリーンショットを。

<img width="417" alt="setting_xy.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/45a19074-a57d-9035-0e69-f97d9f4f95cf.png">
<img width="405" alt="setting_xy2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/8505947e-611f-4901-bc3f-189e79db33ea.png">
<img width="402" alt="setting_12.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/ff3aeed6-db11-844f-28cc-dc7852d7bd62.png">
<img width="398" alt="setting_r12.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/af697505-5b27-cecb-2bc9-678746650695.png">
<img width="405" alt="setting_1617.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/bd0279e1-0cba-7028-df06-be5fd7766de1.png">
<img width="402" alt="setting_leftindex.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/ead29fe6-c78d-e189-0476-ca4f3e1292c7.png">
<img width="398" alt="setting_rightindex.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/dafc6cda-5a81-3451-9b19-ed5a99b246c5.png">
<img width="402" alt="setting_89.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/1160b344-9c23-2439-9ddb-3eeb610b593f.png">

InputManagerの設定後、以下のスクリプトをGameObjectにアタッチすると、入力値をチェックできます。

```csharp:TouchChecker.cs
using UnityEngine;

public class TouchChecker : MonoBehaviour
{
    void Update()
    {
        if(Input.GetAxis("Horizontal") != 0){
            Debug.Log("Horizontal:" + Input.GetAxis("Horizontal"));
        }

        if(Input.GetAxis("Horizontal2") != 0){
            Debug.Log("Horizontal2:" + Input.GetAxis("Horizontal2"));
        }

        if(Input.GetAxis("Vertical") != 0){
            Debug.Log("Vertical:" + Input.GetAxis("Vertical"));
        }

        if(Input.GetAxis("Vertical2") != 0){
            Debug.Log("Vertical2:" + Input.GetAxis("Vertical2"));
        }

        if(Input.GetButtonDown("VR_Left_Button1")){
            Debug.Log("l1");
        }

        if(Input.GetButtonDown("VR_Left_Button2")){
            Debug.Log("l2");
        }

        if(Input.GetButtonDown("VR_Right_Button1")){
            Debug.Log("r1");
        }

        if(Input.GetButtonDown("VR_Right_Button2")){
            Debug.Log("r2");
        }

        if(Input.GetButtonDown("VR_Left_Start")){
            Debug.Log("lStart");
        }

        if(Input.GetButtonDown("VR_Left_Button8")){
            Debug.Log("l push");
        }

        if(Input.GetButtonDown("VR_Right_Button9")){
            Debug.Log("r push");
        }

        if(Input.GetAxis("VR_Left_Index") > 0){
            Debug.Log("VR_Left_Index:" + Input.GetAxis("VR_Left_Index"));
        }

        if(Input.GetAxis("VR_Left_Hand") > 0){
           Debug.Log("VR_Left_Hand:" + Input.GetAxis("VR_Left_Hand"));
        }

        if(Input.GetAxis("VR_Right_Index") > 0){
           Debug.Log("VR_Right_Index:" + Input.GetAxis("VR_Right_Index"));
        }

        if(Input.GetAxis("VR_Right_Hand") > 0){
           Debug.Log("VR_Right_Hand:" + Input.GetAxis("VR_Right_Hand"));
        }
    }
}
```

###トラッキングポジションの取得
主観ですが、RoomScaleよりStationaryの方が開発しやすいです。
RoomScaleが前提のアプリでも、Stationaryで作っています。闇ですね。
以下のスクリプトをGameObjectにアタッチすると、トラッキングポジションをチェックできます。

```csharp:TrackingSample.cs
using UnityEngine;
using UnityEngine.XR;

public class TrackingSample : MonoBehaviour
{
    void Start()
    {
        XRDevice.SetTrackingSpaceType(TrackingSpaceType.Stationary);
        ////RoomScaleの場合
        // XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale);
    }

    void Update()
    {
        Debug.Log("LeftHand_Position : " + InputTracking.GetLocalPosition(XRNode.LeftHand));
        Debug.Log("RightHand_Position : " + InputTracking.GetLocalPosition(XRNode.RightHand));
        Debug.Log("HMD_Position : " + InputTracking.GetLocalPosition(XRNode.CenterEye));
        Debug.Log("LeftHand_Rotation : " + InputTracking.GetLocalRotation(XRNode.LeftHand));
        Debug.Log("RightHand_Rotation : " + InputTracking.GetLocalRotation(XRNode.RightHand));
        Debug.Log("HMD_Rotation : " + InputTracking.GetLocalRotation(XRNode.CenterEye));
    }
}
```
###カメラについて
<img width="124" alt="camera.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20884/31719bb7-6e83-8842-1791-a021e5d72504.png">
空のGameObjectと親子関係にして、親のObjectを動かすのがベストだと思います。

###Oculus Questで使えなかった機能
`InputTracking.Recenter();` → OculusButtonの長押しで代用可能なので、そこまで重要ではない。
`Button.Start`(Unity Button ID : 7) → Oculus Quest上で反応無し。Oculus Riftでも使用不可能(Riftの場合はSteamVR側にBINDされているのが原因？)。

###最後に
Oculus Integrationに依存したくない方、全て自力で実装したい場合について、この方法は有用なんじゃないかと思います。Oculus Rift向けに作成したアプリについては、ステレオパスでビルドターゲットを変更するだけで簡単に動作しました。パフォーマンスは当然微妙でしたが。


###参考リンク
[XR - Unity マニュアル](https://docs.unity3d.com/ja/2019.1/Manual/XR.html)
[102 2 レーザーコントローラー · yumemi-inc/vr-studies Wiki](https://github.com/yumemi-inc/vr-studies/wiki/102-2-%E3%83%AC%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC)
[Unity標準のVR機能（UnityEngine.XR）メモ - フレームシンセシス](https://framesynthesis.jp/tech/unity/xr/)