

シャドウマッピングまたはシャドウイングプロジェクションは、 3Dコンピュータグラフィックスに影を追加するプロセスです。この概念は、1978年にランス・ウィリアムズによって「曲面への曲面の影の投影」というタイトルの論文で紹介されました。[ 1 ]それ以来、多くのコンソールゲームやPCゲームで、プリレンダリングシーンとリアルタイムシーンの両方で使用されています。
影は、ピクセルをzバッファ[ 2 ]またはテクスチャの形式で保存された光源のビューの深度画像と比較することにより、ピクセルが光源から見えるかどうかをテストすることによって作成されます。
光源から外を見ると、見える物体はすべて光の中に現れます。しかし、それらの物体の背後にあるものはすべて影になります。これがシャドウマップを作成する際に用いられる基本原理です。光源の視点からの画像がレンダリングされ、光源が捉えるすべての面の深度(シャドウマップ)が保存されます。次に、描画されたすべての点の深度(目ではなく光源から見た場合)をこの深度マップと比較することで、通常のシーンがレンダリングされます。
この手法はシャドウボリュームよりも精度は劣りますが、特定のアプリケーションでどちらの手法も必要な塗りつぶし時間によっては、シャドウマップの方が高速な代替手段となり得るため、リアルタイムアプリケーションにより適している場合があります。さらに、シャドウマップは追加のステンシルバッファを必要とせず、エッジが滑らかなシャドウを生成するように変更することも可能です。ただし、シャドウボリュームとは異なり、シャドウマップの精度はその解像度によって制限されます。
影付きシーンのレンダリングには、大きく分けて2つの描画ステップがあります。1つ目はシャドウマップ自体を生成するステップ、2つ目はそれをシーンに適用するステップです。実装方法(および光源の数)によっては、2回以上の描画が必要になる場合があります。


最初のステップでは、光源の視点からシーンをレンダリングします。点光源の場合、投影図は、光源が照射したい角度と同じ幅の透視投影図にする必要があります(一種の正方形のスポットライトになります)。指向性のある光(例えば、太陽光)の場合は、正射投影図を使用する必要があります。
このレンダリングから深度バッファが抽出され、保存されます。深度情報のみが重要であるため、描画時間を節約するために、このレンダリングではカラーバッファの更新を避け、すべてのライティングとテクスチャの計算を無効にするのが一般的です。この深度マップは、多くの場合、グラフィックスメモリにテクスチャとして保存されます。
この深度マップは、シーン内の光源またはオブジェクトに変更があった場合は必ず更新する必要がありますが、ビューイングカメラのみが移動するような状況では再利用できます。(光源が複数ある場合は、光源ごとに個別の深度マップを使用する必要があります。)
多くの実装では、シーン内のオブジェクトのサブセットのみをシャドウマップにレンダリングすることで、マップの再描画にかかる時間を節約できます。また、次のステップで描画されるサーフェス(つまり、影を落とすサーフェス)の深度マップの値が、ステッチングの問題を解決するために、オブジェクトを光源から遠ざける深度オフセットをシャドウマップのレンダリングに適用することもあります。あるいは、同様の結果を得るために、前面をカリングしてオブジェクトの背面のみをシャドウマップにレンダリングする方法が用いられることもあります。
2 番目のステップは、通常のカメラの視点からシーンを描画し、シャドウ マップを適用することです。このプロセスには 3 つの主要なコンポーネントがあります。最初のステップは、光源から見たオブジェクトの座標を見つけることです。3Dオブジェクトは、画面上でその幾何学的形状を表すために X 軸と Y 軸を持つ2D座標のみを使用するため、これらの頂点座標は、シャドウ マップ (深度マップ) 内の影の部分の対応するエッジと一致します。2 番目のステップは、オブジェクトの z 値を深度マップの z 値と比較する深度テストです。最後に、これが完了したら、オブジェクトを影または光で描画する必要があります。

深度マップに対して点をテストするには、シーン座標におけるその点の位置を、光源から見た等価な位置に変換する必要があります。これは行列乗算によって行われます。画面上のオブジェクトの位置は通常の座標変換によって決定されますが、光源空間におけるオブジェクトの位置を特定するには、別の座標セットを生成する必要があります。
世界座標を光源の視点座標に変換するために使用される行列は、最初のステップでシャドウマップをレンダリングするために使用される行列と同じです(OpenGLでは、これはモデル行列、ビュー行列、および投影行列の積です)。これにより、正規化されたデバイス座標にするために透視除算(3D 投影を参照)が必要な同質座標のセットが生成されます。正規化されたデバイス座標では、各コンポーネント(x、y、またはz)は -1 から 1 の間に収まります(光源の視点から見える場合)。多くの実装(OpenGL やDirect3Dなど)では、これらの -1 から 1 の値を 0 から 1 にマッピングするために、追加のスケール行列とバイアス行列の乗算が必要です。これは、深度マップ(テクスチャマップ)のルックアップでより一般的な座標です。このスケーリングは透視除算の前に実行でき、次の行列を乗算することで、前の変換計算に簡単に組み込むことができます。
シェーダーやその他のグラフィックスハードウェア拡張機能を使用してこの変換を行う場合、通常は頂点レベルでこの変換が適用され、生成された値は他の頂点間で補間されてフラグメントレベルに渡されます。

光空間座標が見つかると、xとyの値は通常、深度マップテクスチャ内の位置に対応し、zの値はそれに関連付けられた深度に対応するため、深度マップに対してテストを行うことができます。
z値が適切な( x , y )位置の深度マップに格納されている値よりも大きい場合、そのオブジェクトは遮蔽物の背後にあるとみなされ、描画処理で影として描画されるエラーとしてマークされます。そうでない場合は、明るく描画されます。
( x , y ) の位置が深度マップの範囲外にある場合、プログラマーはデフォルトでサーフェスを照らすか影にするかを決定する必要があります (通常は照らす)。
シェーダー実装では、このテストはフラグメントレベルで行われます。また、ハードウェアで使用するテクスチャマップのストレージの種類を選択する際には注意が必要です。補間ができない場合、影の縁がギザギザに見えてしまいます(この影響は、シャドウマップの解像度を上げることで軽減できます)。
深度マップテストを修正して、単に合格か不合格かを判断するのではなく、(影の端からの距離に基づいて)値の範囲を使用することで、エッジが柔らかい影を生成することが可能です。
シャドウマッピング技術は、照明された領域にテクスチャを描画するように変更することもでき、プロジェクターの効果をシミュレートできます。上の「シーンに投影された深度マップの可視化」というキャプションが付いた画像は、そのような処理の一例です。

影付きのシーンを描画するには、いくつかの異なる方法があります。プログラマブルシェーダーが利用可能な場合は、フラグメントシェーダーを使用して深度マップのテストを実行できます。フラグメントシェーダーは、結果に応じてオブジェクトを影付きまたはライト付きで描画し、(シャドウマップを生成するための最初のパスの後)1回のパスでシーンを描画します。
シェーダーが利用できない場合、深度マップテストは通常、何らかのハードウェア拡張機能(GL_ARB_shadowなど)によって実装される必要があり、通常、2つのライティングモデル(ライト付きとシャドウ付き)のどちらかを選択することはできず、より多くのレンダリングパスが必要になります。
この記事のサンプル画像では、OpenGL拡張機能GL_ARB_shadow_ambientを使用して、シャドウマップ処理を2段階で実行しました。
リアルタイムシャドウマッピングの主な欠点の 1 つは、シャドウマップのサイズと深度が最終的なシャドウの品質を決定することです。これは通常、エイリアシングやシャドウの連続性の不具合として現れます。この制限を克服する簡単な方法は、シャドウマップのサイズを大きくすることですが、メモリ、計算、またはハードウェアの制約により、常に可能とは限りません。リアルタイムシャドウマッピングで一般的に使用される技術は、この制限を回避するために開発されました。これらには、カスケードシャドウマップ[ 3 ] 、台形シャドウマップ[ 4 ]、ライトスペースパースペクティブシャドウマップ[ 5 ] 、またはパラレルスプリットシャドウマップ[ 6 ]などがあります。
また、生成された影は、エイリアシングがなくても、エッジが硬いという点も注目に値します。これは必ずしも望ましいものではありません。現実世界の柔らかな影を再現するために、影マップに対して複数のルックアップを実行したり、柔らかなエッジを再現するように設計されたジオメトリを生成したり、非標準の深度影マップを作成したりするなど、いくつかの解決策が開発されてきました。これらの代表的な例としては、パーセンテージクローザーフィルタリング[ 7 ] 、スムージー[ 8 ] 、およびバリアンスシャドウマップ[ 9 ]などがあります。
{{cite journal}}:ジャーナルを引用するには|journal=(ヘルプ){{cite journal}}:ジャーナルを引用するには|journal=(ヘルプ){{cite journal}}:ジャーナルを引用するには|journal=(ヘルプ){{cite journal}}:ジャーナルを引用するには|journal=(ヘルプ){{cite journal}}:ジャーナルを引用するには|journal=(ヘルプ) CS1 maint: 複数の名前: 著者リスト (リンク)が必要です