This is the documentation for Enlighten.

7.6. ライト可視性データ


光源による影がある場合、影がかかったエリアで不要なバウンス光を避けるため、Enlighten にライト可視性データを提供する必要があります。

この可視性データには、ラジオシティ システムのサーフェスの入力サンプル ポイントごとに 1 ビットが含まれます。既定のサンプル ポイントのビットは、そのポイントに対して光が影を落とすかどうかを決定します。

移動しない光源については、この可視性データを事前に計算することをお勧めします。移動する光源については、GPU に存在するシャドウ マップまたはレイ トレースをサンプリングしてこの可視性データを作成することをお勧めします。

移動するライトの可視性データを計算する効率的な方法は、シャドウ マップから読み取る GPU ピクセルまたはコンピュート シェーダーを使用することです。

アルゴリズム

  1. Enlighten ワークスペースからサンプル位置を抽出します
  2. 抽出した位置をテクスチャまたはコンピュート バッファにパッキングします
  3. コンピュート シェーダーまたはピクセル シェーダー コードで実行します
    1. サンプルをライト空間に投影します
    2. シャドウ マップに対してサンプルの深度を比較します
    3. 可視性を連続したビット値に順に並べます
  4. 出力バッファ/レンダリング ターゲットに結果を書き込みます
  5. 出力バッファ/レンダリング ターゲットの内容を CPU メモリに読み込みます
  6. CPU メモリ ポインターを入力ライティング ソルバーに渡します

可視性の形式

入力ライティングは可視性を一連のビットとして読み取ります。バッファの各ビットは、既定のライトのジオメトリのサンプル ポイントの可視性を表します。各システムは、各ライトについて個別の可視性バッファを必要とします。可視性バッファのサイズは、以下の関数を使用してシステムのサンプル位置の数に基づき決定されます。

Geo::s32 perLightSizeForSystem = CalcLightVisibilitySize(inputWorkspace,
                VisibilityFormat::PER_DUSTER_VISIBILITY);

可視性バッファの各ビットはジオメトリのポイントの可視性を表すため、バッファ内のビットの順序は Enlighten API により返される位置の順序と一致している必要があります。

入力サンプル位置

入力サンプル位置は、ラジオシティ計算に含まれるサーフェスに配置されます。描画されるメッシュは、以下の場合にラジオシティ計算に含まれるメッシュと若干異なる場合があります。

シャドウ マップをサンプリングする際に正確なシャドーイングを確保するには、入力サンプル位置がシャドウ マップに描画されたメッシュと同じものに基づいていることを確認してください。

最も簡単な解決策は、ラジオシティ計算に含まれていた LOD と同じものをシャドウのレンダリングに使用し、GetInputWorkspacePositionArray を呼び出して入力サンプル位置を取得します。

投影されたサンプル位置

シャドウ マップにラジオシティ計算に含まれているものと別の LOD を描画する必要がある場合は、投影されたサンプル位置を使用してください。これらの位置を生成するには、Enlighten シーンをエクスポートする際に includeProjectedPointData パラメーターを追加します。

GetInputWorkspaceProjectedPointVersion を呼び出し、既定のインスタンスと LOD の投影された位置を取得します。

以下の GpuSpotlightVisibilityEngine.cpp の関数が GeoRadiosity で使用され、投影されたサンプル位置を抽出します。

//--------------------------------------------------------------------------------------------------
void GEO_CALL PatchDusterPositionsForLodLevel(Geo::v128* dusterPositions, const Enlighten::InputWorkspace* inputWorkspace, Geo::s32 lodLevel)
{
    // システムのすべてのインスタンス ID のリストを取得します
    s32 numInstanceIds = 0;
    GetInputWorkspaceNumInstanceIds(inputWorkspace, &numInstanceIds);
    if (numInstanceIds > 0)
    {
        // インスタンス当たりのポイントの最大数が合理的か確認します
        const s32 numDusterPoints = Enlighten::GetNumberOfPointsInInputWorkspace(inputWorkspace);
        {
            s32 maxPointsAnyInstance = 0;
            const bool gotMaxPoints = GetInputWorkspaceMaxProjectedPointsInAnyInstance(inputWorkspace, &maxPointsAnyInstance);
        }
 
        // インスタンス ID の配列
        GeoAutoPtr<s32, GeoDeleteArrayDestructor<s32> > instanceIds(GEO_NEW_ARRAY(s32, numInstanceIds));
        // パッチされた位置とインデックスの配列
        GeoAutoPtr<s32, GeoDeleteArrayDestructor<s32> > pointIndices(GEO_NEW_ARRAY(s32, numDusterPoints));
        GeoAutoPtr<v128, GeoDeleteArrayDestructor<v128> > pointPositions(GEO_NEW_ARRAY(v128, numDusterPoints));
        GetInputWorkspaceInstanceIds(inputWorkspace, instanceIds.GetPtr());
 
        for (s32 i = 0; i < numInstanceIds; ++i)
        {
            // このインスタンスのポイントを見つけます
            const s32 instanceId = instanceIds[i];
            s32 numProjectedPoints = 0;
            GetInputWorkspaceProjectedPointVersion(inputWorkspace, instanceId, lodLevel, pointIndices.GetPtr(), pointPositions.GetPtr(), &numProjectedPoints);
 
            // パッチを適用します (このバージョンのデータがない場合は、長さ 0 になる可能性があります)
            for (s32 p = 0; p < numProjectedPoints; ++p)
            {
                const s32 ii = pointIndices[p];
                dusterPositions[ii] = pointPositions[p];
            }
        }
    }
}

シェーダー

可視性ピクセル シェーダーの例については、Enlighten ソリューションの GpuSpotlightVisibility.cg をご覧ください。このシェーダーの例は、最大限の互換性を保つよう記述されており、4 つの 8 ビット コンポーネントを持つレンダリング ターゲットを使用しています。これは、既定のターゲット プラットフォームでレンダリングする際には最も効率的な形式ではないことがあります。

この例では、各ピクセルは 32 のサンプルの可視性を計算し、ピクセル シェーダーの出力として書き出される単一の 32 ビット値にまとめます。コード例で使用している出力テクスチャは、幅 32 ピクセル、高さは可視性バッファ全体に適合するために必要な行の数として決定されます。

スレッドごとに単一のサンプルの可視性を計算し、その後 32 のスレッドの可視性の結果を単一の 32 ビット値にまとめるため、コンピュート シェーダーによる GPU 可視性の実装がより効率的になります。次に、これらの値を出力バッファ/テクスチャに書き出し、入力ライティング ソルバーに入力として取り込まれるようにします。