顶点雾 (Direct3D 9)

当系统执行顶点雾化时,它会在多边形中的每个顶点处应用迷雾计算,然后在光栅化期间将结果内插到多边形的面上。 顶点雾效果由 Direct3D 照明和转换引擎计算。 有关详细信息,请参阅 Fog Parameters (Direct3D 9)

如果应用程序不使用 Direct3D 进行转换和照明,则应用程序必须执行雾计算。 在这种情况下,将每个顶点的反射颜色的 alpha 分量中计算的雾因子放置。 你可以随意使用所需的任何公式 - 基于范围、体积或其他公式。 Direct3D 使用提供的雾因子在每个多边形的面上内插。 执行自己的转换和照明的应用程序还必须执行自己的顶点雾计算。 因此,此类应用程序只需启用雾混合并通过关联的呈现状态设置雾色,如 “雾混合 (Direct3D 9) 雾色 (Direct3D 9) 中所述。

注意

使用顶点着色器时,必须使用顶点雾。 这是通过使用顶点着色器将每个顶点雾强度写入 oFog 寄存器来实现的。 像素着色器完成后,oFog 数据用于与雾色进行线性内插。 此强度在像素着色器中不可用。

 

Range-Based雾

注意

Direct3D 仅在将顶点雾与 Direct3D 转换和照明引擎配合使用时,才使用基于范围的雾计算。 这是因为像素雾是在设备驱动程序中实现的,目前不存在支持基于每个像素范围的雾的硬件。 如果应用程序执行自己的转换和照明,它必须执行自己的雾计算,基于范围或其他。

 

有时,使用雾可能会引入图形伪像,导致对象以非直观方式与雾色混合。 例如,假设场景中有两个可见对象:一个距离足够远,可受雾影响,另一个距离足够近,不受影响。 如果观看区域就地旋转,则明显的雾效果可能会改变,即使对象是静止的。 下图显示了这种情况的自上而下视图。

两个视点及其如何影响两个对象的雾的示意图

基于范围的雾是确定雾效果的另一种更准确的方法。 在基于范围的雾中,Direct3D 使用从视点到顶点的实际距离进行雾计算。 Direct3D 会随着两点之间的距离的增加而增加雾的效果,而不是场景中顶点的深度,从而避免旋转伪像。

如果当前设备支持基于范围的雾,则调用 IDirect3DDDevice9::GetDeviceCaps 方法时,它将在 D3DCAPS9 的 RasterCaps 成员中设置D3DPRASTERCAPS_FOGRANGE值。 若要启用基于范围的雾,请将D3DRS_RANGEFOGENABLE呈现状态设置为 TRUE

基于范围的雾在转换和照明期间由 Direct3D 计算。 不使用 Direct3D 转换和照明引擎的应用程序还必须执行自己的顶点雾计算。 在这种情况下,在每个顶点的反射分量 alpha 分量中提供基于范围的雾因子。

使用顶点雾

使用以下步骤在应用程序中启用顶点雾。

  1. 通过将D3DRS_FOGENABLE设置为 TRUE 来启用雾混合。
  2. 将雾色设置为D3DRS_FOGCOLOR呈现状态。
  3. 通过将D3DRS_FOGVERTEXMODE呈现状态设置为 D3DFOGMODE 枚举类型的成员,选择所需的雾公式。
  4. 在呈现状态下,根据需要为所选迷雾公式设置迷雾参数。

以下示例使用 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 方法仅接受第二个参数中的 DWORD 值。 此示例通过将浮点变量的地址强制转换为 DWORD 指针,然后取消引用,成功为这些方法提供浮点值,而无需进行数据转换。

雾类型