HDRFormats10 サンプル
高ダイナミック レンジ (HDR) ライティング エフェクトには、0 ~ 255 以外のカラー値を処理する機能が要求され、通常これは、高レンジ カラー データをテクスチャーとして格納することによって処理されます。HDR アプリケーションには浮動小数点テクスチャー フォーマットを選ぶのが自然ですが、すべてのターゲット システムでこのフォーマットを使用できるとは限りません。このサンプルでは、さまざまなデバイスとの互換性を確保するために、高ダイナミック レンジ データを整数フォーマットにエンコードする方法を示します。
パス
ソース | SDK ルート\Samples\C++\Direct3D10\HDRFormats10 |
実行可能ファイル | SDK ルート\Samples\C++\Direct3D10\Bin\x86 または x64\HDRFormats10.exe |
サンプルの概要
高ダイナミック レンジ ライティング テクニックは、アプリケーションにリアリティを付加します。また、実装が極めて容易で、既存のレンダリング パイプラインにも緊密に統合でき、必要な処理時間もそれほどかかりません。ただし、ほとんどの HDR テクニックは浮動小数点テクスチャー フォーマットに依存するため、ターゲット システムによっては使用できない場合があります。浮動小数点テクスチャーをサポートしていないデバイスで HDR テクニックを使用できるようにするには、1 つの手段として、高レンジ浮動小数点データを整数フォーマットにエンコードし、必要に応じて即時にデコードする方法があります。このサンプルは、Direct3D 9 と Direct3D 10 のコードパスを両方ともサポートしています。以下では、Direct3D 10 のコードパスの例について説明します。
整数テクスチャーは、浮動小数点テクスチャーの代替としては完璧でないことに注意してください。整数へのエンコードには、精度を損ねる、浮動小数点ソースの範囲が一部欠落する、エンコードとデコード処理によってパフォーマンスが低下する、などの欠点があります。このエンコードとデコードはピクセル シェーダー内でシームレスに実行されるので、極端に負荷がかかることはありませんが、フレームレートが若干低下する可能性があります。スカイボックスなどの静的要素には、初期化時に 1 度だけエンコードを行って、実行時のサイクルを節約することができます。
実装
アプリケーションでは、2 つの高ダイナミック レンジ テクニックを使用します。すなわち、トーン マッピングとブルーミングです。これらのテクニックのしくみや、一般的な高ダイナミック レンジ イメージの詳細については、HDR ライティングのプログラミング ガイドを一読したうえで、DirectX ドキュメントに付属する HDRLighting サンプルと HDRCubeMap サンプルを参照してください。
このサンプルで使用するテクニックでは、HDR データをテクスチャーとして格納する能力がクリティカルです。シーンを HDR レンダー ターゲットにレンダリングすること、環境マップ テクスチャーが HDR であること、シーンの輝度の測定に使用する一時テクスチャーすべてを HDR データに格納することがそれぞれ必要となります。浮動小数点テクスチャーをサポートしているデバイスでは、最も効率のよいシンプルな実装が実現しますが、作業手順を若干追加すれば、整数テクスチャーを使用して HDR データを格納することも可能になります。このサンプルでは、3 つのエンコード スキームを実装します。
RGB16
チャンネルあたり 16 ビットの整数フォーマットを使用すると、65536 個の離散値を使用して、チャンネルごとのデータを格納できます。このエンコードは、0.0f から任意の最大値 (このサンプルでは100.0f) を範囲とする 65536 個の値の単純な線形分布です。アルファ チャンネルは使用しません。エンコードされた RGB16 カラーから浮動小数点値をデコードするには、次の式を使用します。
decoded.rgb = encoded.rgb dot max_value
RGB32
チャンネルあたり 32 ビットの整数フォーマットを使用すると、チャンネルあたり 16 ビットの整数フォーマットよりもカラー値の範囲が広くなります。チャンネルごとのデータの格納には、4294967296 個の離散値を使用できます。このエンコードは、0.0f から任意の最大値 (このサンプルでは10000f) を範囲とする 4294967296 個の値の単純な線形分布です。アルファ チャンネルは使用しません。エンコードされた RGB32 カラーから値をデコードするための式は、RGB16 カラーの式とまったく同じです。
decoded.rgb = encoded.rgb dot max_value
R9G9B9E5
このエンコードは RGB16 よりも高度で、対数分布を使用することにより、はるかに広範囲のカラー データを処理できます。各チャンネルはカラー成分の仮数を格納し、アルファ チャンネルは共有指数を格納します。柔軟性が高まる分、余分な計算負荷も加わります。エンコードされた R9G9B9E5 カラーから浮動小数点値をデコードするには、次の式を使用します。
decoded.rgb = encoded.rgb * pow( 2, encoded.a )
次の図は、使用タイミングに従って上から順にシーンをレンダリングするのに使用されるテクスチャーを示しています。青の枠線で囲まれた図には高ダイナミック レンジ データが含まれており、RGBE8 エンコードを使用して表示されています。
HDR を使用したレンダリング
シーンのレンダリング プロセスは、ネイティブの浮動小数点テクスチャー モードでも、エンコードされた整数テクスチャー モードでも、ほとんど変わりません。高ダイナミック レンジ テクスチャーを読み取るピクセル シェーダーで必要となるのは、エンコードされた整数テクスチャーを読み取る際の追加のデコード手順と、HDR データを整数テクスチャーに書き込む際の同様のエンコード手順だけです。シェーダーに一定の引数を使用することで、同じシェーダーのコンパイル方法を変えてすべてのエンコード スキームで使用することができます。次の例は、モデルをライティングするピクセル シェーダーを示しています。
//-----------------------------------------------------------------------------// Name: ScenePS// Type: Pixel Shader// Desc: Environment mapping and simplified hemispheric lighting//-----------------------------------------------------------------------------float4 ScenePS( SceneVS_Output Input, uniform bool RGB9E5, uniform bool RGB32, uniform bool RGB16 ) : SV_TARGET{ // Sample the normal map float3 bump = g_tNormal.Sample( LinearSampler, Input.Tex ); bump *= 2.0; bump -= float3(1,1,1); //move bump into world space float3 binorm = normalize( cross( Input.Normal_World, Input.Tangent_World ) ); float3x3 wtanMatrix = float3x3( binorm, Input.Tangent_World, Input.Normal_World ); bump = mul( bump, wtanMatrix ); //world space bump // Sample the environment map float3 vReflect = reflect( Input.ViewVec_World, bump ); float4 vEnvironment = g_tCube.Sample( LinearSampler, vReflect ); if( RGB9E5 ) vEnvironment.rgb = DecodeRGB9E5( vEnvironment ); else if( RGB32 ) vEnvironment.rgb = DecodeRGB32( vEnvironment ); else if( RGB16 ) vEnvironment.rgb = DecodeRGB16( vEnvironment ); // Simple overhead lighting float3 vColor = saturate( MODEL_COLOR * bump.y ); // Add in reflection vColor = lerp( vColor, vEnvironment.rgb, MODEL_REFLECTIVITY ); if( RGB9E5 ) return EncodeRGB9E5( vColor ); else if( RGB32 ) return EncodeRGB32( vColor ); else if( RGB16 ) return EncodeRGB16( vColor ); else return float4( vColor, 1.0f );}
法線マップ フォーマット
Direct3D 10 のコードパスでは、サンプルは法線マップを使ってオブジェクトをレンダリングします。選択できる法線マップ フォーマットにはさまざまなものがあります。
R8G8B8A8
ほとんどの Direct3D 9 世代のシェーダーで使用されているフォーマットは、R8G8B8A8 フォーマットです。R8G8B8A8 では、法線の x、y、z 成分が 8 ビットの R、G、B チャンネルにテクスチャーとして格納されます。これらの値はバイアスされます。つまり、チャンネルごとに、128 は値 0 を、0 は -1 を、255 は +1 を表します。
アルファ チャンネルはこのサンプルでは使用していませんが、ディスプレイスメント マッピングや Parallax マッピングなどのエフェクトの高さ情報を格納するのに使用できます。詳細については、DisplacementMapping10 サンプルを参照してください。
浮動小数点フォーマット
浮動小数点法線フォーマットを使用すると、R8G8B8A8 などの整数フォーマットよりも精度が高まります。また、浮動小数点テクスチャーには符号を付けることができるので、負の値を表すためにテクスチャーをバイアスする必要はありません。ただし、このサンプルでは、法線マップのソースがバイアス済みの R8G8B8A8 テクスチャーであるため、シェーダー内であえてアンバイアスしています。したがって、このサンプルで浮動小数点法線マップ フォーマットから得られる利点は、単に精度の点のみとなります。
圧縮フォーマット
Direct3D 10 では、法線マップを格納するための圧縮フォーマットが新たに追加されています。追加されたフォーマットは、DXGI_FORMAT_BC5_SNORM と DXGI_FORMAT_BC5_UNORM です。これらのフォーマットは 0 ~ 1 の範囲のデータを格納し、法線マップを圧縮します。前述の HDR フォーマットと異なり、シェーダーでフォーマットをデコードする必要はありません。デコードはハードウェアで既に制御されています。
BC5_UNORM テクスチャーは符号なしです。このフォーマットは 0 ~ 1 の範囲のデータを格納します。R8G8B8A8 フォーマットと同様に、負の値を表すにはシェーダーでデータをアンバイアスする必要があります。
BC5_SNORM テクスチャーは符号付きです。つまり、-1 ~ 1 の値を格納できます。この点を踏まえて法線マップを作成した場合は、負の値を表すためのアンバイアスをシェーダー内で実行する必要はありません。サンプルでは、ソースである法線マップが既にバイアスされているため、BC5_SNORM フォーマットの利点は最大限には活用されていません。