HDRLighting サンプル
このサンプルでは、浮動小数点テクスチャーを使用した HDR ライティング効果をいくつか紹介します。整数テクスチャー フォーマットの場合は、離散値の範囲が制限されているので、動的なライティング条件下ではカラー情報が失われます。逆に、浮動小数点フォーマットの場合は、表示可能な 0.0 ~ 1.0 の範囲を超える値も含め、非常に小さなカラー値または非常に大きなカラー値を格納できます。この柔軟性が、弱い光の下での青方変移や強い光の下でのブルーミングなどの動的なライティング効果を可能にします。また、このサンプルでは、カメラを一時的に露光過多にしたり露光不足にしたりしてライティング条件を変えるという単純な明順応モデルを使用します。
Path
ソース | SDK ルート\Samples\C++\Direct3D\HDRLighting |
実行可能ファイル | SDK ルート\Samples\C++\Direct3D\Bin\x86 または x64\HDRLighting.exe |
このサンプルが興味深い理由
現実の世界での光では、最大輝度と最小輝度との間に非常に高い比率があります。この比率はダイナミック レンジと呼ばれ、日常生活で目に見える光の場合、太陽と夜空の星とでは約 1012:1 です。広いダイナミック レンジに散らばる光を見るために、人間の視覚器官は光に合わせて露光を自動的に調節し、目に入ってくる光の強さに基づいて輝度の範囲を狭くします。暗い屋内と明るい屋外を行き来するとわかるとおり、このプロセスは瞬時に行われるものではありません。このように露光の調整に遅れが生じることは明順応と呼ばれ、リアルタイム アプリケーションでシミュレートできます。
コンピューター ディスプレイや印刷メディアのダイナミック レンジは約 100:1 なので、それよりも広いダイナミック レンジを持つシーンを表示する場合は妥協が避けられません。このサンプルは、もともとは写真に使うために考案されたトーン マッピングと呼ばれるテクニックを借用しています。トーン マッピングは、HDR イメージを狭いダイナミック レンジ空間にマッピングするプロセスです。トーン マッピングは、人間の視覚器官で行われる自動的な露光調節と同じ効果を効率的に生成します。
最後に、まぶしい光がレンズに差し込むと、次の図のようにブルーミングや星彩効果などの収差が自然に起こります。極度に強い光の値がレンダリング プロセスで破棄されない場合、シーンのレンダリング後にこれらの効果を生成して、イメージにさらに現実味を加えることができます。これらはポストプロセッシング効果なので、生成に要する時間は画面解像度にのみ依存し、シーンやライティングの複雑さとは無関係です。
概要
このサンプルでは、Direct3D 9 の浮動小数点テクスチャーを使用して、シーンの HDR ライティング情報を格納します。整数テクスチャー フォーマットは、ピクセル シェーダーでの 0.0f ~ 1.0f の範囲に制限されますが、浮動小数点テクスチャーは、仮数と指数に使用できるビット数に制約されるだけで、任意の値を格納できます。
このサンプルで示すアルゴリズムは、以下の参考文献で実装されているライティング効果にかなり忠実に基づいています。
Erik Reinhard、Mike Stark、Peter Shirley、および James Ferwerda 共著『Photographic Tone Reproduction for Digital Images』。ACM Transactions on Graphics (TOG), Proceedings of the 29th Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH), pp.267-276. New York, NY:ACM Press、2002 年発行。
サンプルが動作するしくみ
このサンプルの場合、シーンのオブジェクトは通常の整数フォーマット テクスチャーを使ってテクスチャー処理されますが、ライトを表す球体オブジェクトは高レンジの値を使ってシェーディングされ、放射光が効果的に作成されます。シーンのすべてのオブジェクトをシェーディングするために、アンビエント、ディフューズ、およびスペキュラのライティングをライトの位置とインテンシティを基に計算する照明モデルを使用します。その理由は、これらのライトに高い値が割り当てられることがあり、光に照らされるオブジェクトに生成されるカラーが 1.0f のカットオフをはるかに超える場合があるからです。これらの HDR 値を取り込むために浮動小数点テクスチャーを使用しない場合、このライト データは失われ、シーンは次の図のように露光過多で表示されることになります。
代わりに、シーンを浮動小数点サーフェイスにレンダリングすれば、HDR 情報は失われず、シーンは次の図のように適切な低ダイナミック レンジにトーン マッピングして表示することができます。
次の図は、このサンプルの最上位のフローを示しています。シーンは、最初に浮動小数点テクスチャーにレンダリングされます。テクスチャーのサイズは、バック バッファーと同じです。ポストプロセッシング効果を作成するためにシーンが数回サンプリングされるので、まずシーンを縮小してシェーダーがサンプリングするピクセル数を最小限にしておくと効果的です。これには、ポストプロセッシング効果に関連付けられたテクスチャーを最大化すると、ポストプロセッシング効果が大きくなるという別の利点もあります。スケーリングされたシーン テクスチャーは、シーンの平均輝度を測定するために処理されます。この平均輝度値を使うと、シーンを低ダイナミック レンジにトーン マッピングした後で、シーン内のどのピクセルが光るのかを確認できます。明るく照らされる領域を除いてシーン内のすべてのカラー データを除外すると、輝度パス フィルターが適用されたシーンのコピーが作成されます。このコピーは、ポストプロセッシング ライティング効果のソースとして使用できます。
このサンプルのシーンは、アンビエント、ディフューズ、およびスペキュラから各ピクセルに与えられるライトを制御するためにピクセル シェーダーを使ってレンダリングされます。このシーンのライトは非常に明るいので、ほとんどのピクセルの各チャンネルのカラー成分はグラフィックス カードで表示可能な 0.0 ~ 1.0 の範囲を超え、テクスチャーを直接表示するとほとんどの部分が白く見えます。ただし、1.0 を超えるカラー情報は失われないので、0.0 ~ 1.0 の範囲にトーン マッピングする必要があるだけです。最終的なパスの段階で、シーンは目的の輝度範囲にトーン マッピングされ、ポストプロセッシング イメージ効果がシーンの上にブレンドされて最終的なイメージが作成されます。
ユーザー ガイド
輝度の計算
シーンの最初の明るさを先に決めておかないと、シーンのインテンシティをスケーリングできません。ここでの目標は、シーンの妥当な平均輝度を推定する計算をできる限り短い時間で実行することです。サンプリングするテクセルの数を減らすと計算は速くなりますが、テスト パターンがまばらに生じて明るい領域が欠落する危険があります。このサンプルでは、シーンをまず 1/4 x 1/4 にスケーリングし、4 x 4 テクセル ブロックの平均値を使ってダウンサンプリングします。このスケーリングされたテクスチャーは、ライティング効果用のソース テクスチャーの作成にも使用されます。カメラがシーン内部を移動するときに不自然なちらつきが発生するのを避けるため、スケーリング演算は正確でなければなりません。
シーンの平均輝度を測定し、トーン マッピングを実行するために使うプロセスは、ホワイトペーパー『Photographic Tone Reproduction for Digital Images』で説明されています。輝度の計算式をこの資料から以下に抜粋します。
後の計算で使うシーンの平均輝度は、すべてのサンプリングされたピクセルの平均対数の真数です。デルタには、純粋な黒のテクセルを扱う小さな値が含まれます。この式は、MeasureLuminance メソッドから呼び出される 4 つのピクセル シェーダー パスを使って実装されます。
平均 log() 値を 64 x 64 テクスチャーにサンプリングします。
16 x 16 にダウンスケーリングします。
4 x 4 にダウンスケーリングします。
1 x 1 にダウンスケーリングし、その結果に対して exp() 演算を実行します。
計算結果を 1 x 1 テクスチャーの内部に収めることで、平均輝度値を必要とする計算をビデオ カード上で完全に行うことができ、AGP 転送を行う必要はありません。
露光の調節
露光の調節は、HDR シーンの適切な低ダイナミック レンジ ビューを見つけるプロセスです。物理的なレンズ システムでは、システムに入ってくる光の量を制限するためにアパーチュアが調節されます。露光の調節をエミュレートするためにコンピューター グラフィックスで使われるプロセスは、トーン マッピングと呼ばれます。トーン マッピングは、HDR イメージ空間をビデオ ディスプレイに適した低ダイナミック レンジ空間にマッピングするプロセスです。露光の調節とは異なり、トーン マッピングの実行にはすべての高レンジ データを使用できます。そのため、使用する演算子によって異なりますが、昔ながらのカメラでは表現できない高い精度で明るい領域と暗い領域をイメージに同時に収めることができます。
シーンの平均輝度を計算した後で、HDR シーン テクスチャーをターゲットの平均輝度に合わせてスケーリングできます。それを行うのが次の式のアルファです。
この式は、最終的なシーンのためにターゲットの平均輝度を中心としてシーンの輝度を線形にスケーリングするだけです。ただし、結果の値は、モニターに表示できる 0.0 ~ 1.0 の低ダイナミック レンジに収まるサイズにはまだ圧縮されていません。目的の圧縮を実行するトーン マッピング演算子は、次のとおりです。
明順応
人間の視覚器官は、明るさの変化にすぐには順応しません。この反応は、トーン マッピングの計算を少し拡張するだけで簡単にシミュレートできます。ユーザーが現在順応している輝度値を、シーンの平均輝度の代わりにトーン マッピング計算式で使用します。順応している輝度値は、1 x 1 テクスチャーに格納され、フレームごとに調整されながら、測定されたシーン輝度を徐々に追跡します (次のコードを参照)。
float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * ( 1 - pow( 0.98f, 30 * g_fElapsedTime ) );
たとえば、カメラが静止している場合、順応している輝度は測定された輝度に最終的に一致するので、順応が無効なときと同じトーン マッピング結果が生成されます。しかし、明るさの度合いが違う領域に焦点を合わせるためにカメラが移動している場合、ビューアーが新しいライティングの条件に順応するまでイメージは露光過多または露光不足になりします。このサンプルで使われる順応モデルでは、人間の順応を忠実に再現することは意図されていません。人間の場合、完全な暗順応には 30 分以上かかることがあります。
輝度パス フィルター
トーン マッピングは、コード内の 2 か所で実行します。グレア テクスチャーをシーンに作成するために最終的なシェーダー パスの一部としてレンダラーで一度実行し、輝度パス フィルターの一部としてもう一度実行します。輝度パス フィルターは、最終的なシーン イメージで明るくする領域をトーン マッピングを使って決定した後で、それ以外のデータを除外します。HDR ライティング効果は、現在の露光に比例するので、それらの効果をトーン マッピングされたイメージ上で実行し、シーンの出力に直接追加することができます。この手順により、整数テクスチャーをグレアの生成に使用できます。
以下のコードに示すとおり、輝度パス フィルターは、暗い領域を除く前にシーンを目的の中間グレーのターゲット輝度にマッピングします。シーンの輝度を 0.0 ~ 1.0 の範囲に変換するトーン マッピング演算子は、直前の式から少し変更されています。輝度を 1 + 輝度で除算する代わりに、式の 1 をオフセット値で置き換えます。このオフセット値を増やすと、シーンの明るい領域と暗い領域との相対的な差も大きくなります。
// Determine what the pixel's value will be after tone mapping occursvSample.rgb *= g_fMiddleGray/(fAdaptedLum + 0.001f);// Subtract out dark pixelsvSample.rgb -= BRIGHT_PASS_THRESHOLD;// Clamp to 0vSample = max(vSample, 0.0f);// Map the resulting value into the 0 to 1 range. Higher values for// BRIGHT_PASS_OFFSET will isolate lights from illuminated scene // objects.vSample.rgb /= (BRIGHT_PASS_OFFSET+vSample);
ブルーミング効果
ブルーミングを行う前に、輝度パス フィルターが適用されたイメージは、元のシーン テクスチャーの 1/8 x 1/8 の大きさにスケーリングされ、ぼかしが加えられます。ブルーミング パスは、輝度パス フィルターが適用されスケーリングされたシーンに対する、分離可能な 2 つのパスからなる垂直方向および水平方向のガウスぼかしです。次の図に示すとおり、テクスチャーには最初に水平方向にぼかしが加えられ、次に垂直方向にぼかしが加えられてプロセスが完了します。最終的なシーン パスの一部として、ブルーミング テクスチャーはバイリニア フィルターを使ってバック バッファーのサイズにスケーリングされ、シーンの出力に直接追加されます。
星彩効果
星彩効果は、星の 1 本の線をレンダリングするために3 つのパスを必要とします。このサンプルで使う星のパターンには 8 本の線が必要なので、完全なレンダリングを行うには 24 のパスが必要です。線の本数、線の方向、色のオフセットなど、星のさまざまなタイプの特性は、GlareDef.h ファイルで定義します。次の図に示すとおり、すべての方向線をレンダリングした後で、線テクスチャーの平均テクセル値を使って最終的な星テクスチャーが合成されます。このテクスチャーがスケーリングされ、最終的なシーン イメージに直接追加されます。