Nearest-Point 采样 (Direct3D 9)

应用程序无需不使用纹理筛选。 可以将 Direct3D 设为使其计算纹素地址(通常不计算为整数),并使用最接近的整数地址复制纹素的颜色。 此过程称作最近点采样。 如果纹理的大小与屏幕上基元图像的大小相似,则可以快速高效地处理纹理。 如果不是,则必须放大或缩小纹理。 结果可以是块图像、别名图像或模糊图像。

C++ 应用程序可以通过调用 IDirect3DDevice9::SetSamplerState 方法选择最近的点采样。 将第一个参数的值设置为要为其选择纹理筛选方法的纹理 (0-7) 整数索引号。 为第二个参数传递D3DSAMP_MAGFILTER、D3DSAMP_MINFILTER或D3DSAMP_MIPFILTER,以设置放大、缩小或 mipmapping 筛选器。 在第三个参数中传递D3DTEXF_POINT。

应谨慎使用最近点采样,因为当纹理在两个纹素之间的边界处采样时,它有时可能会导致图形伪像。 该边界是沿着纹理(u 或 v)的位置,在该位置处,采样的纹素从一个纹素过渡到下一个。 当使用点采样时,系统选择一个样本纹素或另一个,当跨越边界时,结果可能从一个纹素突然变更为下一个。 此效果可能在所显示的纹理中作为不期望的图形伪像出现。 当使用线性筛选时,从纹理索引移动并通过边界时,通过两个相邻纹素及它们之间的平滑混合计算出最终的纹素。

当将极小的纹理映射到极大的多边形时,可以看到这种效果:一种通常称作放大的操作。 例如,当使用看起来像棋盘的纹理时,最近点取样会导致较大的棋盘显示清晰的边缘。 相比之下,线性纹理筛选会产生棋盘颜色在多边形之间平滑过渡的图像。

在大多数情况下,应用程序通过尽可能避免最近点取样来获得最佳结果。 当今的大多数硬件都针对线性筛选做了优化,因此,应用程序的性能应该不会受到影响。 如果你想要的效果绝对需要使用最近点取样(例如,当使用纹理来显示可读文本字符时),你的应用程序应极度小心,以免在纹素边界处采样,这可能会导致负面影响。 下图显示了一些伪像示例。

一个包含六个格子的盒子的图示,盒子右上角处的两个格子出现了不连续的水平线

请注意,组右上角的两个正方形看起来与其相邻方块不同,对角线偏移量穿过它们。 要避免产生此类图形伪像,你必须熟悉用于最近点筛选的 Direct3D 纹理采样规则。 Direct3D 将范围为 [0.0, 1.0](0.0 到 1.0,包括端值)的浮点纹理坐标映射到范围为 [ - 0.5, n - 0.5] 的整数纹素空间值,其中 n 是纹理上给定维度的纹素数量。 生成的纹理索引四舍五入到最接近的整数。 此映射可能会导致在纹素边界处的采样不准确。

例如,假设有一个应用程序使用D3DTADDRESS_WRAP纹理寻址模式呈现多边形。 使用 Direct3D 采用的映射时,宽度为 4 个纹素的纹理的 u 纹理索引映射如下图所示。

位于纹素之间边界处的纹理坐标 0.0 和 1.0 的示意图

请注意,此图的纹理坐标(0.0 和 1.0)正好位于纹素之间的边界处。 使用 Direct3D 映射值的方法,纹理坐标的范围为 [ - 0.5, 4 - 0.5],其中 4 是纹理的宽度。 对于这种情况,采样的纹素是纹理索引为 1.0 的 0 号纹素。 但是,如果纹理坐标只略小于 1.0,则采样的纹素将是 n 号纹素而不是 0 号纹素。

这意味着,在屏幕空间对齐的三角形上进行最近点取样以使用精确的 0.0 和 1.0 纹理坐标来放大小纹理时,会使得在纹素之间的边界处对纹理映射的像素进行采样。 在纹理坐标的计算中,任何微小的误差都会导致沿着渲染图像中对应于纹理贴图中纹素边缘的区域内出现伪像。

以完美的精度执行这种浮点纹理坐标到整数纹素的映射非常困难、耗费大量计算时间并且通常不是必要的。 大多数硬件实现使用迭代方法计算三角形内每个像素位置处的纹理坐标。 迭代方法倾向于隐藏这些误差,因为误差会在迭代期间均匀地累积。

Direct3D 参考光栅器使用直接赋值方法来计算每个像素位置处的纹理索引。 直接赋值与迭代方法的不同之处在于:操作中的任何误差表现为更随机的误差分布。 其结果是,在边界处发生的采样误差会更加明显,因为参考光栅器不以完美的精度执行该操作。

最好的方法是只在必要时使用最近点筛选。 在必须使用它时,建议你从边界位置稍微偏移纹理坐标,以免产生伪像。

纹理筛选