中心窩レンダリングは、ユーザーの視界の周辺にある表示領域を低解像度でレンダリングする最適化の技術です。中心窩レンダリングは、知覚される視覚品質にほとんど影響を与えずにレンダリングのパフォーマンスを向上させることができます。
中心窩レンダリングは、中心窩 (最も密度の高い視細胞神経の集まりが含まれている、網膜の小さい部分) に由来する名前です。中心窩レンダリングの目的は、画面全体でレンダリング解像度を変化させることで、中心窩で認識できる部分だけが最高の解像度でレンダリングされるようにすることです。
XR プラットフォームでは、変数レートシェーディング (VRS) や変数ラスタライゼーション (VRR) など、さまざまな技術を使用して中心窩レンダリングを実装しています。使用する技術によって、中心窩レンダリングが有効になっているときにシェーダーがテクスチャをサンプルする方法が変わります。アセットをあらゆるプラットフォームで動作させるために、Unity はシェーダーマクロ、キーワード、およびプリプロセッサーシンボルを提供しています。これらを使用してシェーダーを適応させることで、すべてのプラットフォームでスクリーンスペースの計算が正しい結果を得られるようにします。使用方法の詳細については、中心窩レンダリングシェーダーを参照してください (Unity と URP が提供するシェーダーは、これらのマクロをすでに使用しています)。
XR デバイスは、次の 2 つのモードのいずれかの中心窩レンダリングをサポートできます。
現在、VRS と中心窩レンダリング用の均一ラスタを使用している XR プラットフォームには、OpenXR と Meta Quest があります。VRR と中心窩レンダリング用の非一様ラスタを使用している XR プラットフォームには、visionOS (Metal グラフィックス API でレンダリングする場合) があります。
中心窩レンダリングを使用するには、プロジェクトが以下の前提条件を満たしている必要があります。
注:
Unity プロジェクトで中心窩レンダリングを有効にするには、Project Settings (メニューで Edit > Project Settings を選択) で XR Plug-in Management セクションに移動します。中心窩レンダリングをサポートする各プラグインの設定セクションに、この機能を有効にするオプションが表示されています。使用可能な設定については、XR プロバイダーのプラグインのドキュメントを参照してください。
設定でオプションを有効にするほかに、中心窩レンダリングの制御に記載されているように、ランタイムの中心窩レンダリングのレンダリングレベルを設定する必要があります。
注意XR プラットフォームでは、中心窩レンダリングに対してさまざまなレベルの制御レベルを提供することが可能です。例えば、visionOS で Metal レンダリングを使用する場合、固定中心窩レンダリングを有効にすると常に最大強度になります。
中心窩レンダリングを制御するには、XRDisplaySubsystem の foveatedRenderingLevel プロパティを 0 から 1 の間の値に設定します。プロジェクトのプロバイダーのプラグイン設定で、ランタイムの中心窩を有効にする必要があります。有効にしないと、ランタイムの設定が無視されます。
以下のメソッド例では、中心窩のレベルを設定します。
public void SetFRLevel(XRDisplaySubsystem xrDisplaySubsystem, float strength)
{
xrDisplaySubsystem.foveatedRenderingLevel = strength;
}
中心窩レンダリングのレベルを 0 に設定すると、中心窩は無効になり、レンダリングには影響しません。
アイトラッキングまたは視線ベースの中心窩レンダリングをサポートするデバイスでは、XRDisplaySubsystem の foveatedRenderingFlags プロパティを設定することで、この機能を有効にできます。
// xrDisplaySubsystem is the active XRDisplaySystem instance
xrDisplaySubsystem.foveatedRenderingFlags = XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;
ランタイムに固定中心窩レンダリングを選択した場合でも、サポートするデバイスで foveatedRenderingFlags プロパティを設定すると、視線ベースの中心窩レンダリングを有効にすることができます。
注意XRDisplaySubsystem は SubsystemManager から取得します。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class FoveationControl : MonoBehaviour
{
XRDisplaySubsystem xrDisplaySubsystem;
public float strength = 1.0f;
void Start()
{
// Find the XR display subsystem
var xrDisplaySubsystems = new List<XRDisplaySubsystem>();
SubsystemManager.GetSubsystems<XRDisplaySubsystem>(xrDisplaySubsystems);
if (xrDisplaySubsystems.Count < 1)
{
Debug.LogError("No XR display subsystems found.");
return;
}
foreach(var subsystem in xrDisplaySubsystems)
{
if (subsystem.running)
{
xrDisplaySubsystem = subsystem;
break;
}
}
xrDisplaySubsystem.foveatedRenderingFlags = XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;
SetFRLevel();
}
public void SetFRLevel()
{
xrDisplaySubsystem.foveatedRenderingLevel = strength;
}
}
現在のデバイスの中心窩レンダリング機能は、SystemInfo オブジェクトの foveatedRenderingCaps プロパティから取得できます。
FoveatedRenderingCaps caps = SystemInfo.foveatedRenderingCaps;
このプロパティが FoveatedRenderingCaps.None になっている場合、デバイスは中心窩レンダリングをサポートしていません。サポートされていない理由は、ソフトウェア、デバイスのランタイム、ドライバーなど、さまざまなものが考えられます。そのため、プラットフォームで中心窩レンダリングをサポートしていても、特定のデバイスでは使用できない場合があります。
FoveatedRenderingCaps、FoveationImage、NonUniformRaster のその他の値は、デバイスが中心窩レンダリングを実装する方法に関する情報を提供します。これはカスタムのレンダーパイプラインを実装する際に役立つ可能性があります。FoveationImage は、中心窩レンダリングの実装で VRS を使用していることを示し、NonUniformRaster は VRR を使用していることを示しています。
Unity エンジンに含まれているシェーダーは、中心窩レンダリングの均一および非一様のラスタライゼーションの両方をすでにサポートしています。スクリーンスペースの計算を実行するカスタムシェーダーがある場合、非一様なラスタ技術を使用するプラットフォームで中心窩レンダリングをサポートするために、シェーダーの更新が必要な場合があります。
非一様なラスタでレンダリングされたピクセルは、通常のグリッドを表しません。そのため、通常のグリッドを想定しているスクリーンスペースの計算を変更して、VRR で正しく機能するようにする必要があります。Unity は、シェーダーマクロ、キーワード、およびプリプロセッサーシンボルを提供します。これらを使用してシェーダーを適応させ、すべてのプラットフォームで画面スペースの計算が正しい結果を得られるようにします (Unity と URP が提供するシェーダーは、これらのマクロをすでに使用しています)。
例えば、以下の画像の左側は、非一様なラスタライゼーションを補正せずに VRR でレンダリングしたシーンのビューを示しています。画像の右側は、正しくレンダリングした場合と同じビューを示しています。
左側の画像の端に近い部分が押しつぶされていることに注意してください。この視覚的な圧縮は、テクスチャの周辺領域がより低いピクセル密度でラスタライズされたために発生しています。このテクスチャをサンプリングする場合は、非一様一な UV 座標を使用する必要があります (または、提供されている中心窩レンダリングシェーダー関数のいずれかを使用して、リニア UV 座標を非一様な座標に変換する必要があります)。
注意Unity では、VRR 技術を使用したときにピクセルがラスタライズされたスペースを表す場合に “非一様なラスタ” という用語を使用し、通常のグリッドを持つ通常のラスタライゼーションスペースを表す場合は “リニアラスタ” という用語を使用します。
URP が中心窩レンダリングで正しい結果が得られるように画面スペースのシェーダーを更新するには、(Core RP Library のパッケージから) 以下の include ファイルを追加します。
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
これらのファイルには、中心窩レンダリングのキーワードとマクロに加え、スクリーンスペース座標を非一様からリニアに、またはその逆へマップする関数が含まれています。
可変レートシェーディング (VRS) 技術は、領域がユーザーの有効視野 (FOV) 内のどこにあるかに基づいて、フラグメントシェーダーへの呼び出しのたびにシェーディングされる画面ピクセル数を変更します。可変レートシェーディングは既存のシェーダーと互換性があります。VRS を使用する XR プラットフォームでは、中心窩レンダリング下で動作するようにカスタムシェーダーを変更する必要はありません。
可変レートラスタライゼーション (VRR) 技術は、近接のピクセル間の有効距離が均一でなくなるようにラスタライゼーションを調整します。例えば、有効視野 (FOV) の周辺領域は、最終的な表示に合成されるときに低解像度テクスチャにレンダリングされ、引き伸ばされることがあります。ラスタライゼーションが非一様なため、スクリーンスペースで計算を実行するシェーダーは、ラスタライゼーションが均一なグリッドを使用することを前提としている場合、VRR で誤った結果が生成される可能性があります。VRR を使用する XR プラットフォーム上で中心窩レンダリングで動作するようにするには、カスタムシェーダーの変更が必要な場合があります。
リニアテクスチャをサンプリングする場合は、リニア座標を使用する必要があります。逆に、非一様なテクスチャをサンプルする場合は、非一様な座標を使用する必要があります。
頂点シェーダーからフラグメント (ピクセル) シェーダーに渡されるすべての頂点属性は、SV_POSITION を除き、常にリニア空間にあります。SV_POSITION 座標を使用して非一様なテクスチャを直接サンプルすることは可能ですが、サンプリングに他の頂点属性を使用する場合は、適切なリニアから非一様への再マッピング関数を使用する必要があります。同様に、SV_POSITION を使用してリニアテクスチャをサンプルする場合は、FoveatedRemapNonUniformToLinear 関数を使用する必要があります。
テクスチャの座標空間は、その作成方法によって異なります。深度バッファや G バッファなど、Unity エンジンによって作成されたテクスチャのほとんどは、VRR でレンダリングする場合は非一様なスペースにあります (ただし例外もありますが、現時点では文書化されていません)。アーティストが描画された UI オーバーレイなど、手動で作成されたスクリーンスペースのテクスチャは、通常リニアであり、リニア UV 座標でサンプルする必要があります。
コンピュートシェーダーでは、ソースとデスティネーションのテクスチャがリニアスペースか非一様なスペースかを考慮し、サンプリングや書き込みを行う前に必要に応じて座標を再マップするする必要があります。同様に、UV 座標のソース、コンピュートシェーダー内で計算する方法、リニア座標と非一様な座標のどちらを想定するか、関数を渡すかどうか、についても検討します。Unity のコンピュートシェーダーに関する一般的な情報については、コンピュートシェーダーのトピックと、ComputeShader API を参照してください。
FoveatedRendering.hlsl は、カスタムシェーダーで中心窩レンダリングをサポートするために使用できる関数のセットを定義します。これらの関数は、現在の中心窩レンダリングのタイプがリニアか非一様かに関係なく、また中心窩レンダリングが使用されていない場合にも、正しい結果を返します。また、これらの関数は、プラットフォームがスクリーンスペースの原点を画面の上部または下部のどちらに配置するかに応じて、Y 軸の反転も処理します。
注意これらの関数は、非一様な中心窩レンダリング (VRR) を使用していないプラットフォームでは、パフォーマンスに影響を与えません。条件付き #ifdef 文を使用して、これらを除外する必要はありません。ただし、VRR を使用するプラットフォームでは、中心窩レンダリングが無効になっていても、シェーダー定数をチェックする動的分岐があり、オーバーヘッドがわずかに増えます。
宣言: float2 FoveatedRemapLinearToNonUniform(float2 uv)
リニアなスクリーンスペース UV 座標を、必要な Y 軸反転を含めて非一様座標に変換します。中心窩レンダリングが有効でない場合、またはプラットプラットフォームが非一様なラスタライゼーションを使用しない場合、関数は UV 座標を変更せずに返します。
宣言: float2 FoveatedRemapNonUniformToLinear(float2 uv)
非一様なスクリーンスペース UV 座標を、必要な Y 軸反転を含めてリニアに変換します。中心窩レンダリングが有効でない場合、またはプラットプラットフォームが非一様なラスタライゼーションを使用しない場合、関数は UV 座標を変更せずに返します。
宣言: float2 FoveatedRemapPrevFrameLinearToNonUniform(float2 uv)
前にレンダリングされたフレームに基づいて、リニアなスクリーンスペースの UV 座標を再マッピングします (Metal には実装されていません)。
宣言: float2 FoveatedRemapPrevFrameNonUniformToLinear(float2 uv)
前にレンダリングされたフレームに基づいて、非一様なスクリーンスペースの UV 座標を再マッピングします (Metal には実装されていません)。
宣言: float2 FoveatedRemapDensity(float2 uv)
指定されたスクリーン UV 座標での画面解像度とラスタ解像度の比率。中心窩レンダリングが有効でない場合、またはプラットプラットフォームが非一様ラスタライゼーションを使用しない場合、この関数は (1.0, 1.0) を返します (Metal には実装されていません)。
宣言: float2 FoveatedRemapPrevFrameDensity(float2 uv)
前のフレーム時点の密度の比率 (Metal には実装されていません)。
宣言: float2 FoveatedRemapLinearToNonUniformCS(float2 positionCS)
リニアなスペースのスクリーン座標を非一様なスペースのスクリーン座標に変換します。中心窩レンダリングが有効でない場合、またはプラットプラットフォームがラスタライゼーションを使用しない場合、この関数は座標を変更せずに返します。
宣言: float2 FoveatedRemapNonUniformToLinearCS(float2 positionCS)
非一様なスペースのスクリーン座標をリニアなスペースのスクリーン座標に変換します。中心窩レンダリングが有効でない場合、またはプラットプラットフォームがラスタライゼーションを使用しない場合、この関数は座標を変更せずに返します。
リニアなスクリーンスペースの UV 座標を非一様ラスタのスクリーンスペースに変換するには、以下の関数を使用します。
uvNonUniform = FoveatedRemapLinearToNonUniform(uvLinear);
非一様なラスタのスクリーンスペースにおける UV 座標をリニアのスクリーンスペースに変換するには、以下の関数を使用します。
uvLinear = FoveatedRemapNonUniformToLinear(uvNonUniform);
ガウシアンブラーなどのエフェクトを更新するには、以下の関数を使用します。
uvNonUniform = FoveatedRemapDensity(uvLinear);
Shader Graph の Screen Position ノードには、中心窩レンダリングの影響を受けるテクスチャのサンプリングによく使用される座標があります。この Shader Graph ノードの Mode 設定により、座標の形式が決定されます。ほとんどのモードでは、VRR でレンダリングするときの座標空間は非一様です。一方、Raw モードは、すべてのケースでリニアです。
| Screen Position モード | UV 座標空間 || | | 可変レートシェーディング (VRS) と非中心窩レンダリング | 可変レートラスタライゼーション (VRR) | | :——– | :—-: | :———: | Default | リニア | 非一様 Raw | リニア | リニア Center | リニア | 非一様 Tiled | リニア | 非一様 Pixel | リニア | 非一様
Screen Position ノードの Raw モードを使用して非一様なテクスチャをサンプリングすると、結果は不正確になります。
この状況を説明するために、Screen Position ノードが Scene Depth ノードに接続され、そのノードがフラグメントシェーダーの通常色に接続されている Shader Graph について考えてみます。
このシェーダーは、シーンの深度バッファの深度値に応じて色をレンダリングします。このシェーダーは、Default モードの Screen Position ノードを使用しており、深度バッファ (およびエンジンによって作成された他のほとんどのテクスチャ) と同じスペースに結果を返すため、中心窩レンダリング下で正しく機能します。ただし、モードを Raw に変更すると、可変レートラスタライゼーションを使用するプラットフォームで中心窩レンダリングが有効な場合は、結果が正しくなくなります。
| 正しいサンプリングと一致しないサンプリング | |
|---|---|
![]() |
![]() |
| 左の画像は、シェーダーがクアッド上にあり、正しい座標空間を使用してシーン深度バッファをサンプリングしていることを示しています。 | 右の画像は、サンプリングされたテクスチャに誤った座標空間を使用した中心窩レンダリングを示しています。サンプリングされたテクスチャがシーンのジオメトリと一致しなくなっていることに注意してください。 |
Shader Graph が Raw 画面の位置を利用しており、他のモードを使用できない場合は、Custom Function ノードで中心窩レンダリング用のシェーダー関数を使用して Raw 座標を再マップします (正規化する必要があります)。
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
// The Raw mode screenPosition must first be normalized: position.xy/position.ww
void CorrectedScreenPosition_float(float4 screenPosition, out float2 correctedScreenPosition)
{
correctedScreenPosition = FoveatedRemapLinearToNonUniform(screenPosition);
}
注意この場合、Custom Function ノードを作成してファイルを参照する必要があります。これは、文字列型を使用すると、#include ステートメントが関数本体の中に配置され、構文エラーが発生するためです。
例えば、以下の Shader Graph は 2 つの Custom Function ノードを通じて Raw 座標をルーティングしています。
1 つ目のカスタム関数は、x 要素と y 要素を w 要素 (B = A.xy/A.ww) で割ることで Raw 座標を正規化します。2 つ目のカスタム関数は、必要に応じて FoveatedRemapLinearToNonUniform を使用してリニア座標を非一様なスペースへマップします。中心窩レンダリングが無効になっている場合、または現在のプラットフォームが中心窩レンダリングに VRR を使用しない場合、FoveatedRemapLinearToNonUniform はリニア座標を変更せずに返すことに注意してください。このようにして、シェーダーはすべての状況でシーン深度を正しくサンプリングします。