ピクセル フォグ

ピクセル フォグ

ピクセル フォグという名前は、デバイス ドライバがピクセル単位で計算することに由来する。これは頂点フォグとは異なる。頂点フォグは、トランスフォームおよびライティングの計算時にパイプラインが計算する。ピクセル フォグは、ドライバによっては、ブレンディング計算に適用するフォグ係数 (各ピクセルの深度を使用) を決定するために事前に計算された参照テーブルを使うため、テーブル フォグと呼ばれることもある。ピクセル フォグは、D3DFOGMODE 列挙型のメンバが示すフォグ公式のいずれかを使って適用する。これらの公式の実装はドライバ固有である。ドライバが複雑なフォグ公式をサポートしていない場合は、より単純な公式を使うこと。

視点からの相対深度と Z ベースの深度

深度バッファ内での z 値の不均等なばらつきによって生じる、フォグの不自然なグラフィックス効果を抑えるために、ほとんどのハードウェア デバイスでは、ピクセル フォグに z ベース深度値ではなく視点からの相対深度を使う。視点からの相対深度とは、本質的には同次座標セットからの w 要素である。Microsoft® Direct3D® は、デバイス空間座標から RHW 要素の逆数を取得して真の w を再生成する。デバイスが視点からの相対フォグをサポートしている場合、IDirect3DDevice9::GetDeviceCaps メソッドを呼び出すと、そのデバイスは D3DCAPS9 構造体の RasterCaps メンバに D3DPRASTERCAPS_WFOG フラグを設定する。リファレンス ラスタライザを除き、ソフトウェア デバイスは常に z を使ってピクセル フォグ エフェクトを計算する。

視点との相対フォグがサポートされているとき、設定された射影行列でデバイス空間の w 値に対応する、ワールド空間の z 値を生成する場合、システムは z ベース深度よりも視点からの相対深度を優先して自動的に使う。射影行列を設定するには、IDirect3DDevice9::SetTransform メソッドを呼び出し、D3DTS_PROJECTION 値を使い、目的の行列を表す D3DMATRIX 構造体を渡す。射影行列がこの要件に対応していない場合、フォグ エフェクトは正しく適用されない。対応している行列の生成の詳細については、「W バッファに有効な射影行列」を参照すること。「射影トランスフォームとは」で説明するパースペクティブ射影行列は、適切な射影行列を生成する。

Direct3D では、現在設定されている射影行列を使って w ベース深度の計算を実行する。したがって、アプリケーションで Direct3D トランスフォーム パイプラインを使わない場合であっても、目的の w ベース機能を取得するために適切な射影行列を設定しておく必要がある。

Direct3D は射影行列の第 4 列を調べる。係数が [0,0,0,1] (アフィン射影) の場合には、システムは z ベースの深度値をフォグに使う。この場合、デバイス空間の線形フォグ エフェクトの開始距離および終了距離を指定する必要もある。この範囲は、ユーザーに最も近いポイントを 0.0 とし、最も遠いポイントを 1.0 とした範囲である。

ピクセル フォグの使い方

アプリケーションでピクセル フォグを有効にするには、次の手順を実行する。

  1. D3DRS_FOGENABLE レンダリング ステートを TRUE に設定して、フォグ ブレンディングを有効にする。
  2. D3DRS_FOGCOLOR レンダリング ステートで、目的のフォグ色を設定する。
  3. D3DRS_FOGTABLEMODE レンダリング ステートを D3DFOGMODE 列挙型の対応するメンバに設定して、使用するフォグ公式を選択する。
  4. 選択したフォグ モードに必要なフォグ パラメータを、関連するレンダリング ステートに設定する。線形フォグの開始距離と終了距離、指数フォグのフォグ密度も含む。

次のサンプル コードは、これらの手順を示している。

// 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 SetupPixelFog(DWORD Color, DWORD Mode)
{
    float Start   = 0.5f;    // For linear mode
    float End     = 0.8f;
    float Density = 0.66f;   // For exponential modes
 
    // Enable fog blending.
    g_pDevice->SetRenderState(D3DRS_FOGENABLE, TRUE);
 
    // Set the fog color.
    g_pDevice->SetRenderState(D3DRS_FOGCOLOR, Color);
    
    // Set fog parameters.
    if( Mode == D3DFOG_LINEAR )
    {
        g_pDevice->SetRenderState(D3DRS_FOGTABLEMODE, Mode);
        g_pDevice->SetRenderState(D3DRS_FOGSTART, *(DWORD *)(&Start;));
        g_pDevice->SetRenderState(D3DRS_FOGEND,   *(DWORD *)(&End;));
    }
    else
    {
        g_pDevice->SetRenderState(D3DRS_FOGTABLEMODE, Mode);
        g_pDevice->SetRenderState(D3DRS_FOGDENSITY, *(DWORD *)(&Density;));
    }

IDirect3DDevice9::SetRenderState メソッドは、第 2 パラメータに DWORD 値だけを受け取るが、浮動小数点のフォグ パラメータが要求されることもある。上の例では浮動小数点の値を IDirect3DDevice9::SetRenderState に渡すために、データを平行移動するのではなく、浮動小数点変数のアドレスを DWORD ポインタにキャストして、次にそれを参照している。