3、采样器状态:寻址模式、过滤模式与LOD控制

采样器状态,说白了就是告诉GPU「怎么读纹理」的一套参数。很多开发者觉得这玩意儿简单,不就是设置几个枚举值嘛。但我见过太多项目,因为采样器配置不当,导致画面出现奇怪的接缝、闪烁,甚至性能雪崩。今天咱们就把这块彻底讲透。

3.1 寻址模式:纹理坐标超出[0,1]怎么办?

纹理坐标通常范围是0到1。但实际渲染中,坐标超出这个范围太常见了。比如做地形拼接、天空盒、或者UV动画时。GPU怎么处理这些「越界」坐标?这就是寻址模式要解决的问题。

模式 行为 典型场景
Wrap(重复) 坐标取小数部分,无限重复 地板、砖墙、重复纹理
Clamp(钳制) 超出部分取边界像素 UI、天空盒、单张贴图
Mirror(镜像) 像照镜子一样翻转重复 对称图案、角色贴图
Border(边框色) 超出部分返回固定颜色 裁剪、遮罩、调试

Wrap模式是最常用的。比如一块草地纹理,你铺100米长,UV坐标从0到100,GPU自动取小数部分,纹理就无缝重复了。但这里有个坑——如果纹理本身左右边缘颜色不一致,Wrap模式会产生明显的接缝。我曾在项目里遇到一个地形,远处看有一条条竖线,排查了半天才发现是纹理边缘没做无缝处理。

Clamp模式适合那些「只出现一次」的纹理。比如UI上的按钮,或者天空盒。坐标超出1.0时,GPU直接取最边缘的像素。嗯,这里要注意:如果纹理边缘是纯色还好,如果是渐变,Clamp会导致边缘出现一条硬边。我曾经用Clamp做水面反射,结果岸边出现了一条亮线,后来改成Mirror才解决。

Mirror模式比较有意思。它像镜子一样,0到1正常显示,1到2是镜像翻转,2到3又正常。这种模式特别适合做对称图案,比如角色的左右脸贴图。我个人习惯在做角色皮肤贴图时用Mirror,这样左右脸纹理完全对称,省去手动调整的麻烦。

Border模式用得少,但关键时刻能救命。比如做裁剪效果,或者调试时想看看哪些像素超出了纹理范围。我曾经用它来排查UV溢出问题——把Border设成亮红色,一眼就能看到哪些地方坐标越界了。

性能提示:寻址模式本身几乎不影响性能。但Wrap模式会导致纹理缓存命中率下降,因为相邻像素的纹理坐标可能跳到很远的地方。Clamp模式缓存最友好,因为相邻像素大概率访问同一块纹理数据。

3.2 过滤模式:像素与纹素之间的博弈

纹理采样时,一个屏幕像素往往对应多个纹素(缩小),或者一个纹素对应多个像素(放大)。怎么从离散的纹素中计算出连续的像素颜色?这就是过滤模式的工作。

3.2.1 点过滤(Point)

最简单粗暴。取最近的纹素颜色。速度快,但效果嘛……放大时全是马赛克,缩小时会闪烁。我建议只在像素艺术风格或者调试时用。比如你做《我的世界》风格的游戏,点过滤反而更有味道。

3.2.2 双线性过滤(Bilinear)

取周围4个纹素做加权平均。效果比点过滤好很多,放大时边缘平滑。但缩小时依然会闪烁,因为GPU只用了最近一层的Mipmap。这是大多数游戏的最低配置。我个人习惯在移动端用双线性,性能开销小,效果也能接受。

3.2.3 三线性过滤(Trilinear)

在两层Mipmap之间再做一次插值。说白了就是「双线性 + Mipmap层间插值」。效果比双线性好,缩小时不会闪烁。但开销也大了一倍。我一般在PC端默认用三线性,移动端看情况。

3.2.4 各向异性过滤(Anisotropic)

这是最高级的过滤模式。它考虑了视角方向。比如你斜着看地面,纹理在屏幕空间是拉伸的。普通过滤会模糊,各向异性过滤会沿着拉伸方向多采样几个点,保持远处纹理的清晰度。

各向异性过滤的采样数通常是2x、4x、8x、16x。数值越大,效果越好,开销也越大。我实测过,4x和8x在视觉上差异不大,但性能开销差了一倍。所以我的建议是:PC端用4x或8x,移动端用2x或者干脆关掉。

我的经验:各向异性过滤对性能的影响,其实比很多人想象的小。因为GPU硬件专门优化过。但要注意,它和Mipmap配合使用效果最好。没有Mipmap的各向异性过滤,性能会差很多。

3.3 LOD偏置与Clamp:控制纹理细节的阀门

Mipmap是纹理的「金字塔」,从大到小一层层预计算好。GPU根据像素在屏幕上的大小,自动选择用哪一层。但有时候自动选择的结果并不理想,这时候就需要LOD偏置和Clamp来干预。

3.3.1 LOD偏置(LOD Bias)

LOD偏置就是在GPU自动计算的LOD层级上,加上一个偏移量。正值让GPU用更模糊的层(更小的Mipmap),负值让GPU用更清晰的层(更大的Mipmap)。

举个例子:你做一个雪地场景,远处雪地纹理自动选了第4层Mipmap,看起来有点模糊。你希望远处也能保持一些细节,就可以把LOD偏置设为-0.5或-1.0,让GPU偏向使用更清晰的层。

但要注意,负偏置会导致远处纹理闪烁,因为Mipmap层级切换更频繁了。我曾在项目里为了追求清晰度,把LOD偏置设成-2.0,结果远处地面一直在闪,像水波纹一样。后来改成-0.5才稳定下来。

3.3.2 LOD Clamp

LOD Clamp限制了GPU能使用的Mipmap层级范围。比如你设置MinLOD=0, MaxLOD=3,那GPU最多用到第3层Mipmap,再远也不会用更模糊的层。

这个参数在两种场景下特别有用:

  • 防止过度模糊:有些纹理在远处会模糊成一团,你可以用MaxLOD限制一下,让远处至少保留一些细节。
  • 性能优化:如果你知道某些纹理永远不会被近看,可以设置MinLOD=2,跳过最大的几层Mipmap,节省显存和带宽。

避坑指南:我曾经在一个VR项目里,为了节省显存,把所有纹理的MaxLOD都设成了4。结果用户转头时,远处的纹理突然变清晰,产生了明显的「弹入」效果,非常出戏。后来我根据纹理的重要程度,分别设置不同的Clamp值,才解决了这个问题。

3.4 实战建议:采样器配置的黄金法则

说了这么多,总结几条我自己的经验法则:

  1. 寻址模式:默认用Wrap,UI和天空盒用Clamp,对称贴图用Mirror,调试用Border。
  2. 过滤模式:移动端用Bilinear,PC端用Trilinear,需要远处清晰度时开Anisotropic 4x。
  3. LOD偏置:默认0,需要更清晰时设-0.5,不要超过-1.0。
  4. LOD Clamp:不限制时性能最好,但显存占用大。根据纹理使用频率,适当设置MaxLOD。

最后说一句:采样器状态不是设一次就完事的。不同纹理、不同场景、不同平台,最优配置都不一样。我建议你在项目初期就建立一个采样器配置表,针对每种纹理类型(漫反射、法线、遮罩等)分别设置。这样后期调优时,改一个参数就能全局生效,省心很多。