DepthOfField サンプル

このサンプルは、フィールドの深度エフェクトを作成するためのテクニックを示しています。ここでは、カメラから指定された距離にあるオブジェクトのみフォーカスされます。その他の距離にあるオブジェクトはフォーカスされません。フォーカス外のオブジェクトをレンダリングすると、シーンにリアリティが加わります。この方法は、ほとんどのハードウェアで最も合理的な方法となっています。また、フィールドの深度のポスト プロセッシングは、画像ベースのモーション ブラーや高ダイナミック レンジ (HDR) ライティングなどのその他のポスト プロセッシング テクニックと簡単に組み合わせることができます。

Ee416592.DOF(ja-jp,VS.85).jpg

Path

ソース SDK ルート\Samples\C++\Direct3D\DepthOfField
実行可能ファイル SDK ルート\Samples\C++\Direct3D\Bin\x86 または x64\DepthOfField.exe

背景

CMyD3DApplication::InitDeviceObjects では、D3DXLoadMeshFromX でジオメトリを読み込みます。存在しない場合は D3DXComputeNormals を呼び出してメッシュ法線を作成します。次に、ID3DXMesh::OptimizeInplace を呼び出し、頂点キャッシュのメッシュを最適化します。その後、D3DXCreateTextureFromFile を使用して、テクスチャーを読み込みます。

CMyD3DApplication::RestoreDeviceObjects は次を実行します。

  • カメラ クラスをセットアップします。カメラ クラスは、マウスやキーボード入力の処理をカプセル化し、それぞれのビュー行列を更新します。

  • D3DXCreateTexture を呼び出し、バック バッファーと同じ高さと幅で D3DUSAGE_RENDERTARGET A8R8G8B8 テクスチャーを作成します。これに失敗した場合は、D3DUSAGE_RENDERTARGET フラグなしでもう一度試します。

  • D3DXCreateRenderToSurface を使用して ID3DXRenderToSurface を作成し、レンダー ターゲットをサポートしていないカードのテクスチャーのレンダリングに利用します。

  • D3DX エフェクト ファイルを ID3DXEffectxxx に読み込み、D3DXHANDLE をすべてのフレームに設定するすべてのパラメーターにキャッシュします。

  • ID3DXBaseEffect::SetVector および ID3DXBaseEffect::SetTexture を使用して、マテリアル プロパティやレンダー ターゲット テクスチャーなどのすべてのフレームを変更しないエフェクト パラメーターを初期化します。

  • 現在のデバイスのエフェクトで、最初の有効なテクニックを探します。

  • ポストプロセッシング パスで使用される 4 つの頂点 (クワッド) を作成します。クワッドには、テクスチャー座標のセットが 6 つ定義されます。テクスチャー座標の各セットは少し位置がシフトされることから、これらがポストプロセッシングで使用される場合、ピクセル シェーダー エフェクトにはぼかしが発生します。テクスチャー座標のセット全体は、すべてのテクニックで使用されることはありません。このクワッドの使用方法については、次で詳しく説明します。

  • ピクセル空間 (ここでは 1.0 が 1 ピクセル) からエフェクトのカーネルである TwelveKernelBase をテクスチャー座標空間にスケーリングし、その結果を TwelveKernel というラベルが付けられた個別の配列に格納します。

CMyD3DApplication::FrameMove では、カメラ クラスで FrameMove() を呼び出し、それまでのユーザー入力に応じてビュー行列を動かします。

CMyD3DApplication::Render は、基本的に次の 2 つのことを実行します。

  1. 最初にシーンをレンダー ターゲットにレンダリングします。この時、同時にブラー係数が計算され、これがレンダー ターゲットのアルファ チャンネルに格納されます。アルファ値が 0 である場合、これは、特定のピクセルが不鮮明ではないことを示します。アルファ値が 1 の場合は、特定のピクセルが不鮮明なことを示します。

  2. 次に、このレンダー ターゲットとアルファ チャンネルに格納された深度情報を使用して、全画面クワッドをレンダリングし、最終的なサーフェスで各ピクセルのピクセル シェーダーを実行します。

さらに詳しく説明すると、CMyD3DApplication::Render の最初の部分では、WorldVertexShader と呼ばれる vs_1_1 頂点シェーダーを使用する WorldWithBlurFactor テクニックを使用します。この頂点シェーダーは画面空間で頂点の位置を変更し、単独の N ドット L ライティング方程式を実行し、テクスチャー座標をコピーし、深度をベースにブラー係数を計算します。ブラー係数は、次の式で計算されます。

fBlurFactor = dot(float4(vViewPosition, 1.0), vFocalPlane)*fHyperfocalDistance;Output.Diffuse.a = fBlurFactor*fBlurFactor;

この式では、あるポイントから平面までの距離を計算し、いくつかの係数によって結果がスケーリングされます。過焦点距離は、鮮明な像が得られる最も近い距離を示す係数です。ブラー係数は 2 乗され、0.75f が上限とされます。そのため、中心ピクセルは常にぼんやりとした画像となり、それによって不自然な効果が抑えられています。

WorldWithBlurFactor テクニックは、ディフューズ頂点カラーとメッシュのテクスチャー カラーを調節する WorldPixelShader を呼び出す ps_1_1 ピクセル シェーダーを使います。これによって、必要な場合にテクスチャーのブレンディングを実行できます。

CMyD3DApplication::Render の 2 番目の部分では、実際にブラーが発生します。5 つのテクニックの 1 つを使用して、基本的に異なる 2 つのピクセル シェーダー ブラー テクニックを示します。

UsePS20ThirteenLookups テクニックおよび UsePS20SevenLookups テクニックは、どちらも DepthOfFieldManySamples を呼び出す ps_2_0 ピクセル シェーダーを使用します。ただし、これは異なるパラメーターを使用してコンパイルされます。ピクセル シェーダーは非常に単純です。サンプルの固定数の場合、これは値の配列を使用して TwelveKernel を呼び出します。オリジナルの UV テクスチャー座標をオフセットするには、上記のレンダー ターゲットで作成されたテクスチャーで、tex2D() とこの新しい UV を呼び出します。カーネルは、2 つの六角形で定義されています。1 つは単独のピクセル出力で、他の 2 つのピクセル出力には最適なブラーを取得するためにポイント間に「等しく」スペースが置かれています。各サンプルでは、次の式で色の累積和を求めます。

		Blurred += lerp(Original.rgb, Current.rgb, saturate(Original.a*Current.a)); 

すべてのサンプルが取得されたら、サンプル数で除算されたこのカラーが返されます。

もう一方の、UsePS20SixTexcoords テクニック、UsePS11FourTexcoordsNoRings テクニック、および UsePS11FourTexcoordsWithRings テクニックはどれも同じです。上記とは異なり、テクスチャー座標をオフセットするカーネルは使用せず、代わりに事前計算されたテクスチャー座標の個別セットを使用します。これらのテクスチャー座標は、CMyD3DApplication::SetupQuad を呼び出すアプリケーション関数で作成され、各セットは上記の DepthOfFieldManySamples で実行されるのとまったく同じ方法で使用される場合に、ブラーを作成するためにオフセットされます。この方法の利点は、ps_1_1 ハードウェアで実行できることです。

UsePS11FourTexcoordsNoRings と UsePS11FourTexcoordsWithRings の違いは、UsePS11FourTexcoordsWithRings が中心ピクセルの RGB と中心ピクセルのアルファ値 (ブラー係数) をベースにした 3 つのジッター ピクセルの RGB の間で線形補間することです。中心ピクセルが不鮮明なときに、いずれかのジッター ピクセルが不鮮明でない場合は、ジッター ピクセルの平均が正しく計算されません。ただし、UsePS11FourTexcoordsNoRings は中心ピクセルのアルファにジッター ピクセルのアルファを乗じた値を基準にして、中心ピクセルの RGB と 3 つのジッター ピクセルの RGB との間を線形に補間します。0 はブラーが発生しないことを意味します。これは、ジッター ピクセルの 1 つが不鮮明でなくても、中心ピクセルが不鮮明な場合は 0 になります。* 1 = 0 の場合、不自然な効果がない結果となるので、ジッター ピクセルは平均が計算されません。

たとえば、次のようにオリジナルの不鮮明ではないシーンがあるとします。

Ee416592.DOF_original(ja-jp,VS.85).jpg

I を押すことで、サンプルはシーンのブラー係数を表示します。白はピクセルが不鮮明ではないこと (アルファ =0.0f) を示し、黒はピクセルが不鮮明なこと (アルファ=1.0f) を示します。

Ee416592.DOF_blurfactor(ja-jp,VS.85).jpg

ここでは、最終シーンは次のようになります。

Ee416592.DOF_blurred(ja-jp,VS.85).jpg