頂点フォグ (Direct3D 9)
システムは頂点フォグを実行するとき、ポリゴンの各頂点にフォグ計算を適用し、次に、ラスタライズの際、ポリゴンの面に結果を補間します。頂点フォグのエフェクトは、Direct3D ライティングおよびトランスフォーム エンジンによって計算されます。詳細については、「フォグ パラメーター (Direct3D 9)」を参照してください。
アプリケーションで Direct3D を使わずにトランスフォームおよびライティングを実行する場合は、アプリケーションでフォグ計算を行う必要があります。この場合、計算されたフォグ係数を、各頂点のスペキュラ色のアルファ成分に置きます。公式には、範囲ベースの公式、体積を利用する公式など、どのようなものでも使用できます。Direct3D は与えられたフォグ係数を使って、各ポリゴンの面を補間します。アプリケーションで独自のトランスフォームおよびライティングを実行する場合は、独自の頂点フォグの計算を実行する必要があります。したがって、そのようなアプリケーションでは、「フォグ ブレンディング (Direct3D 9)」および「フォグ カラー (Direct3D 9)」で説明するように、フォグ ブレンディングを有効にして、関連するレンダリング ステートによってフォグ カラーを設定するだけですみます。
注 頂点シェーダーを使う場合は、頂点フォグを使う必要があります。そのためには、頂点シェーダーを使って、頂点ごとのフォグ強度を oFog レジスタに書き込みます。ピクセル シェーダーの処理が完了した後、oFog データを使ってフォグ カラーによる線形補間が行われます。この強度はピクセル シェーダーでは利用できません。
範囲ベースのフォグ
注 Direct3D では、Direct3D のトランスフォームおよびライティング エンジンで頂点フォグを使うときのみ、範囲ベースのフォグの計算を実行します。これは、ピクセル フォグはデバイス ドライバーに実装され、現在のところ、ピクセル単位の範囲ベースのフォグをサポートするハードウェアは存在しないためです。アプリケーションで独自のトランスフォームおよびライティングを実行する場合は、範囲ベースの計算かその他の計算による独自のフォグ計算を行う必要があります。
フォグを使うと、オブジェクトがフォグ カラーと直感的でない方法でブレンドされる不自然なグラフィックス効果が生じることがあります。たとえば、2 つのオブジェクトが見えていて、一方はフォグの影響を受けるくらいに遠くにあり、他方は影響されないくらいに近くにあるというシーンを想像してください。表示領域が同じ場所で回転した場合、オブジェクトが静止していたとしても、現れるフォグ エフェクトは変化することがあります。次の図は、このような状況を上から見たところです。
範囲ベースのフォグは、フォグ エフェクトをより正確に決定する方法です。範囲ベースのフォグでは、Direct3D は視点から頂点までの実際の距離をフォグの計算に使います。シーンの範囲内での頂点の深度ではなく 2 点間の距離の増加に従ってフォグのエフェクトが増加されるため、不自然な回転効果が回避されます。
現在のデバイスが範囲ベースのフォグをサポートしている場合、IDirect3DDevice9::GetDeviceCaps メソッドを呼び出したときに、デバイスは D3DCAPS9 の RasterCaps メンバーに D3DPRASTERCAPS_FOGRANGE 値を設定します。範囲ベースのフォグを有効にするには、D3DRS_RANGEFOGENABLE レンダリング ステートを TRUE に設定します。
範囲ベースのフォグは、Direct3D により、トランスフォームおよびライティングの間に計算されます。Direct3D トランスフォームおよびライティング エンジンを使わないアプリケーションは、独自に頂点フォグの計算も行わなければなりません。この場合、範囲ベースのフォグ係数を、各頂点のスペキュラ成分のアルファ成分に設定します。
頂点フォグの使い方
アプリケーションで頂点フォグを有効にするには、次の手順を実行します。
- D3DRS_FOGENABLE を TRUE に設定にして、フォグ ブレンディングを有効にします。
- D3DRS_FOGCOLOR レンダリング ステートで、フォグ カラーを設定します。
- D3DRS_FOGVERTEXMODE レンダリング ステートを D3DFOGMODE 列挙型のメンバーに設定して、目的のフォグ公式を選択します。
- 選択したフォグ公式で必要なフォグ パラメーターをレンダリング ステートに設定します。
次の C++ コード例は、これらの手順を示したものです。
// For brevity, error values in this example are not checked
// after each call. A real-world application should check
// these values appropriately.
//
// For the purposes of this example, g_pDevice is a valid
// pointer to an IDirect3DDevice9 interface.
void SetupVertexFog(DWORD Color, DWORD Mode, BOOL UseRange, FLOAT Density)
{
float Start = 0.5f, // Linear fog distances
End = 0.8f;
// Enable fog blending.
g_pDevice->SetRenderState(D3DRS_FOGENABLE, TRUE);
// Set the fog color.
g_pDevice->SetRenderState(D3DRS_FOGCOLOR, Color);
// Set fog parameters.
if(D3DFOG_LINEAR == Mode)
{
g_pDevice->SetRenderState(D3DRS_FOGVERTEXMODE, Mode);
g_pDevice->SetRenderState(D3DRS_FOGSTART, *(DWORD *)(&Start));
g_pDevice->SetRenderState(D3DRS_FOGEND, *(DWORD *)(&End));
}
else
{
g_pDevice->SetRenderState(D3DRS_FOGVERTEXMODE, Mode);
g_pDevice->SetRenderState(D3DRS_FOGDENSITY, *(DWORD *)(&Density));
}
// Enable range-based fog if desired (only supported for
// vertex fog). For this example, it is assumed that UseRange
// is set to a nonzero value only if the driver exposes the
// D3DPRASTERCAPS_FOGRANGE capability.
// Note: This is slightly more performance intensive
// than non-range-based fog.
if(UseRange)
g_pDevice->SetRenderState(D3DRS_RANGEFOGENABLE, TRUE);
}
IDirect3DDevice9::SetRenderState メソッドは、第 2 パラメーターに DWORD 値だけを受け取りますが、浮動小数点のフォグ パラメーターが要求されることもあります。この例では、浮動小数点の値をデータの平行移動なしでメソッドに渡すために、浮動小数点変数のアドレスを DWORD ポインターとしてキャストし、次にそれを参照から解除しています。