🏃

OpenXRランタイムを実行時に選ぶ

2021/12/12に公開

はじめに

XRアプリを開発する時は各デバイス毎のSDKを利用する必要がありマルチデバイス対応するのは非常に面倒でした。そのためどのXRデバイスでも動作する共通規格としてKhronosグループでOpenXRを策定しています。現状OpenXRを実装したWindowsのランタイムは以下の5つがあります。

  • Oculus
  • SteamVR
  • WindowsMR
  • Vive
  • Varjo

これらをインストールするとどれか1つをアクティブにできますがアプリ側から容易に選択することができませんでした。そこでOpenXR 1.0.18からランタイム一覧を列挙される仕様が追加されたのでそれを利用する方法を解説します。

ちなみにこの内容はOpenXRの仕様なのでUnity以外でも利用できます。

アクティブなOpenXRランタイム

各ランタイムは以下の設定画面からアクティブ化できます。

Oculus
Oculus

SteamVR
SteamVR

WindowsMR
WindowsMR

Vive
Vive

Varjo
Varjo

ここでアクティブにすると以下のレジストリにjsonファイルのパスが保存されます。

  • レジストリ HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenXR\<major_api_version> キーにEXPAND_SZで ActiveRuntime
    • <major_api_version> は現状 1 のみです。

Oculusがアクティブだと以下のようになります。

Oculus OpenXR

そしてOpenXR SDKは以下の順序でランタイムを探索します。

  1. 環境変数 XR_RUNTIME_JSON
  2. 上記のレジストリキー

Unityエディタからは環境変数を利用して以下の設定からランタイムを切り替えられます。
Unity

という事はアプリも環境変数にランタイムのjsonパスを設定してからOpenXRをアクティブにすれば切り替えられそうです。

インストール済みのOpenXRランタイム一覧 (OpenXR 1.0.17以前)

各ランタイムのjsonパスはそれぞれのインストール先に配置されています。ですがインストールパスを変更できるのでレジストリなどからパスを決定する必要がありとても面倒です。デフォルトのパスにインストールするとjsonはそれぞれ以下のパスに存在します。

- Oculus
C:\Program Files\Oculus\Support\oculus-runtime\oculus_openxr_64.json

- SteamVR
C:\Program Files (x86)\Steam\steamapps\common\SteamVR\steamxr_win64.json

- WindowsMR
C:\WINDOWS\system32\MixedRealityRuntime.json

- Vive
C:\Program Files (x86)\VIVE\Updater\App\ViveVRRuntime\ViveVR_openxr\ViveOpenXR.json

- Varjo
C:\Program Files\Varjo\varjo-openxr\VarjoOpenXR.json

インストール済みのOpenXRランタイム一覧 (OpenXR 1.0.18以降)

各ランタイムのjsonは配置場所が規格化されておらずランタイム自体もインストール先を変更できるのでパスを探すのが面倒でした。
そのためOpenXR 1.0.18からランタイムのjsonパスを登録するレジストリキーが以下のように定めされました。

  • レジストリ HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenXR\<major_api_version>\AvailableRuntimes キーにDWORDで名前がjsonパス、値0なら有効、0以外なら無効

それぞれのランタイムについて以下のバージョンで確認しましたがOculusとVarjoしか対応していないため他も追従してほしい所です。

  • Oculus: 35.0.0.73.175
  • SteamVR: 1.12.4
  • WindowsMR: 109.2111.23003.0
  • Vive: 2.0.18.6
  • Varjo: 3.4.0.8

AvailableRuntimes

Unityでランタイムを指定してOpenXRを有効にする

上述の仕様を元にPC内に存在するjsonパス収集と環境変数にjsonパスを設定するライブラリを作りました。
これを利用するとランタイムを指定してOpenXRアプリを実行できるようになります。
jsonパス収集はレジストリから探索する方法と1.0.18のレジストリキーから収集する方法の2つを用意しています。

https://github.com/shiena/OpenXRRuntimeSelector

これを利用してOculusランタイムがあれば優先した後にVRを有効にする場合は以下のコードになります。
スクリプトからVRを有効にするのでProject Settings/XR Plug-in ManagementのInitialize XR on Startupを無効にしておきます。

using OpenXRRuntimeJsons;

public class Initialize : MonoBehaviour
{
    private void Awake()
    {
        // PCに存在するランタイムのjsonパスを収集してOculusが存在するなら環境変数XR_RUNTIME_JSONに設定する
        SetOculusRuntimeFromAvailableRuntimes();
        // XRを初期化してOpenXRを有効にする
        StartCoroutine(StartXRCoroutine());
    }

    private void SetOculusRuntimeFromAvailableRuntimes()
    {
        // Get the available OpenXR runtime json
        IReadOnlyDictionary<OpenXRRuntimeType,string> openXRRuntimes = OpenXRRuntimeJson.GetRuntimeJsonPaths();
        if (openXRRuntimes.ContainsKey(OpenXRRuntimeType.Oculus))
        {
            // Use the Oculus OpenXR runtime
            OpenXRRuntimeJson.SetRuntimeJsonPath(OpenXRRuntimeType.Oculus);
        }
    }

    private IEnumerator StartXRCoroutine()
    {
        if (XRGeneralSettings.Instance.Manager.isInitializationComplete)
        {
            yield return true;
            yield break;
        }

        Debug.Log("Initializing XR...");
        yield return XRGeneralSettings.Instance.Manager.InitializeLoader();

        if (!XRGeneralSettings.Instance.Manager.isInitializationComplete)
        {
            Debug.LogError("Initializing XR Failed. Check Editor or Player log for details.");
            yield return false;
        }
        else
        {
            Debug.Log("Starting XR...");
            XRGeneralSettings.Instance.Manager.StartSubsystems();
            yield return true;
        }
    }
}

また、PC内に存在するランタイム名のボタンを列挙して選択できるサンプルプロジェクトも用意しました。
https://github.com/shiena/OpenXRRuntimeSelectorSample

5つのランタイムがインストールされているPCでサンプルプロジェクトを実行すると以下のように環境変数、システムデフォルトのレジストリ、各ランタイムのボタンが表示されて押したランタイムを有効にしてOpenXRを利用したVRのシーンをロードします。
OpenXRRuntimeSelectorSample

参考リンク

Discussion