超雑訳 CSM Scrolling, An acceleration technique for the rendering of cascaded shadow maps

こんちゃ!
Pocolです。
今日は…
[Acton 2012] Mike Acton, “CSM Scrolling, An acceleration technique for the rendering of cascaded shadow maps”, SIGGRAPH 2012 Advances in Real-Time Rendering in Games course.
を読んでみようと思います。
いつもながら、誤字・誤訳があるかと思いますので,ご指摘頂ける場合は正しい翻訳例と共に指摘して頂けるとありがたいです。

Abstract

本講演では、ビットマップスクロール技術をシャドウマップキャッシングスキームと組み合わせることで、ゲームにおけるリアルタイムカスケードシャドウマッピングのパフォーマンスを大幅に向上させる方法について説明します。この2つのシステムは、カスケードシャドウマッピングの標準モデルにうまく統合され、フレーム間でレンダリングされたシャドウマップ情報の多くを保持するためにテンポラルコヒーレンスを利用します。この技術は現在のゲーム機に適しており、Insomniac社の近日発売タイトルである「overstrike」に搭載される予定です。

1. Introduction

我々は、[Engel 06]で説明されているカスケードシャドウマップ(CSM)の標準的な技法をベースにしています。シャドウマップのための線形深度バッファは,全体を通して仮定され,近傍平面と遠方平面はそれぞれ0.0と1.0の深度に対応します。我々は、与えられたCSMマップが使用されるカメラの錐台のビューのサブセクションを記述するために”sub-frustum”という用語を使用します。

典型的なゲームシナリオでは、CSMバッファの内容がフレーム間で非常に一貫していることが観察できます。通常、太陽光の方向は一定であり(または、ほとんどの場合、そのように扱うことができる)、多くのシーンオブジェクトは静止しており、動いているのはカメラとシーンジオメトリのごく一部だけです。

カメラが静止している場合、地面や建物などのシーン要素は一般的にシャドウマップ内で変化せず、比較的小さなオブジェクトだけが動き、マップに再描画する必要があります。このことから、CSMプロセスでは、静的な部分をフレーム間でキャッシュすることで、ゼロから描画する必要があるのは小さな部分だけであることがわかります。

一方、カメラだけが動いている場合、シャドウ・マップはカメラの視錐台の一部分に従うように制約されているため、マップの内容全体がフレームごとに変化することになります。しかし、この変化は予測可能な方法で発生するため、スクロール技術を使ってマップの内容の多くを保持し、再描画が必要なジオメトリの量を減らすことができます。

一般的に、カメラも他のシーン要素も動いているため、キャッシュとスクロールのテクニックを組み合わせることで、各フレームのマップ生成を高速化することができます。

2. Shadow map caching

CSMスクロールは、シャドウマップをキャッシュするための、より一般的なテクニックをベースにしています。各ライトに対してシャドウマップが生成されるリアルタイム・ライティング・システムを考えてみましょう。与えられたフレームに対してライトのマップを準備する際、通常、どのシーンオブジェクトがライトから「見える」かを決定するためにシーンクエリが実行され、マップに描画する必要があります。このクエリは通常、シーンオブジェクトがライトの影響範囲と重なるかどうか、そしておそらくライトの視点からのオクルージョンをテストします。テストに合格したオブジェクトは、マップへのレンダリングのために送信されます。また、各シーンオブジェクトにアクティブかスタティックかのフラグを立てることもできます。スタティックとみなされるには、オブジェクトは一定の基準を満たさなければなりません。例えば、所定の時間(例えば10秒間)静止しているなどです。(ここでは、アクティブとスタティックの間の状態変化が比較的まれであることを保証するのに十分な長さの、何フレームもの時間間隔が適切です)。

シーン・クエリが、前のフレームと同じオブジェクトのリストを返すこともあります。これらのオブジェクトがすべて静的とフラグが立っていて、さらに影を落とすライトが動いていなければ、明らかにシャドウマップは前のフレームのものと同じになります。前のフレームでマップをメモリにキャッシュしておけば、現在のフレームではそれをそのまま再利用可能です。

例えば、キャラクターがライトの経路を歩いているとします。それでも、マップの残りのかなりの部分は変わらないかもしれない。そのため、静的オブジェクトだけを含むマップのバージョンをキャッシュしておき、まずそれを作業メモリ領域にコピーし、その上にアクティブなオブジェクトをレンダリングすることで、そこから完成したシャドウマップを生成することは有益です。アクティブ・オブジェクトのリストが小さい場合、キャッシュされたマップのために確保された永続的なメモリの代償として、レンダリング作業を大幅に節約できる可能性があります。マップに16ビットの深度フォーマットを使用することで、このコストをいくらか下げました。

シャドウ・マップ・キャッシング技術の擬似コード概要は以下の通りで、図1は擬似コードで説明されたプロセスを要約したものです。

リストSを決定するためのオクルージョンテストは、オクルーダーの役割として静的なシーンオブジェクトのみを使用すべきであることに注意してください。我々は一度オクルードされたら,オクルードされたままのSのメンバーを保証したく,アクティブなオクルーダーはこれに対して明らかなに不向きです。

※疑似コードは, [Acton 2012]より引用

※図は,[Acton 2012]より引用

3. CSM scrolling

ローカル光源の一般的なケースを扱う場合、シャドウマップキャッシング技術は、一般的に、シャドウ投影が前のフレームから静止している場合にのみ有用です。一方、太陽光の方向が一定である場合のカスケードシャドウマップの特殊なケースでは、カメラの移動や回転に伴って投影が頻繁に変化しますが、それは特に単純な方法で行われます。まず、カメラの移動だけを考えてみましょう。もし移動が光線方向に対して垂直であれば、2Dマップの内容は左右または上下にスクロールされます。つまり、マップの各ピクセルは、カメラが移動した分だけインクリメントまたはデクリメントされる。カメラの一般的な平行移動には、これら2つの効果の組み合わせが含まれます。

カメラを回転させると、CSMビュー・ボリュームがより大きく移動することがよくあります。これらの移動は平行移動であるため、マップの内容は、移動の大きさは大きくなるものの、同じような影響を受けます。

これらの観察から、先に説明したシャドウマップ・キャッシング方式は、マップデータの一部をスクロールさせる技術と組み合わせることで、カスケード接続されたシャドウマップをカバーするように拡張できるという考えが生まれました。基本原理は、現在のフレームと前のフレームの両方に共通するマップの静的部分をスクロールし、新たにレンダリングされた静的ジオメトリで端のギャップを埋めることです。スクロールがどのように行われるかという低レベルの仕様はひとまず無視して、CSMバージョンは以下の擬似コードに示されており、図2は擬似コードに概説されているメカニズムを要約したものです。

注:前フレームのクエリから静的オブジェクトのリストであるS’を取得する際には、前フレームの位置情報のキャッシュバージョンを使用することが重要です。シーンオブジェクトに関する現在のフレームの情報は、以前は静的であったオブジェクトの一部が移動または削除されている可能性があるため、ここでは不十分です。

アルゴリズムのパフォーマンスにとって重要なのは、ジオメトリを比較的コンパクトなチャンクに分割したシーンの記述を使用することです。シーンを単一のモノリシックな要素としてレンダリングしても、わずかなカメラの動きにもレンダリングコストがかかるため、何も得られません。

図2から、集合ΔSは、新しく静止したオブジェクトと、最後のフレーム以降に視界にスクロールしてきた以前の静止オブジェクトの両方から構成されていることがわかります。

※疑似コードは, [Acton 2012]より引用

※図は,[Acton 2012]より引用

4. Low-level scrolling mechanism

これは、各ピクセルのuvオフセットが一定である単純なテクスチャマッピングと大差がないため、gpuに適した操作です。

4.1. Lateral scrolling

まず、カメラの動きが光線の方向に垂直な平行移動であるとします。深度の変化は発生せず、既存のテクスチャデータの単純なuv変換で十分です。これは、ピクセルシェーダで次のように表現される、通常のテクスチャマッピングを使用して実行できます:

※疑似コードは, [Acton 2012]より引用

ここでのテクスチャ・ルックアップはポイント・サンプリングを使用しています。頂点シェーダは単に補間されたテクスチャ座標を供給し、適切にオフセットされたテクスチャ座標でフルスクリーンポリゴンが描画されます。オフセットの計算についてはセクション5で説明します。

4.2 Scrolling in the depth dimension

ライトの方向に平行な動きを実現するには、サンプリングされた各深度に深度オフセット値を加える必要があります。したがって、3軸すべてに沿った一般的な移動は、深度オフセットを追加した通常のテクスチャマッピングによって得られます:

※疑似コードは, [Acton 2012]より引用

入力インターポレーターの3番目のチャンネルは、深度オフセットを渡すために使われています。

4.3 Treatment of the boundaries

マップの境界を越えてテクセルを読み込もうとした場合は、未知の深さとして扱われ、その後に新しくレンダリングされたデータで埋められます。つまり、深度バッファのクリア値である1.0にクリアされるべきです。これは、clamp-to-borderモードを設定し、ボーダーカラーを1.0に設定することで最も簡単に実現できます。

同様に重要なのは、ニア・ファーの距離の範囲外にある深度の扱いです。ハードウェアは通常、結果を[0.0, 1.0]の範囲にクランプしてから書き出します。このクランプ動作が望ましいかどうかを検討する必要があります。

深度オフセットによってピクセルの新しい深度がニアプレーンに近い側になる場合、つまり負の深度値になる場合は、深度を0.0にクランプしてもよいです。シャドウマップにレンダリングされた結果とは異なりますが、スクロール技術の有無にかかわらず、常に望ましくありません。したがって、この違いは、実際には一般的に発生しません。実際、スクロールマップバージョンの非標準的な動作は、遠くのキャスターからの影に穴が開くのをある程度防ぐことができるため、間違いなく、より望ましいと見なすことができます。

ファープレーンの状況は少し違う。範囲外の値を1.0にクランプするのは賢明だが、追加の処置が必要だ。ルックアップされた深さがすでに1.0fで、遠い平面に対応し、深さのオフセットが負であるとします。単純に深度オフセットを加えて、結果の深度を書き出すと、それは遠い平面よりも近い表面を表すことになります。この素朴な方法の問題点は、1.0fが深度バッファのクリア値でもあることです。つまり、遠平面上に正確に横たわる点は、単にバッファクリア以降書き込まれていないピクセルと区別がつきません。深度オフセットによってレンダリングボリュームの後壁全体が深度方向に引っ張られるのは避けたいところです。したがって、1.0の深度は書き込まれていないピクセルを表し、1.0のままにしておくのが賢明です。この操作をサポートする標準的なハードウェア設定がないため、ピクセルシェーダに条件付きテストを追加します。最終バージョンは次のようになります。

※疑似コードは, [Acton 2012]より引用

5. Managing the render volume associated with a map

すべてのマップに適用される正方形のテクスチャソリューション(私たちのシステムでは512×512)が前もって選択されます。シャドウマッピングを必要とするカメラ錐台の部分は、[Engel 06]で紹介されている標準的なCSMアルゴリズムと同様に、カメラのz軸に沿って選択された深さに位置する平面を分割することによって、(通常は4つの)sub-frustumに分割されます。

これで各マップにレンダーボリュームが割り当てられました。ボリュームの物理的なサイズは、対応するカメラのsub-frustumの直径(任意の2点間の最も遠い距離)を包含するのに十分な大きさでなければならず、次に説明する全テクセル移動を可能にするために、各方向に1テクセルずつ拡大されます。ある著者の主張とは逆に、sub-frustumの境界球を包含する必要はないことに注意してください。ジオメトリのレンダリングには、カメラのsub-frustumの「影」の外側にあるかどうかに関係なく、各マップの全領域を使用します。

レンダーボリュームは、[Valient 08]で説明されているように、カメラが動いているときに静止した影の安定性を維持するために、光線の方向に垂直な2つの軸に全テクセル量だけ移動させる必要があります。CSMスクロールでは、この制約を必要とするもう1つの理由があります:スクロールされたシャドウデータの整合性を維持するためです。この場合,レンダリングボリュームが全深度単位,たとえば16ビット深度バッファの場合は\(2^{-16}\)だけシフトするように,光線に平行な移動を制約することも望ましいです。

我々のシステムでは、与えられたマップのレンダーボリュームの位置を決定するために、まずカメラsub-frustumをライトの座標フレームに変換します。この座標フレームは、z方向が光線に平行で、x軸とy軸がワールドアップ方向によって通常の方法で拘束され、原点がワールド原点に一致するようにした直交フレームです。次に、ライト空間座標でsub-frsutumの軸合わせバウンディングボックスを見つけ、これを使用してレンダーボリュームの中心を配置します。最後に、座標を全テクセル単位と全深度単位に丸めます。

結果の座標は2つの方法で使用されます。ワールド座標に変換して戻すことで、カリング用のクエリボリュームとレンダリング用のレンダーボリュームを配置できます。また、ライト空間座標の1フレーム履歴を保持することで、現在のフレームのスクロール量を生成するのに必要なすべての情報を得ることができます。次のコードは、ライト空間座標のAABBの位置が、セクション4のシェーダーに渡される頂点レベルの値にどのように変換されるかを示しています:

※疑似コードは, [Acton 2012]より引用

余談:マップへのレンダリングに費やす時間を短縮するための1つの可能なテクニックは、マップの周囲にガードバンドを設けることです。これは、フレームバッファへのレンダリング時にサンプリングされるマップの部分の外側にあるにもかかわらず、シャドウマップデータを冗長に保存する領域です。このような「拡張マップ」の利点は、マップがガードバンドの外側に移動する必要があるまで、スクロールや静的なジオメトリの再描画を行う必要なく、マップに対応する領域を拡張マップの内側で移動させることができることです。もちろん、ここにはトレードオフがあります。平均レンダリング時間の短縮は、マップが大きくなるか、シャドウが粗くなるという代償を伴います。

6. Results

図3では、カメラの平行移動下でのCSMの4つのレベルのシャドウ深度バッファが示されています。灰色のバッファは、すべてのジオメトリの無条件レンダリングの結果を示し、青色のバッファは、スクロール操作の直後にキャッシュされたデータの部分を示し、赤色のバッファは、スクロールされたデータの上にレンダリングされる新しく表示される静的ジオメトリを示します。この例ではアクティブなシーンオブジェクトは使用されていません。

※図は,[Acton 2012]より引用

青いマップの下と右にある白い帯に注目してください。これは、スクロール処理によってバッファのクリアカラー(1.0f)に設定された領域で、次の処理によって塗りつぶされる領域を表しています。

図3のカメラモーションの速さは約\(15{\rm ms}^{-1}\)です(30fpsの場合)。青いマップのブランク・ストリップのテクセル単位でのサイズは、マップの物理的サイズに反比例して変化することに注意してください。

図4は、カメラの回転運動が毎秒約210度(30fps)の場合に対応する結果を示しています。この場合、各カメラのsub-frsutumは視点からの距離に比例した速度で回転するため、4つのマップすべてで空白ストリップのテクセルサイズはほぼ同じになります。

※図は,[Acton 2012]より引用

この2つの動きの大きさは、典型的な試合中のシナリオで遭遇する可能性のあるものよりも大きい方である。特に右側の粗いマップでは、赤いジオメトリが比較的ないことが、このテクニックの価値を示しています。

※図は,[Acton 2012]より引用

7. Bibliography

  • [Engel 06] W. Engel. “Cascaded shadow maps”, in: Engel, W.F., et al., “ShaderX5 – Advanced Rendering Techniques”, Charles River Media, 2006.
  • [Valient 08] M. Valient. “Stable rendering of cascaded shadow maps”, in: Engel, W. F., et al., “ShaderX6 – Advanced Rendering Techniques”, Charles River Media, 2008.