顶点雾 (Direct3D 9)

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

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

注意

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

 

Range-Based 雾

注意

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

 

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

两个视点的关系图,以及它们如何影响两个对象的雾

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

如果当前设备支持基于范围的雾,则调用 IDirect3DDevice9::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 指针,然后取消引用这些方法,从而成功地将这些方法提供浮点值,而无需进行数据转换。

雾类型