纹理走样处理
前面我们已经讲了如何通过插值与透视矫正获取三角形内每个像素的 UV 坐标和属性值,进而对纹理贴图进行采样。但采样过程本身并不完美——如果处理不当,渲染结果会出现两种典型的纹理走样(Texture Aliasing)现象:
- 放大走样(Magnification):当物体离相机很近时,屏幕上的多个像素映射到纹理上的同一个像素(Texel),如果采用最近邻采样,画面会出现明显的锯齿和马赛克方块。
- 缩小走样(Minification):当物体离相机很远时,屏幕上的一个像素覆盖纹理上的一大片区域(可能包含成百上千个像素)。相机或物体稍有移动,采样点就会剧烈跳变,表现为远处物体的闪烁和摩尔纹(Moire Pattern)。
下面分别讨论这两种走样的解决方案。
放大走样(Magnification)
对于放大走样,核心思路是用插值来平滑采样结果,而不是简单取最近的那个像素。常用的方法有双线性插值(Bilinear Interpolation)和双三次插值(Bicubic Interpolation)。
双线性插值(Bilinear)
双线性插值对采样点周围的
第一步:确定四个采样点与插值系数。
设采样点映射到纹理上的 UV 坐标为
为确定采样点落在哪个像素内,将 UV 坐标减去
以
| 记法 | 坐标 | 位置 |
|---|---|---|
| 左下 | ||
| 右下 | ||
| 左上 | ||
| 右上 |
采样点在四个像素之间的偏移量,等于
为什么这样算?像素
同理
第二步:水平方向插值(4 个点 → 2 个点)。
定义线性插值函数
先在底部和顶部分别做水平插值:
第三步:垂直方向插值(2 个点 → 1 个点)。
对
将前三步展开,得到完整的双线性插值公式:
四个权重之和恒为 lerp)换来了视觉上的大幅平滑。
具体计算示例:
假设采样点映射到纹理上的 UV 坐标为
左下角像素
(直接用公式也得到相同结果:
周围四个像素的颜色值(为直观,取极限色)为:
| 记法 | 坐标 | 颜色 | RGB |
|---|---|---|---|
| 红色 | |||
| 绿色 | |||
| 蓝色 | |||
| 黄色 |
水平插值:
垂直插值:
双三次插值(Bicubic)
Bilinear 只用
代价是计算量从 3 次 lerp 增加到 16
次加权求和,且每个像素的权重需通过三次函数计算。在实时渲染中,Bicubic
的开销通常被认为过高,因此游戏引擎几乎一律使用 Bilinear(配合
MipMap)来满足性能要求,Bicubic 更多出现在离线渲染和图像处理软件中。
缩小走样(Minification)
物体距离摄像机越远,它在屏幕上的投影就越小,此时屏幕上一个像素会覆盖纹理上大范围的区域。如前所述,若直接采样,远处的纹理会严重闪烁并产生摩尔纹。
超采样能解决吗?
一个自然的想法是使用之前介绍过的超采样(Supersampling / SSAA)——对每个像素内部取多个子采样点再平均:
超采样确实有效果,但它要求每个像素执行多次纹理采样与着色计算,开销极高。有没有更高效的方法?
MipMap
解决缩小走样的根本方法,是直接求出屏幕像素所覆盖的那一大片像素的平均颜色。但如果在运行时对每个像素实时计算上百个像素的均值,性能会瞬间崩溃。
MipMap(来源于拉丁语 multum in parvo,意为”小空间里装很多东西”)采用了预计算(Pre-filtering)的策略:在资源加载阶段,将纹理逐级缩小,提前算好所有分辨率版本的图像,存入显存。
MipMap 的层级定义如下:
- Level 0:原始纹理(如
) - Level 1:
(由 Level 0 每 个像素求平均得到) - Level 2:
- …
- Level n:
选择正确的 MipMap 层级
光栅化时,GPU 会并行处理相邻的
这四个偏导数描述了”在屏幕上向右/向下移动一个像素时,纹理坐标分别变化多少”。两个偏导向量在纹理空间中张成了一个平行四边形,代表了当前屏幕像素在纹理上的近似覆盖区域。
取这两个偏导向量中较长者的模长作为覆盖区域的半径
有了
(一个像素覆盖约 1 个像素)→ (用原图) (一个像素覆盖约 4 个像素宽)→ (用 Level 2, 分辨率) → (用 Level 7)
三线性插值(Trilinear Interpolation)

直接用取整后的
三线性插值的做法是:
设
- 在 Level
上做一次双线性插值,得到颜色 - 在 Level
上做一次双线性插值,得到颜色 - 将两者在层级维度上线性混合:
“三线性”得名于:两次双线性(水平 + 垂直,共两维)再加上层级间的线性插值(第三维)。
可以看到经过三线性插值,最终渲染结果不再出现明显分界,有了过渡。
具体计算示例:
假设 GPU 计算出
(对应 的 Level 1) (对应 的 Level 2)- 混合系数
分别在 Level 1 和 Level 2 上对同一 UV 做 Bilinear 采样,得到:
最终颜色:
Trilinear 以两倍于 Bilinear 的纹理采样次数(2 次 Bilinear = 总共 8 次像素读取),彻底消除了 MipMap 层级之间的跳变,是实时渲染中质量与性能的甜点配置。配合后续的各向异性过滤(通常记作 Trilinear + Aniso),即为现代 GPU 的默认纹理采样方案。
MipMap 的存储代价与局限
根据等比数列求和:
MipMap 仅额外增加了约
但 MipMap 也有明显的局限:
远处的纹理被模糊成了一片。原因在于 MipMap
假设像素在纹理上的覆盖区域是正方形(
各向异性过滤(Anisotropic Filtering)
各向异性过滤对 MipMap 的”正方形假设”做了改进。它不仅预计算正方形的平均颜色,还预计算了不同长宽比的矩形区域(称为 Rips),在采样时根据像素覆盖区域的实际形状和方向选择匹配的矩形采样:
在光栅化时,GPU
根据偏导数的方向与大小判断覆盖区域的长宽比,沿各向异性方向做多次采样再混合。典型的设置(
各向异性过滤对掠射角表面(如 FPS
游戏中的地板、墙壁)的改善尤为明显,能够保留 MipMap
会模糊掉的远处细节。代价是额外的显存和采样带宽,但在现代 GPU 上,开启
总结
纹理走样处理是实时渲染中连接”图像质量”与”性能”的桥梁:
- 放大走样:用双线性插值(Bilinear)以极低成本平滑最近邻采样的马赛克,极端情况可升级为双三次插值(Bicubic)获取更高平滑度。
- 缩小走样:用 MipMap
预计算多级分辨率,以
的显存代价消除闪烁和摩尔纹;三线性插值(Trilinear)消除层级间的跳变线;各向异性过滤纠正掠射角下的过度模糊。 - 这几种技术的组合(Trilinear + Anisotropic)在现代 GPU 上已是出厂默认的纹理采样配置,在质量与性能之间取得了工程上的最佳平衡。
这次的插图来自画师 luoyu
图片地址:https://www.pixiv.net/artworks/116797550