OVRCameraRig についてのあれこれ

#対象者
　[Oculus Integration](https://assetstore.unity.com/packages/tools/integration/oculus-integration-82022) をなんとなくで使っている方。（現段階でゴリゴリ使っている方には当たり前の内容かもしれませんが悪しからず）

＊筆者はRiftを持っておらず、**以下の検証はすべてOculusQuest でのもの**になりますが、基本的には同じだと思います。また、OculusGoは3DoFのため、一部の情報はGoには当てはまらないことがあります。
#初めに
　OVRCameraRigはOculus公式にて用意されたアセット"Oculus Integration"内に含まれるPrefabで、シーン中にドロップするだけで簡単にVRの世界に入ることのできる優れものです。ですが、VRの開発の宿命ともいえますが、逐一HMDを被らないといけず、**デバックが死ぬほど面倒くさい**ため、ふわっとした理解のまま開発進めていました。
　・・・が現在開発中のコンテンツでOVRCameraRigの詳しい知識が必要になってしまったので、せっかくなのできちんと調べてみることにしました。
###実行環境
Unity2019.1.4f1
OculusQuest ver 8.0.0
Oculus Integration ver 1.40

#Transform情報

　**実機上でのOVRCameraRig内のTransform**がどうなっているか知りたくなったので調べてみることにしました。（具体的には、**現実世界での移動値、回転値がOVRCameraRig内のどこに反映されるのか**、等です。）


　OVRCameraRigは以下のような階層構造になっています。（なお、OVRControllerPrefabに関しては本来は一定ないオブジェクトですが、コントローラーを表示するために追加しました）
![OVRCameraRig階層.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422708/330e1f62-b272-6695-3e3d-91badb0f3747.png)

今回は、実機上での赤線のTransform情報を調べてみました。

####検証結果

| Trackするもの | 対応するオブジェクト |
|--------------|:----------------------------:|
| HMD本体の動き | EyeAnchor(Center,Left,Right) |
| Controllerの動き|HandAnchor(Left,Right)|

　現実でy軸にHMDを+1動けば、CenterEyeAnchor,LeftEyeAnchor,RightEyeAnchorもy軸に+1します。具体的にどうなっているかは下記動画の方を見てもらえばわかると思います。

＊上からもわかる通り、**EyeAnchorとHandAnchor のPositionをスクリプトで操作しても動かすことはできません**（一時的に3DoFにしたりすれば可能だとは思います。その他にも抜け道はあると思います・・・）

　余談ですが、コントローラーがロストした時には、Transform値はロスト直前の値で止まり、回転は普通に反映される、いわゆる3DoFの動きになります。
####動画
　ローカルでのPositionとRotationの値をTextに表示させています。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">この前の実機上でのOVRCameraRig内のTransform値図るやつ見やすくした版。 <a href="https://t.co/r8KFYjZFYz">pic.twitter.com/r8KFYjZFYz</a></p>&mdash; ほるかす@めぐるーまー (@pwhrhs) <a href="https://twitter.com/pwhrhs/status/1170340619232759808?ref_src=twsrc%5Etfw">September 7, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

####ソースコード
大したことしてないですが、検証方法に誤りがあったときのために一応載せておきます

```
public class OVRCameraRigTransformInfo : MonoBehaviour
{
    [SerializeField]
    private Text text;  //情報を乗せるText

    [SerializeField]
    private GameObject[] go;    //知りたいObjectをアタッチ

    
    private void Update()
    {
        text.text = "";    
        foreach(var obj in go)
        {
            GetGameObjectPositon(obj);
        }

    }

    private void GetGameObjectPositon(GameObject obj)
    {
        /*
        float worldPosX = obj.transform.position.x;
        float worldPosY = obj.transform.position.y;
        float worldPosZ = obj.transform.position.z;
        */

        float localPosX = obj.transform.localPosition.x;
        float localPosY = obj.transform.localPosition.y;
        float localPosZ = obj.transform.localPosition.z;

        /*
        float worldRotX = obj.transform.rotation.x;
        float worldRotY = obj.transform.rotation.y;
        float worldRotZ = obj.transform.rotation.z;
        */

        float localRotX = obj.transform.localRotation.x;
        float localRotY = obj.transform.localRotation.y;
        float localRotZ = obj.transform.localRotation.z;
 
        text.text += obj.name + " Pos " + " X: " + localPosX.ToString("0.000") + " Y: " + localPosY.ToString("0.000") + " Z: " + localPosZ.ToString("0.000")
                        + " Rotation " + " X: " + localRotX.ToString("0.000") + " Y: " + localRotY.ToString("0.000") + " Z: " + localRotZ.ToString("0.000") + "\n";
    }
}
```

一応、ワールド座標系の方も入れといたのでご自分の目で確かめたい方は煮るなり焼くなりして下さい。
#Colliderの設定
　VRゲームでは、プレイヤーの位置を「スクリプトを組む」+　「現実側で人が動く」で操作することがほとんどです。そのため、それらの移動値をすべて加味してColliderを設定する必要があります。すなわち、TrackingSpaceオブジェクト等にColliderを設定するのでは不十分で**EyeAnchorオブジェクト以下（普通はCenterEyeAnchorだと思います）にColliderを設定する必要があります**（もしくはEyeAnchorのTransformに紐づけられたオブジェクトを作ってそこに入れる）。

　ですが、一点注意してほしいのは、EyeAnchor（HandAnchor）オブジェクトにColliderをアタッチした時、**Colliderが貫通しない設定であっても「実機上でColliderが影響を与えることはなく、Colliderは貫通」**します。厳密にいうと「ColliderがあってもそれをTracking情報が上書きしている」が正しい気がします。

####検証
　上については、「[collider-visualizer](https://github.com/tomori-hikage/collider-visualizer)」という便利なデバック機能を作った方がいらっしゃったのでそちらを使わせて頂いて検証しました。

　下の画像は、CenterEyeAnchorにColliderを設定し、ゲームモードで再生した様子です（VRHMDは接続されてません）。
確かにCubeと接触が起き、貫通が起きないことを確認しました。

![ColliderGameMode.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422708/110103ad-a1c8-0290-c186-f3452c3a41ae.png)



続いてOculusQuest実機上での動作です。CenterEyeAnchorにColliderをつけているのですが、y軸の位置は少し下げてあります（そのままだとカメラがColliderの中に入って見えないため）

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">OVRCameraRigのCenterEyeAnchorに貫通しないColliderをつけてOculusQuest上で動かしてみた動画です。画面下の赤いのがCollider。<br>Unityのゲームモードでは確かに貫通しないのに、実機だと貫通します。おそらく、Tracking情報で上書きされているからかと。 <a href="https://t.co/bUc5wtCav5">pic.twitter.com/bUc5wtCav5</a></p>&mdash; ほるかす@めぐるーまー (@pwhrhs) <a href="https://twitter.com/pwhrhs/status/1170323299982692352?ref_src=twsrc%5Etfw">September 7, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



　そもそも論として仮にColliderがEyeAnchorに影響を及ぼすとしても、それはUX的によろしくないので**プレイヤーにColliderをつける際は IsTriger をオンに**した方がいいです（バーチャル壁に引っかかって、リアルでは前進してるのにバーチャルのカメラが動かないのは気持ち悪い）
#各種コンポーネントについて
　OVRCameraRigには様々なコンポーネントがついており、それらは開発するうえで大変便利な機能を持っています。それらほとんどのものはOculus公式から [ドキュメント](https://developer.oculus.com/documentation/unity/latest/concepts/unity-utilities-overview)が出ているのでそれを見ると良いと思います。
　が、当然のごとく英語なのと細かいニュアンスが伝わってこないものもあるので、自分へのメモという意味でもこちらに残していきます。

###OVRManager



- TargetDevice : ビルドするデバイス。たまに指定間違ってることがあるので要注意。
- Monoscopic : 両目に同じ画像がレンダリングされます。要するに立体視ではなく平面視になる。知っておいて損はしない機能かと。 
- TrackingOriginType : カメラの基準点。
 - Eye Level : HMDと床からの距離をとってそこをカメラの位置とする。
 - Floor Level : ガーディアン設定時の床の位置にカメラを設定する。
 - Stage : 基本はFloor Levelと同じだが、正面の向きがアプリ起動時に固定化される（リセンターしても正面が変わらない）
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422708/da40dfe4-e362-2fad-1b60-dd17841353d2.png)

- UsePositionTrack : オフにすることで3DoFになる。ただし、コントローラーは6DoF。また、TrackingOriginTypeをEyeLevelにしないとコントローラーが頭上に出てしまう。


＊インスペクタ上には表示されていませんが、OVRManagerには結構開発で便利な機能が搭載されているので一度スクリプトをのぞいてみるといいと思います。（CPU,GPU LevelやFixedFoveatedRenderingLevelの設定等）

　
#その他細かい使用上の注意点
うまく動かないときに自分が陥りがちなOVRCameraRig関連の情報のメモ

・デフォルトでは、CenterEyeAnchorにMainCameraタグ + AudioListenerがある。 → 新たにシーン作成した際のMainCameraは消しておく！
・TargetDeviceに自分の使うHMDを設定しておく
・ver 1.40の時点ではデフォルトでOVRCameraRigにOVRControllerPrefabが入っていないのでコントローラーは表示されない。表示させたいときはProjectから追加する。