OculusQuestでどこでもドアを実現してみる

# はじめに
XR Interaction Toolkitと、Pocket Portal VRというアセットを使用して、OculusQuestでどこでもドアを実現してみました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XR Interaction ToolkitでPocket Portal VRを動かしてみました <a href="https://t.co/9URsnOya5j">pic.twitter.com/9URsnOya5j</a></p>&mdash; 高浜 (@SatoshiTakahama) <a href="https://twitter.com/SatoshiTakahama/status/1240585974024794112?ref_src=twsrc%5Etfw">March 19, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[Pocket Portal VR]
(https://assetstore.unity.com/packages/tools/particles-effects/pocket-portal-vr-85657)
Pocket Portal VRのアセットのページです。Pocket Portal VRは、作者がサポートできない状態とのことで、オープンソース化されています。

XR Interaction Toolkitは、Unity上でPackage Manegerからインストールできます。
また、XR Interaction Toolkitのサンプルシーンは[XR-Interaction-Toolkit-Examples](https://github.com/Unity-Technologies/XR-Interaction-Toolkit-Examples)から入手できます。

#開発環境
Unity 2019.3.2f1
XR Interaction Toolkit 0.9.3
Oculus XR Plugin 1.2.0
Pocket Portal VR 2.3

#修正したところ
Portal.csのRenderMonoを以下のように書き換えました。

```C#:Portal.cs
	private void RenderMono(Camera camera) {
        Transform trackingSpace = xrRig.cameraGameObject.transform;
        var leftEye = trackingSpace.localPosition + new Vector3(-camera.stereoSeparation / 2f, 0f, 0f);
        var RightEye = trackingSpace.localPosition + new Vector3(camera.stereoSeparation / 2f, 0f, 0f);


        if (camera.stereoTargetEye == StereoTargetEyeMask.Both || camera.stereoTargetEye == StereoTargetEyeMask.Left)
        {
            Vector3 leftPosition = xrRig.transform.TransformPoint(leftEye);
            Quaternion leftRot = xrRig.transform.rotation * trackingSpace.localRotation;
            RenderPlane(renderCam, leftTexture, leftPosition, leftRot, camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left));
            meshRenderer.material.SetTexture("_LeftTex", leftTexture);
        }

        if (camera.stereoTargetEye == StereoTargetEyeMask.Both || camera.stereoTargetEye == StereoTargetEyeMask.Right)
        {
            Vector3 rightPosition = xrRig.transform.TransformPoint(RightEye);
            Quaternion rightRot = xrRig.transform.rotation * trackingSpace.localRotation;
            RenderPlane(renderCam, rightTexture, rightPosition, rightRot, camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right));
            meshRenderer.material.SetTexture("_RightTex", rightTexture);
        }
    }
```

上記コード中で使用しているxrRigは、XR Interaction ToolkitのXRRigをstart時に取得しておきます。

```
xrRig = GameObject.FindObjectOfType<XRRig>();
```
左右カメラ視差をつくるためのオフセット設定は、[どこでもドア（ポータル）をUnity NativeのVRで実現してみる](http://tuti107.hatenablog.com/entry/2017/03/19/212656)を参考にさせていただきました。

# Oculus Integrationとの組み合わせについて
~~Oculus Integrationとの組み合わせで動作させる場合、サンプルシーンRiftOVRDemoを試してみたところ、特にコードを修正しなくでもビルドはできるのですが、OculusQuestで動かしたときに両目でポータルの見える位置がずれてしまい立体視できない状態でした。コード修正で立体視できる状態にできないか試してみたのですがうまくいきませんでした・・対応方法をご存じの方がいましたら教えていただけると嬉しいです。~~
(2020/3/22追記)
シェーダーで左右のテクスチャ切り替えを変にトグルさせている処理が有効になっており、Portal.cs中で設定している箇所を以下のように無効に設定することで対処できました。

```
//#if USES_OPEN_VR
//        Shader.SetGlobalInt("OpenVRRender", 1);
//#else
        Shader.SetGlobalInt("OpenVRRender", 0);
//#endif
```

その他、Portal.csのRenderOpenVRを以下のように書き換えました。

```C#:Portal.cs
	private void RenderOpenVR(Camera camera) {
#if USES_OPEN_VR
        Transform trackingSpace = rig.centerEyeAnchor.transform;
        var leftEye = trackingSpace.localPosition + new Vector3(-camera.stereoSeparation / 2f, 0f, 0f);
        var RightEye = trackingSpace.localPosition + new Vector3(camera.stereoSeparation / 2f, 0f, 0f);

        if (camera.stereoTargetEye == StereoTargetEyeMask.Both || camera.stereoTargetEye == StereoTargetEyeMask.Left)
        {
            Vector3 leftPosition = rig.transform.TransformPoint(leftEye);
            Quaternion leftRot = rig.transform.rotation * trackingSpace.localRotation;
            RenderPlane(renderCam, leftTexture, leftPosition, leftRot, camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left));
            meshRenderer.material.SetTexture("_LeftTex", leftTexture);
        }

        if (camera.stereoTargetEye == StereoTargetEyeMask.Both || camera.stereoTargetEye == StereoTargetEyeMask.Right)
        {
            Vector3 rightPosition = rig.transform.TransformPoint(RightEye);
            Quaternion rightRot = rig.transform.rotation * trackingSpace.localRotation;
            RenderPlane(renderCam, rightTexture, rightPosition, rightRot, camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right));
            meshRenderer.material.SetTexture("_RightTex", rightTexture);
        }
#endif
    }

```