Android XR 拡張機能の設定を使用して、フレームレートを向上させ、GPU の負荷とレンダリング レイテンシを削減する

対象の XR デバイス
このガイダンスは、このようなタイプの XR デバイス向けのエクスペリエンスを構築する際に役立ちます。
XR ヘッドセット
有線 XR グラス

Unity には、Android XR 固有のパフォーマンス関連機能がいくつか用意されています。これらの機能を使用するには、Android XR Extensions パッケージが必要です。これらの機能を有効にすると、スペースワープと Vulkan サブサンプリングによってフレームレートが向上し、GPU の負荷が軽減されます。また、レイト ラッチングによってトラッキングされたレンダリングのレイテンシが短縮されます。

前提条件

このガイダンスに沿って操作する前に、次の前提条件を確認して完了していることを確認してください。

スペーシャル ワープを有効にする

URP アプリケーション スペースワープは、フレームを 1 つおきに合成することで高いフレームレートを維持するのに役立つ OpenXR 最適化です。この手法では、前のフレームのモーション ベクトルと深度データを使用して、ピクセルが移動する場所を予測し、計算能力とエネルギー使用量を削減します。

利点

  • 代替フレームを合成することで、GPU レンダリングのワークロードを軽減します。
  • 計算能力とエネルギー消費量を大幅に削減します。
  • 再投影を使用して、ユーザーの動きとディスプレイの更新の間のレイテンシを短縮します。

この機能を有効にする

  1. Unity のメインメニューで、[Edit] > [Project Settings] をクリックします。
  2. [XR プラグイン管理] セクションを開きます。
  3. 現在の XR デバイスに対応するタブを選択します。
  4. [OpenXR Feature Groups] セクションに移動します。
  5. [すべての機能] セクションで、[アプリケーション SpaceWarp] を有効にします。

    スペースワープの Unity 設定

Vulkan サブサンプリングを有効にする

Vulkan サブサンプリングを使用すると、フラグメント密度マップを使用して、さまざまな密度で画像を作成してサンプリングできます。この Vulkan 機能により、画面のさまざまな領域をさまざまな解像度でレンダリングしてメモリに転送できます。これは、周辺領域で低解像度を使用できる視線追跡レンダリングで特に便利です。

利点

  • フォーム ファクタに応じて、フォビエイテッド レンダリングと組み合わせた場合にさまざまな改善効果が得られます。
  • バイリニア フィルタリングにより、周辺領域のエイリアシングを軽減します。
  • さまざまな画面領域で効率的な可変レート レンダリングを可能にします。

この機能を有効にする

  1. Unity のメインメニューで、[Edit] > [Project Settings] をクリックします。
  2. [XR プラグイン管理] セクションを開き、[OpenXR] をクリックします。
  3. [Android XR(拡張機能): セッション管理] の横にある歯車アイコンをクリックします。
  4. [サブサンプリング(Vulkan)] を有効にします。

    Vulkan サブサンプリングの Unity 設定

遅延ラッチを有効にする

遅延ラッチは、ユーザーの物理的な動きと、その結果としてディスプレイに表示される視覚的な変化との間の遅延を最小限に抑える手法です。これにより、フレーム生成パイプラインの後半で頭のポーズを更新できるため、XR アプリの快適さと知覚フレームレートの両方が向上します。これは、入力レイテンシを 1 フレーム時間近く短縮することで実現されます。

利点

  • モーション トゥ フォト(MTP)のレイテンシを大幅に削減します。
  • ユーザーの快適性を高め、VR 酔いを軽減します。
  • 安定性と精度が向上します。

この機能を有効にする

遅延ラッチングを有効にするには、アプリの実行時にこの機能をオンにします。

private XRDisplaySubsystem xrDisplay;

private XRDisplaySubsystem.LateLatchNode lateLatchNode = XRDisplaySubsystem.LateLatchNode.Head;

void Start()
{
    List<XRDisplaySubsystem> xrDisplaySubsystems = new();

    SubsystemManager.GetSubsystems(xrDisplaySubsystems);

    if (xrDisplaySubsystems.Count >= 1)
    {
        xrDisplay = xrDisplaySubsystems[0];
    }
}

void Update()
{
    if (xrDisplay != null)
    {
        transform.position += new Vector3(Mathf.Epsilon, 0, 0);

        Quaternion rot = transform.rotation;

        rot.x += Mathf.Epsilon;

        transform.rotation = rot;

        xrDisplay.MarkTransformLateLatched(transform, lateLatchNode);
    }
}