像素雾 (Direct3D 9)

像素雾从设备驱动程序中按像素计算的事实中获取其名称。 这不同于顶点雾,在转换和照明计算过程中由管道计算。 像素雾有时称为表雾,因为某些驱动程序使用预先计算的查找表来确定雾因子,使用每个像素的深度来应用混合计算。 可以使用由 D3DFOGMODE 枚举类型的成员标识的任何雾公式应用它。 这些公式的实现特定于驱动程序。 如果驱动程序不支持复杂的雾公式,它应降级为不太复杂的公式。

Eye-Relative 与基于 Z 的深度

为了缓解深度缓冲区中 z 值分布不均匀导致的与雾相关的图形项目,大多数硬件设备使用相对于眼睛的深度而不是基于 z 的像素雾深度值。 眼睛相对深度本质上是同质坐标集中的 w 元素。 Microsoft Direct3D 从设备空间坐标集中获取 RHW 元素的倒数,以重现 true w。 如果设备支持眼睛相对雾,则调用 IDirect3DDevice9::GetDeviceCaps 方法时,它会在 D3DCAPS9 结构的 RasterCaps 成员中设置 D3DPRASTERCAPS_WFOG 标志。 除了参考光栅器之外,软件设备始终使用 z 来计算像素雾效果。

当支持眼睛相对雾时,如果提供的投影矩阵在与设备空间中的 w 值等效,则系统会自动使用眼睛相对深度,而不是基于 z 的深度。 通过使用D3DTS_PROJECTION值并传递表示所需矩阵的 D3DMATRIX 结构,调用 IDirect3DDevice9::SetTransform 方法来设置投影矩阵。 如果投影矩阵不符合此要求,则雾效果未正确应用。 有关生成合规矩阵的详细信息,请参阅 投影转换(Direct3D 9)

Direct3D 在其基于 w 的深度计算中使用当前设置的投影矩阵。 因此,应用程序必须设置合规的投影矩阵才能接收所需的基于 w 的功能,即使它不使用 Direct3D 转换管道也是如此。

Direct3D 检查投影矩阵的第四列。 如果系数为 [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 方法仅接受第二个参数中的 DWORD 值,但某些雾参数是必需的浮点值。 前面的示例提供了浮点值,用于 IDirect3DDevice9::SetRenderState 而不转换数据,方法是将浮点变量的地址强制转换为 DWORD 指针,然后取消引用它们。

雾类型