This is the documentation for Enlighten.

6.5.3. ピクセルごとのプローブ ライティング


ピクセルごとのプローブ ライティングは、視点から近いエリアでは最大限の有効な間接光の解像度を提供しますが、遠いエリアでは有効解像度を自動的に下げます。

この手法では、タイルで構成されたアトラスにインデックス化される間接クリップマップ テクスチャを実装した 3D 仮想テクスチャを使用します。

この手法は、非常に大きなメッシュ全体で正確なライティングを実現します。実行コストは、更新されるプローブの数によってのみ増加し、プローブによってライティングされるオブジェクトの数は関係ありません。

ほとんどのケースでは、ピクセルごとのプローブ ライティングを使用することをお勧めします。

ピクセルごとのプローブ ライティングを使用するには以下を行います。

  • 高レベル ランタイムを構成して、Entire Probe Set Solver を有効にする必要があります。 
  • 自動プローブ配置を使用する必要があります。
  • L1 SH プローブ出力を使用する必要があります。
  • 浮動小数点プローブ出力を使用する必要があります。

高レベル ランタイム更新マネージャーを使用して、ラジオシティ計算の結果に応じて仮想テクスチャを更新します。間接光をレンダリングするには、仮想テクスチャからプローブ SH 係数をサンプリングし、ピクセル法線の方向でSH ライティングを評価します

初期設定

PppiConfiguration を使用して 3D 仮想テクスチャを構成します。すぐに使用するには、デフォルト コンストラクターを使用して適当なデフォルト値を得ます。高レベル ランタイム更新マネージャーを構築する際は、UpdateManagerProperties::m_PppiConfiguration に構成を割り当てます。

Enlighten::UpdateManagerProperties properties;
properties.m_UseEntireProbeSetSolver = true;
properties.m_PppiConfiguration = Enlighten::PppiConfiguration();

IUpdateManager::GetPppiRequiredOutputTextures を呼び出して、必要な出力テクスチャのサイズと形式を確認します。 

Enlighten::PppiOutputTextureRequirements requirements = updateManager->GetPppiRequiredOutputTextures();

各出力テクスチャに対し、必要なサイズと形式のレンダリング リソースを作成します。

更新マネージャーはこれらのテクスチャの所有権を持たないため、呼び出し元でテクスチャのライフタイムが更新マネージャーと同じであることを確認する必要があります。 

使用可能なプラットフォームでは、共有 GPU メモリのテクスチャをタイリングしていない線形レイアウトで使用することをお勧めします。Enlighten は、これらの CPU 上のテクスチャに直接書き込むことができます。このオプションを使用できない場合、テクスチャ データのコピーを保持できる大きさの別のバッファを割り当てます。

メモリの出力テクスチャのレイアウトを示す PppiOutputWorkspace 構造体を構築し、IUpdateManager::SetPppiOutputWorkspace を呼び出します。

出力テクスチャを CPU に直接書き込むことができない場合、テクスチャが更新されるたびに、使用しているグラフィックス API を使ってこのバッファの変更部分を GPU にフラッシュする必要があります。出力テクスチャが書き込まれたときにこの動作を行う IPppiTextureUpdateHandler の実装を提供します。 

IUpdateManager::AllocateProbeSet、DetachProbeSet、または UpdatePppi を呼び出すたび、仮想テクスチャが更新され、出力テクスチャ更新通知が生成されます。1 つのフレームで多数の通知が生成される可能性があるので、必要なグラフィックス API 呼び出し数を最小限に抑えるために、複数の更新をまとめることをお勧めします。

class PppiTextureUpdateHandler : public Enlighten::IPppiTextureUpdateHandler
{
    void UpdateAtlas(const Enlighten::VolumeTextureRegion& region)
    {
        // CPU から GPU にコピーするアトラス テクスチャの特定領域をマークします
    }
 
    void UpdateIndirection(const Enlighten::IndirectionTextureRegions& regions)
    {
        // CPU から GPU にコピーするアトラス テクスチャの特定領域をマークします
    }
};

各フレーム

メッシュを描画する前に、IUpdateManager::Update の呼び出しと同時に IUpdateManager::UpdatePppi を呼び出します。ビューの原点を指定して、視点から近い位置でフル解像度の間接光を実現します。

ビュー ボリュームを提供することにより、ワールドの視認できないエリアを更新するコストの発生を防ぐことをお勧めします。最適化の選択肢として、ライティングの精度と引き換えに、LOD 距離を制限して更新を高速にすることが挙げられます。 

交互に切り替わるフレームの異なるビューに対し IUpdateManager::UpdatePppi を呼び出した場合、不必要でコストが高い間接テクスチャ更新が発生する可能性があります。

両方のビューが非常に似通っている場合、これらを組み合わせたビュー ボリュームと平均のビューの原点を IUpdateManager::UpdatePppi に指定します。これらのビューが大きく異なる場合、各ビューに更新マネージャーのインスタンスを 1 つ作成します。

間接光のレンダリング

ピクセル シェーダーで仮想テクスチャをサンプリングするには、GeoRuntime/Resources/PppiCommon.cgSamplePppiVirtualTexture 関数で IUpdateManager::UpdatePppi により返された出力テクスチャとシェーダー パラメーターを使用します。

抜粋:PppiCommon.cg
struct PppiSample
{
    float4 R;
    float4 G;
    float4 B;
    float InverseValidity;
    float EnvironmentVisibility;
};
 
PppiSample SamplePppiVirtualTexture(float3 worldPosition, float3 viewOrigin)
{
    ...
}

引数 worldPosition は、ピクセルのワールド空間の位置です。引数 viewOrigin は、カメラの位置であり、詳細レベルを決定するために使用します。

PppiSample の RG、および B は、各カラー チャネルの L1 SH 係数を含んでいます。これを使い、ピクセル法線の方向で SH ライティングを評価します。

無効な (間引かれた) プローブに近いエリアでは、ライティングの結果は暗くなります。これを相殺するには、ライティングの結果に InverseValidity を乗算します。