スマホVRアプリをOculusGoアプリに移植＆最適化した話

#はじめに
去年(2017)の[BitSummit](http://bitsummit.org/2017/?lang=ja)で弊社が出展していた
「[GOD BREATH YOU](http://panora.tokyo/28484/)」とゆう非対称型のスマホVR（Cardboard）アプリを[MakerFaireTokyo2018](http://makezine.jp/event/makers2018/m0088/)用にOculusGoアプリに移植＆最適化した話です
今回、会社に許可を得て記事にしています
https://www.youtube.com/watch?v=lhjDmxPlvG8
>「神の息吹」で、イカダに乗った遭難者を島まで導く協力型脱出VRゲーム。VRゴーグルを装着して視界を伝えるプレイヤーが「遭難者」に、ブロワーで風を送って船の向きを変えるプレイヤーが「神様」になってプレイするのが特徴。行く手を阻む障害物を避けるなど、お互いに協力しながら遭難者を乗せたイカダを時間内にゴールまで送り届けることが目的だ。

#移植の経緯
弊社がMakerFaireTokyo2018に出展するとゆう事で自分も何か出したいなあと思っていた所、OculusGoが巷に流行っていて、自分自身すごくOculusGoに興味を持っていて、イカダの部分をOculusGoのコントローラーにすれば簡単に移植できそうと思い、今回の移植をやろうと思いました。
<img width="661" alt="1→10drive試作室、協力型VRゲーム「GOD_BREATH_YOU」など2作をBitSummitに出展_–_PANORA.png" src="https://qiita-image-store.s3.amazonaws.com/0/158441/0edb2344-a082-efd5-25c2-14689fafe61a.png">

#機材構成
基本機材を仕込んだイカダをブロワーを使って回した情報をHMDに送る仕組みを取っています
###[昔]スマホVR
![空白ページ.png](https://qiita-image-store.s3.amazonaws.com/0/158441/423c966f-6d9a-4330-ca0f-fa30d191ba93.png)
###[新]OculusGo
![空白ページ.png](https://qiita-image-store.s3.amazonaws.com/0/158441/c5005c50-5d9a-4323-340c-56ec1f171fe6.png)

#移植
大体順番で書いていきます
・Unityのバージョンを上げる 元々5.5.3だったので（確かOculusプラグインがぎり使えなかったような）なるべく最新のバージョンに上げたかったので（バージョンを上げると色々都合がいい）2017.4.7f1に変更

・とりあえずバージョンをあげた事によるアセットなどアップデートや削除してエラーなどを直す

・Cardboardプラグイン削除

・[OculusIntegration](https://www.assetstore.unity3d.com/jp/#!/content/82022)追加してセットアップ　

・とりあえずビルドしてみる、この時点ではまだ操作できなくても、描画できればOK　だが、ここで色々ハマった　多分一番時間がかかったような
　アプリには転送できるが起動したら何故か落ちる、LogCatで探ってみるが落ちているログ見て調べてもよく分からず（内容はちょっと忘れました）、色々試行錯誤しました。Unityのバージョンを下げたり上げたり、新規のシーンでビルドしてみたりと、ちなみに新規のシーンでビルドして起動できたので、ここでシーンが悪いと気付いて、色々見てたら、なんかインスペクターのプロパティにNULLが入っている箇所を発見したのですが、正直それって全く使ってなくて、起動時も全く使っていない空のプロパティなんですけど、とゆう事で消したらちゃんと起動しました。ちょっと正直よく分からないですねw

・[AssetHunter](https://assetstore.unity.com/packages/tools/utilities/asset-hunter-2-22983)アセットを使ってビルドに不要なアセットなど削除してプロジェクトのダイエット、だがバイナリデータがResourcesのもので圧迫していたのであまりバイナリデータのダイエットには効果がなかった　このアセットResourcesのものは消してくれないっぽい

・ビルド時にシェーダーコンパイルが走って、ビルド時間が長くなってしまったので、
fogアセットの[Volumetric Fog & Mist](https://www.assetstore.unity3d.com/jp/#!/content/49858)を削除してUnityのfogに変更　正直、変更しても負荷や見た目が変わらなかった

・シーンの中のCardboardで使っていたカメラを「OVRCameraRig」プレハブと差し替える
　Cardboardで使っていたカメラの中身の構成をOVRCameraRigのカメラにも似せて作る

・[Easy Input for Gear VR and Oculus Go](https://www.assetstore.unity3d.com/#!/content/88829?aid=1100l3oC8)
アセットを追加　このアセットは簡単言うとOculusGoコントローラーのインプットを簡単に組み込めるようにするアセット　まあ　なくてもいけてたかも

・OculusGoコントローラー（イカダ）のY回転値をHMDに反映
　以前のBLE基盤でやった時よりOculusGoコントローラーの方が感度がよくなったのでちょっと酔いやすくなってしまったかも

以上、移植自体そんなに時間はかかってないけど、最初のビルドして描画する方で時間かかりました。

#デバッグ方法
OculusGo開発はCardboardと比べると非常にエディタ上でのデバッグが非常にやりにくく確認する際はいちいちビルドして確認しないといけません。ちなみにこうゆうやり方もあります。[ゲームパッドを使ったデバッグ方法](https://qiita.com/m0a/items/07d24bd376e6e0f43c16)
Cardboardはキー操作で視点変えたりできます。
それで、今回自分が使ったデバッグ方法はOculusRiftを使う方法です（OculusRiftを持っていない人に取っては敷居が高いですね）
Oculus　Integrationプラグインは元々OculusRiftやGearVRを一緒に使えてたのでもちろんOculusGoでも使えるとゆう事です。なので、特に設定する事なくSwitchPlatformを「Android」でも全然OculusRiftが使えました。　
デバッグ方法の一つとして選択肢に入れてもいいかもしれないですね。

#最適化
最適化する前は起動したばかりだと35fpsぐらいのが、どんどんプレイすると20fps〜15fpsに落ち込む事があったので、目標はプレイ中は４０fpsぐらいを目指したいと思います。

・最初にビルド＆ランをしてUnityのプロファイラーでどこの箇所がパフォーマンスを落としているか調べました。結果、　描画周りがパフォーマンスを落としている事に気付きました。

・OculusionCulingを適用する　特に効果がなかった

・スタンダードシェーダーからモバイルの軽いシェーダー変更　特に効果がなかった

・マップ上のオブジェクトをまとめてドローコールを減らす　２００→８０ぐらい　特に効果がなかったので戻す
<img width="691" alt="Unity_2017_4_9f1_Personal__64bit__-_Main_unity_-_GodBreathYou_-_Android__Personal___Metal_.png" src="https://qiita-image-store.s3.amazonaws.com/0/158441/83c2d05b-6ae1-266d-6f84-9207174dd2ac.png">

・普通にライトのタイプがRialTimeで描画されていたのでbakedに変更してライトマップやライトプローブに焼く　　結構効果があった
<img width="688" alt="Unity_2017_4_9f1_Personal__64bit__-_Main_unity_-_GodBreathYou_-_Android__Personal___Metal_.png" src="https://qiita-image-store.s3.amazonaws.com/0/158441/61d0617a-3fc3-2b6a-ebde-ca7dddaef4b8.png">
　
###OculusGo固有の最適化
参考にさせてもらった資料
・https://framesynthesis.jp/tech/unity/oculusgo/
・https://framesynthesis.jp/tech/unity/oculusrift/
・https://www.slideshare.net/UnityTechnologiesJapan002/unite-tokyo-2018oculusvr-96453609
・http://kan-kikuchi.hatenablog.com/entry/Oculus_Go_Unite2018

・Stereo Rendering MethodをSingle Passに変更 結構効果があった
>左右の目の画像を同時に 1 つのまとまったレンダーテクスチャにレンダリングします。つまり、シーン全体が 1 回だけレンダリングされ、CPU 処理時間が大幅に短縮されます。この機能がないと、Unity は、最初は左目画像を次に右目画像をというように、シーンを 2 回レンダリングします。
　<img width="638" alt="手軽にOculus_Go用アプリの負荷を削減したり、見栄えを良くしたりする方法【Unity】【VR】【Oculus_Go】_【Unite_2018_Tokyo】_-___3_kanのメモ帳_.png" src="https://qiita-image-store.s3.amazonaws.com/0/158441/69bd90e4-3f90-96cd-e4bf-ee7dcf776209.png">

・OVRCameraRigのOVR ManagerにあるEnable Adaptive Resolutionをオフにする
GPUの使用率が高くなるとフレーム落ちしないように自動的に解像度を下げる機能
これはかなり効果があった　オススメ！

・固定中心窩レンダリング (Fixed Foveated Rendering)を使う
　これは画面の端の解像度を下げて負荷削減する機能
　Low, Medium, Highの3種類あり、Highを使っても見た目あまり気にならなかったがあまり効果がなさそうだったが一応おまじない程度に

・アイバッファ解像度を下げる
　極端に半分の解像度を設定しても負荷はあまり変わらなかった　普通は上がりそうですけどね　何故か変わらず なので　デフォルトに

・GPUのパフォーマンスレベルを０に設定　　なるべくバッテリー消費・発熱起こさない為　おまじない程度

以上、特にOculusGo固有の最適化が一番効果がありました。
最適化後は常に３０FPS〜５０FPSぐらいを維持して特に長時間つけっぱなしでも落ちずに起動できていました。

#おまけ　展示時の運用　ススメ
予備でもう一台追加してたので、バッテリー不足にならず余裕を持ってローテーション組めました
ものによると思いますが、　アプリ起動しっぱなしスリープなしで連続稼働時間2時間ぐらいです
大体充電１時間で４０％回復します

スリープせずにずっとつけっぱなしにする場合はセンサー部分をテープとかで塞いでおくといちいちスリープ解除をしないで済むので運用時オススメです
![【対策】Oculus Goのスリープが勝手に解除される、電源オフにできない、充電が減る問題の解決法 _ ぶいあーる情報局 - Google Chrome 2018-08-02 20.04.21.png](https://qiita-image-store.s3.amazonaws.com/0/158441/50d25675-e045-3035-b35a-2390e6545bcc.png)

こんな感じにHMD以外で制御できるようにしていました　　コントローラーに色々仕込んでいた方が運用が楽にできるかもしれません
![20180521_01.png](https://qiita-image-store.s3.amazonaws.com/0/158441/10f257db-28bd-a5c9-4234-d8276af164c4.png)