使用 Mipmap 的纹理筛选 (Direct3D 9)

mipmap 是一种纹理序列,每个纹理都以逐步降低的分辨率表示同一图像。 mipmap 中每个图像(或级别)的高度和宽度比上一个级别小 2 次。 Mipmap 不需要为正方形。

高分辨率 mipmap 图像用来指示靠近用户的物体。 低分辨率图像用来指示看起来离得很远的物体。 Mip 映射可改善所呈现的纹理的质量,但会占用更多内存。

Direct3D 以附加表面链的形式呈现 mipmap。 分辨率最高的纹理位于链的最前面,并且将下一级的 mipmap 作为附件。 反过来,这一级又以下一级的 mipmap 作为附件,依此类推,直到分辨率最低的 mipmap 为止。

以下图示以这些层级为例。 位图纹理表示 3D 第一人称视角游戏中一个容器上的标志。 当创建为 mipmap 时,像素最高的纹理排在集合的第一位。 在 mipmap 集中,随后的每个纹理的高度和宽度都小二次方。 在此情况下,分辨率最高的 mipmap 的像素为 256x256。 下一个纹理的像素为 128x128。 链中最后一个纹理的像素为 64x64。

此标志与可见位置的距离最大。 如果用户开始离标志很远,则游戏将显示 mipmap 链中最小的纹理,在此情况下,纹理的像素为 64x64。

图示为纹理像素为 64x64 的危险标志

当用户的视点更接近标志时,游戏会使用 mipmap 链中分辨率逐渐提高的纹理。 下图中,像素分辨率为 128x128。

图示为纹理像素为 128x128 的危险标志

当用户视点在离标志的最小允许距离时,游戏使用分辨率最高的纹理,如下图所示。

图示为纹理像素为 256x256 的危险标志

使用这种方法模拟纹理的角度更为有效。 通过这种方法能更快地利用多个不同分辨率的纹理,而不是以多种分辨率呈现单个纹理。

Direct3D 可评估 mipmap 集中的哪个纹理的分辨率与所需的输出最为接近,而且可将像素映射到相应的纹素空间。 如果最终图像的分辨率介于 mipmap 集中的纹理的分辨率之间,则 Direct3D 可以检查两个 mipmap 中的纹素并混合它们的颜色值。

要使用 mipmap,应用程序必须构建一组 mipmap。 应用程序通过将 mipmap 集选作当前纹理集中的第一个纹理的方式应用 mipmap。 有关详细信息,请参阅 纹理混合 (Direct3D 9)

接下来,应用程序必须设置 Direct3D 用于纹理采样的筛选方法。 最快速的 mipmap 筛选方法是让 Direct3D 选择最近的纹素。 在选择时,可以使用 D3DTEXF_POINT 枚举值。 如果应用程序使用 D3DTEXF_LINEAR 枚举值,则 Direct3D 的筛选效果更佳。 选择最接近的 mipmap,然后计算当前像素映射到的纹理周围的纹素的加权平均值。

Mipmap 纹理应用于 3D 场景中,可缩短呈现场景所需的时间。 Mipmap 纹理还可以增强场景的真实性, 但通常需要占用大量的内存。

创建一组 Mipmap

以下示例演示应用程序如何调用 IDirect3DDevice9::CreateTexture 方法以构建五个 mipmap 级别的链:256x256、128x128、64x64、32x32 和 16x16。

// This code example assumes that m_d3dDevice is a
// valid pointer to a IDirect3DDevice9 interface

IDirect3DTexture9 * pMipMap;
m_pD3DDevice->CreateTexture(256, 256, 5, 0, D3DFMT_R8G8B8, 
    D3DPOOL_MANAGED, &pMipMap);

IDirect3DDevice9::CreateTexture 接受的前两个参数是顶级纹理的大小和宽度。 第三个参数指定纹理中的级别数。 如果将此值设置为零,Direct3D 将创建一个图面链,每个图面的功率比前一个小 2 次,最小大小为 1x1。 第四个参数指定此资源的用法;在本例中,指定 0 表示没有资源的特定使用情况。 第五个参数指定纹理的图面格式。 对此参数使用 D3DFORMAT 枚举类型中的值。 第六个参数指定 D3DPOOL 枚举类型的成员,该成员指示要在其中放置所创建资源的内存类。 除非使用动态纹理,否则建议D3DPOOL_MANAGED。 最后一个参数采用指向 IDirect3DTexture9 接口的指针的地址。

注意

mipmap 链中的每个图面的尺寸是链中上一个图面的一半。 如果顶层 mipmap 的尺寸为 256x128,则第二层 mipmap 的尺寸为 128x64,第三层 mipmap 的尺寸为 64x32,依此类推,最低层 mipmap 的尺寸为 1x1。 链中任何 mipmap 的宽度或高度不得小于 1,因此你可以请求的 mipmap 层级在数量上存在限制。 以 4x2 顶层 mipmap 表面为例,允许的最大值为 3 层。 也就是,顶层 mipmap 的尺寸为 4x2,第二层 mipmap 的尺寸为 2x1,第三层 mipmap 的尺寸为 1x1。 如果值大于 3,会使第二层 mipmap 的高度变为小数值,因此这是不允许的。

 

选择并显示 Mipmap

调用 IDirect3DDevice9::SetTexture 方法,将 mipmap 纹理集设置为当前纹理列表中的第一个纹理。 有关详细信息,请参阅 纹理混合 (Direct3D 9)

应用程序选择 mipmap 纹理集后,必须将 D3DTEXTUREFILTERTYPE 枚举类型中的值分配给D3DSAMP_MIPFILTER采样器状态。 然后,Direct3D 会自动执行 mipmap 纹理筛选。 以下代码示例演示了如何启用 mipmap 纹理筛选。

m_pD3DDevice->SetTexture(0, pMipMap);
m_pD3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

应用程序还可以通过使用 IDirect3DTexture9::GetSurfaceLevel 方法并指定要检索的 mipmap 级别来手动遍历 mipmap 图面链。 以下示例从最高到最低分辨率遍历 mipmap 链。

IDirect3DSurface9 * pSurfaceLevel;
for (int iLevel = 0; iLevel < pMipMap->GetLevelCount(); iLevel++)
{
    pMipMap->GetSurfaceLevel(iLevel, &pSurfaceLevel);
    // Process this level
    pSurfaceLevel->Release();
}

应用程序需要手动遍历 mipmap 链,以便将位图数据加载到链中的每个图面中。 这通常是遍历链的唯一原因。 应用程序可以通过调用 IDirect3DBaseTexture9::GetLevelCount 来检索 mipmap 中的级别数。

纹理筛选