はじめに

前回のスマホ用 VR アプリを Mirage Solo に移植してみるを読んでくださった皆さん、たぶんそんなにお久しぶりじゃないですね。ええ。

本記事では2016年に Release されたなごみの耳かきを Oculus Go に移植していきます。(前回の記事での改修を終わらせている前提で本記事は書かれています。)

clipboard.png

Oculus Go を開発者モードに設定している事前提です。されてない方は Oculus Go をリンクしているスマホ上で開発者モードを ON にしてください。(開発者モードへの設定詳細はこちらのサイトがおすすめです。Unity + Oculus Go 開発メモ)

そして ADB で接続できるところまで終わっている前提で話を進めていきます。

PlayerSettings の設定

基本的にほぼ前回のままです。差分の変更箇所は次のとおり。

  • 色空間を Linear から Gamma に
  • MinimumAPI Android7.0に
  • VR サポートに Oculus に(Daydream が残ってたら消しましょう)
  • Enable Adaptive Resolution を無効に
  • Dynamic Batching と Static Batching を有効に
  • Stereo Rendering Method を Single Pass(Preview)に

clipboard.png

Oculus Go のドキュメントでは Single Pass 推奨されてたので Single Pass で今回は進めていきます。(PPSv2がうまく動かなかったりするのでポストプロセスエフェクトを使う場合は注意)

Enable Adaptive Resolution と Dynamic Batching 、 Static Batching の設定も Oculus ドキュメントの推奨設定です。

Oculus Integration の設定

Oculus Go の SDK は AssetStore のOculus Integrationを使います。

clipboard.png

インポートしたあとの Oculus → VR → Prefabs に使うファイルが入っています。

clipboard.png

まずカメラとして OVRCameraRig を設置します。(既存の Main Camera は削除する)

OVRCameraRig にある「 LeftHandAnchor 」および「 RightHandAnchr 」に「 TrackedRemote 」の Prefab を両方に配置します。

これでユーザーが設定してるコントローラーの持ち手側のコントローラーが自動的に表示されるようになります。

clipboard.png

Oculus コントローラーの設定

前回 Mirage Solo ではデフォルトでコントローラーがどこを指しているかのレーザーポインタがありましたが、 Oculus Go には存在しません。

このままだと操作が辛いので下記サイトを参考にレーザーポインタを実装しました。

【 Unity / Oculus Go 】 Oculus Go コントローラー表示方法とボタン取得方法

また uGUI の Event System と連動する機能が Oculus Integration には無いようなので、同じくこのサイトで書いてある Ray で Button を押すやり方を参考にしました。

Fixed Foveated Rendering

Oculus Go の目玉機能として絵の外周部分を低解像度にレンダリングすることで FPS を稼ぐという機能があります。

使い方は簡単で下記コードを Start とかで呼ぶだけです。設定は4種類あり(Off/LMSLow/LMSMedium/LMSHigh)右ほど解像度を落としていくことになります。

パッと見全くわからないのに負荷がかなり下がるのでオススメ機能です。

void Start () {
    OVRManager.tiledMultiResLevel = OVRManager.TiledMultiResLevel.LMSHigh;
}

おわりに

Mirage Solo のときに大半の改修を終わらせていたので、コントローラの制御を Oculus Go 用に実装し直すだけで、動作するようになりました。

演算スペックでは Oculus Go のほうが低いのですが、 Fixed Foveated Rendering のおかげで Mirage Solo と変わらない速度も出たので描画品質を落とす調整も必要ありませんでした。

Mirage Solo は6DoF

Oculus Go は3DoF

なので6DoF と3DoF の違いに合わせた UI/UX の調整さえできれば、 Mirage Solo/Oculus Go は両対応はそれほど難しくはないかもしれませんね。

おまけ

見るだけコンテンツを作るときに Oculus Go と Daydream を毎回設定変えて Build するのも面倒くさかったので Build ツールを作りました。将来的にはコントローラー周りも共通のものを作りたいですね。


using System;
using System.IO;
using UnityEditor;

namespace UPFT.Editor
{
    public static class AppBuilder
    {
        /// <summary>
        /// HMD の名前
        /// </summary>
        public enum HmdName
        {
            OculusGo,
            Daydream
        }

        /// <summary>
        /// BuildDirectory
        /// </summary>
        private static string _buildDirectory => Path.Combine(Directory.GetCurrentDirectory(), "Builds");

        /// <summary>
        /// Build 設定
        /// </summary>
        private static BuildOptions _buildOption;

        /// <summary>
        /// Build 実行前の SDK 設定
        /// </summary>
        private static string[] _defaultVirtualRealitySDKs;

        /// <summary>
        /// Release ビルド
        /// </summary>
        [MenuItem("UPFT/ReleaseBuild", false, 10)]
        public static void ReleaseBuild()
        {
            //ReleaseBuild に設定
            _buildOption = BuildOptions.None;

            buildProcess();
        }

        /// <summary>
        /// Development ビルド
        /// </summary>
        [MenuItem("UPFT/DevelopBuild", false, 11)]
        public static void DevelopBuild()
        {
            //ReleaseBuild に設定
            _buildOption = BuildOptions.Development;

            buildProcess();
        }

        /// <summary>
        /// Build
        /// </summary>
        private static void buildProcess()
        {

            //Build する Directory がない場合は作成
            safeCreateDirectory(_buildDirectory);

            //現在の SDK 設定を保存
            _defaultVirtualRealitySDKs = PlayerSettings.GetVirtualRealitySDKs(BuildTargetGroup.Android);

            //BuildVersion を加算
            PlayerSettings.Android.bundleVersionCode += 1;

            //Daydream 用の Build 出力
            daydreamBuild();

            //Oculus 用の Build 出力
            oculusBuild();

            //使用する SDK を Build 前の設定に戻す
            PlayerSettings.SetVirtualRealitySDKs(BuildTargetGroup.Android,_defaultVirtualRealitySDKs);
        }

        /// <summary>
        /// Daydream の Build 処理
        /// </summary>
        private static void daydreamBuild()
        {
            //apk の名前設定
            string apkName = PlayerSettings.productName + Enum.GetName(typeof(HmdName), HmdName.Daydream) + ".apk";

            //使用する SDK 一覧の配列作成
            string[] sdks = new string[1]{"daydream"};
            PlayerSettings.SetVirtualRealitySDKs(BuildTargetGroup.Android,sdks);

            buildPlayer(apkName);
        }

        /// <summary>
        /// OculusGo の Build 処理
        /// </summary>
        private static void oculusBuild()
        {
            //apk の名前設定
            string apkName = PlayerSettings.productName + Enum.GetName(typeof(HmdName),HmdName.OculusGo) + ".apk";

            //使用する SDK 一覧の配列作成
            string[] sdks = new string[1]{"Oculus"};
            PlayerSettings.SetVirtualRealitySDKs(BuildTargetGroup.Android,sdks);

            buildPlayer(apkName);
        }

        /// <summary>
        /// Build 実行
        /// </summary>
        /// <param name="filePath"></param>
        private static void buildPlayer(string apkName)
        {
            //ファイル名設定
            string filePath = Path.Combine(_buildDirectory, apkName);

            // ビルド
            BuildPipeline.BuildPlayer(
                EditorBuildSettings.scenes,
                filePath,
                BuildTarget.Android,
                _buildOption
            );
        }

        /// <summary>
        /// 指定したパスにディレクトリが存在しない場合
        /// すべてのディレクトリとサブディレクトリを作成します
        /// </summary>
        private static DirectoryInfo safeCreateDirectory(string path)
        {
            return Directory.Exists(path) ? null : Directory.CreateDirectory(path);
        }
    }
}