看到URP项目里地表远景那圈一圈的环形波纹,或者铁丝网材质在镜头旋转时像水波一样滚动闪烁,基本就能确定是摩尔纹了。这在Unity URP项目中尤其常见,而且比内置管线时代更容易翻车。这篇文章把我在URP项目里处理摩尔纹的完整思路整理出来,覆盖表现分类、管线原因、贴图源头控制、Shader层频域钳制、屏幕空间兜底五个维度。适合正在被远景贴图闪烁、植被虫洞、栅栏波纹折磨的环境美术与图形程序员参考,方案按成本从低到高排列,可以直接对着落地。
1. 摩尔纹在URP项目里的四种高频现场
先说清楚敌人长什么样。摩尔纹本质是画面里的高频重复图案和屏幕采样频率打架,在URP项目里最常见的有四类,每一类的处理思路都不一样,所以要分清楚场景再对症下药。
1.1 地形与平铺贴图的环形波纹
这是最经典的一类。大范围草地在摄像机拉高后,地表出现一圈圈向外扩散的圆环状波纹,摄像机移动时波纹像水面涟漪一样滚动。原因是草地贴图的重复频率在远景处和屏幕像素采样率接近,两个周期信号互相干涉,产生了肉眼可见的差频图案。
这类摩尔纹有个明显的特征:视角越低越严重。斜着看地面的时候,地面在屏幕上的水平方向被压缩得很厉害,而竖直方向保持比例,导致屏幕上相邻像素覆盖的地面UV跨度差异极大,差频信号就越发明显。
1.2 规则几何结构的波浪状色带
铁丝网、栅栏、百叶窗、雨棚这类规则重复的几何结构在远景会出现波浪形的色带漂移。这个不一定是贴图问题,也可能是几何本身的重复频率和屏幕采样率冲突。
处理几何类摩尔纹和贴图类完全不同,不能靠调纹理参数解决。常见做法是远景处切换到更低多边形的LOD变体,或者在材质里让网格在远距离时做透明度渐隐,破坏规则的轮廓线。我见过不少项目在这个问题上死磕贴图参数,折腾半天毫无效果,先判断来源再动手很重要。
1.3 植被与Alpha Test边缘的虫洞闪烁
树冠、草丛、头发这类用Alpha Test硬裁切边缘的物体,在远景和镜头晃动时边缘会产生密集的亮暗噪点,俗称"虫洞感"。这个其实是裁切边缘的高频信号在降采样时被随机丢弃,导致边缘发闪。
这类问题在移动端尤其重,因为移动端很多项目用不上效果较好的抗锯齿方案,Alpha Test边缘就成了重灾区。URP里处理这个方向我会放在第四章专门讲Shader层的方案,这里先记住它的触发机制和贴图重复无关,是采样阶段的高频丢失。
1.4 阴影边缘的水波纹
平行光阴影在日光照到栅栏、树叶这类高频物体时,阴影边缘会出现一圈圈的水纹滚动。原因是阴影贴图分辨率不足,PCF软阴影在采样时对高频遮挡物做了欠采样,导致阴影边缘出现条纹干涉。
在URP里解决阴影摩尔纹的优先级是:先提高阴影贴图分辨率或级联数,再开启软阴影里的高质量滤波。如果开了高质量还是闪,就要考虑给投射阴影的材质做特殊处理,比如让远景植被的阴影投射改为简化版Mesh。这条链路经常被忽略,因为阴影摩尔纹容易被当成"美术摆件问题"而非渲染问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么URP里这类问题特别容易翻车
很多从内置管线切到URP的同事都有同样的疑惑:同样一张贴图、同样的摄像机距离,内置管线没那么明显,一到URP就闪得厉害。这不是错觉,URP的渲染栈确实在某些环节更容易暴露摩尔纹。
2.1 内置管线的老经验不完全适用
内置管线的Projector、实时阴影、自带MSAA组合在高端平台上能压住一部分摩尔纹。到了URP,默认的Forward渲染路径在移动端为了性能会关掉不少抗锯齿选项。也就是说,切换URP不是少了功能,而是默认参数选择走"性能优先"路线,摩尔纹控制优先级相当靠后。
更要命的是,很多团队切URP后保留了内置管线时期的面数规模和贴图分辨率,但没同步补上抗锯齿和后处理配置,于是高频混叠问题全部暴露出来。
2.2 TAA在URP里的可用性差异
内置管线时代,不少人依赖第三方后期栈里的TAA算法压制远景闪烁。URP的Volume框架在后来的版本里提供了TAA,但有几个前提:
- TAA需要依赖摄像机运动产生的Jitter偏移帧,移动端某些GPU驱动下Jitter会造成植被边缘抖动,反而加剧闪烁感。
- URP里TAA和水面反射平面、特定透明Shader的交互需要额外测试,偶尔会出重影。
所以URP项目里不能照搬内置管线"直接开TAA"的经验,必须结合平台和渲染路径做取舍。这个我会在第五章展开说。
2.3 相机栈叠加导致高频二次混叠
URP的多摄像机架构中,Overlay Camera和Base Camera叠加渲染时,每多一次降采样就会引入一次高频丢失。尤其是使用Overlay相机做UI、武器模型、局部特效的时候,画面合并回主相机的过程里,远景的精细纹理被二次采样,波纹会被放大。
排查技巧:把Overlay相机逐个隐藏,看波纹是否有所减轻。如果一个项目叠加了三层相机,远景摩尔纹基本跑不掉,无论贴图怎么压都没用。
2.4 纹理流送与Mip加载时机的坑
URP项目和Addressables等资源管理方案配合时,常遇到Mipmap偏载问题。纹理流送系统在远景优先加载低Mip时是正常的,但某些异步加载场景会出现Mip Level延迟更新,导致高Mip的锐利纹理被错误地用于远景,造成短暂的强摩尔纹爆发。
这种问题最坑的地方在于它不是每次都复现,只在资源加载时机不对时闪现。排查时需要开纹理资源调试面板,盯着特定贴图的Mip状态变化。
3. 纹理源头治理:把高频提前压掉
Shader和后处理都是补救,最划算的还是在贴图阶段就让高频信号变弱。这一章讲三个层面:Mipmap参数、各向异性过滤、贴图内容本身的去规律化。
3.1 Mipmap参数别图省事
日常项目里最常见的错误是:地表大纹理为了省内存关闭了Generate Mip Maps。后果就是远景采样直接对原图做硬降采样,摩尔纹必然爆炸。
在URP项目里,凡是被摄像机拉远观察的贴图,都应该打开Mipmap。需要注意一个隐藏参数:Mip Map Filtering。默认的Box滤波在远景会产生轻微的过度模糊,但也比混叠强得多。想要折中效果可以用Kaiser滤波,它能保留更多中频细节的同时压制高频混叠。
TextrueImporter面板里针对地表、植被Diffuse和Normal贴图的推荐参数如下:
| 贴图类型 | Generate Mip Maps | Filtering | Aniso Level | 说明 |
|---|---|---|---|---|
| 地表Diffuse | 开启 | Kaiser | 4~8 | 压平视角改善明显 |
| 地表Normal | 开启 | Kaiser | 2~4 | 细节损失可接受 |
| 植被Diffuse | 开启 | Box | 4 | 远景更依赖模糊压制 |
| 植被Alpha | 开启 | Box | 1 | 避免透明边缘额外锯齿 |
| UI贴图 | 按需 | 不建议开 | 1 | UI不需要远景 |
3.2 各向异性过滤不是开关,是权衡
各向异性过滤解决的是斜视角下贴图被拉伸模糊的问题。URP里最大可以开到16x,但这不等于所有贴图都应该开到16x。
以草地为例,摄像机以30度角斜看地面,水平方向的UV导数远大于竖直方向,普通各向同性滤波会把两侧一视同仁地模糊掉,而各向异性过滤能在拉伸方向上保留清晰度。逐像素开销在桌面GPU上可以忽略,但移动端高倍Aniso会消耗带宽,具体档位建议配合真机Profile再定。
给一个实用起点:地表和屋顶、墙面这类大面积平铺贴图开4x~8x;角色皮肤、头发贴图开1x;粒子贴图不开。这个配置在多数移动设备上能压住带宽。
3.3 贴图内容本身要去规律化
这是最容易被忽略的一层。摩尔纹的产生依赖周期性的高频信号,平铺贴图里如果存在明显的规律纹路,比如草地每片叶子朝向一致、砖墙缝隙距离均匀、织物经纬线完全平行,那等于主动给摩尔纹提供信号源。
处理方法:
- 法线贴图里把细节层的对比度整体下调,保留大结构、去掉高对比小碎纹。
- Diffuse贴图在远景等效分辨率下看不出来的小细节,直接模糊掉,不要留着。
- 平铺贴图用四方连续处理里常见的"随机偏移+混合"思路,让重复单元之间出现不规则性。
实际操作时,我会把一张远景草地的Diffuse缩小到128x128看缩略图,如果还能看清叶片轮廓,说明高频太强,远景一定会闪。压到缩略图看起来是一片柔和的绿色色块,反而就是安全状态。
3.4 一张地表贴图的调参案例
某个项目把一片草甸出现环形波纹,排查下来问题集中在Normal贴图:细节对比度过高,且Mipmap Filtering是Box,中频信息被保留过多。处理步骤:
- 在贴图处理工具里对Normal细节层做一次轻度模糊,压掉每根草的独立朝向。
- 进入Unity,把Mip Map Filtering改为Kaiser。
- Aniso Level从16降到8,因为波纹主要出现在直视角,而不是压平视角,16x帮助不大。
- 后台编译Shader变体后真机验证。
结果:环形波纹大幅减弱,从"滚动闪烁"变成"几乎不可察觉的静止纹理"。这个案例说明,纹理参数调整的收益往往比后处理明显得多。
4. Shader层频控:UV导数钳制与自适应模糊
贴图侧控制是宏观手段,但总有一些贴图因为风格需要必须保留高频,或者地形平铺跨度过大导致源头压不住。这时就要在Shader里做局部频控了。
4.1 屏幕空间频率的度量工具:UV导数
屏幕上的每个像素在UV空间里覆盖的范围其实都不一样。比如正对着墙看,一个像素可能只覆盖0.001个UV单位;斜着看同一面墙,一个像素可能覆盖0.01个UV单位。UV变化率越大,说明贴图在这个方向被"放大"得越厉害,高频细节丢失得越严重。
HLSL里计算UV导数用三个函数:ddx(沿屏幕x方向的导数)、ddy(沿屏幕y方向的导数)、fwidth(两者的绝对值之和)。fwidth(uv) 可以直接理解成"当前像素覆盖了多少UV宽度的纹理"。
这个值越大,说明当前像素正在对高频贴图做欠采样,正是摩尔纹的高发区。
4.2 基础版:钳制Mip Level
最直接的解法:手动算Mip Level,并给一个下限值,防止远距离高频贴图被锐利采样。
hlsl复制float CalculateMipLevel(float2 uv)
{
float2 dx = ddx(uv);
float2 dy = ddy(uv);
float d = max(dot(dx, dx), dot(dy, dy));
return 0.5 * log2(d); // 近似标准mip层级
}
float mipLevel = CalculateMipLevel(uv);
mipLevel = max(mipLevel, _MinMip); // 强制不低于某个模糊等级
float4 col = tex2Dlod(_MainTex, float4(uv, 0, mipLevel));
这里的关键是_MinMip这个值怎么定。定太低没用,定太高会让所有远处贴图糊成一团。我的习惯是从0开始逐步往上加,用真机截图对比,找到"波纹消失但纹理轮廓还认得出"的临界值。
值得留意的是tex2Dlod在移动端会有一些性能开销,如果只影响少量大面材质问题不大,但如果全场景泛滥,建议只在自定义Shader里用,不要套到所有Lit变体上。
4.3 进阶版:高频自适应模糊
单纯钳制Mip会产生一条明显的"清晰到模糊"接缝。进阶做法是根据UV导数做一个平滑过渡的混合,视觉上更自然。
思路是:取两个采样结果,一个用正常Mip,另一个用更高的模糊Mip,然后根据fwidth的强度做插值。
hlsl复制float mipLevel = CalculateMipLevel(uv);
float4 colA = tex2Dlod(_MainTex, float4(uv, 0, mipLevel));
float4 colB = tex2Dlod(_MainTex, float4(uv, 0, mipLevel + 2));
float t = saturate((fwidth(uv) - _StartFreq) / (_MaxFreq - _StartFreq));
float4 col = lerp(colA, colB, t);
saturate把插值限制在0到1之间,_StartFreq和_MaxFreq分别表示"开始模糊的UV频率阈值"和"完全模糊的阈值"。这两个值需要根据贴图平铺大小去调,没有万能数值,但逻辑是通用的。
这套方案对比直接钳制Mip的优势在于:中近距离完全不受影响,只有高频风险区域参与模糊,没有生硬的视觉跳变。
4.4 ShaderGraph与手写HLSL的接入方式
如果项目主要用ShaderGraph,可以把上面的代码放进Custom Function节点。需要注意Custom Function的输入输出类型要明确声明,UV的导数函数在ShaderGraph里也可以用。
如果是手写URP Lit风格Shader,需要把这段逻辑插在采样BaseMap之前,同时注意透明队列和混合模式的特殊性。我记得有一次把这套逻辑贴到透明材质上,结果因为透明物体没有深度写导致远处透明面混合顺序错乱,反而出现更明显的条纹,后来限定只对不透明队列开启才解决。
4.5 Alpha Test植被的改造
前面提到的植被虫洞问题,本质是硬裁切边缘的高频丢失。URP里比Alpha Test更稳的做法是带阈值的Dithered Transparency,用一张Bayer矩阵噪声做透明度渐变,让边缘形成抖动过渡而不是硬切。
hlsl复制float alphaThreshold = 0.5;
float dither = dot(float2(0.25, 0.75), frac(uv * _ScreenParams.xy));
clip(smoothstep(alphaThreshold - _SmoothWidth, alphaThreshold + _SmoothWidth, alpha) - dither);
这样处理后的植被边缘在远景会变成细密的点状过渡,视觉上不再有虫洞闪烁,代价是边缘不再是完美硬边,不过多数草丛、树冠风格都能接受。
URP 14以上版本对Cross-fade、Dithered LOD的配合已经比较成熟,如果用LODGroup切换植被,建议优先选Cross-fade LOD选项。
5. 屏幕空间兜底:URP里的抗锯齿与后处理配置
走到这一层,说明源头和Shader层已经尽力了,需要靠全屏手段兜底。URP里能用到的工具比内置管线多一些,但配置姿势有讲究。
5.1 URP Asset与Volume里的抗锯齿入口
URP有两个位置控制抗锯齿:
第一个在URP Asset的Quality设置里,有MSAA、SMAA、FXAA三种选择。MSAA只在不透明物体上生效,植被用的是Alpha Test,实际上能吃到MSAA的边缘覆盖,但Toon Shader或自定义Shader需要额外处理。FXAA是最廉价的方案,但它本质是边缘柔化,对画面整体锐度损失比较大,远景纹理容易发糊。
第二个在Post-processing Volume里,添加Temporal Anti-aliasing后,可以单独调质量与锐化参数。TAA是压制远景摩尔纹最适合的屏幕空间工具,因为它依靠时间累积重建高频信号,对静止画面提升尤其明显。但移动端要谨慎:Jitter会让静态植被边缘出现缓慢漂移感,个别设备上反而比不开更明显,开之前先做针对性真机验证。
5.2 Renderer Feature拦截场景颜色做局部降频
如果项目不能开TAA或者开了也不满意,又不想全局砍锐度,可以自己写一个Renderer Feature做局部模糊。思路不复杂:在后处理Pass里读取Scene Color的亮度,计算梯度,对高频区域叠加一个轻度高斯模糊。
实际实现时需要区分"静态远景模糊"和"近景清晰"这两块区域。我一般用深度值做系数分配:深度超过某个距离的像素加大模糊强度,近景保持原样。这样比全局模糊聪明很多,也不会影响角色和近景细节。
这类自研后处理在上手成本上确实不低,但对水面反射、无限远地面这类顽固场景,效果比TAA和叠MSAA都直接。
5.3 平台组合建议表
| 平台与渲染路径 | 首选方案 | 备选方案 | 注意事项 |
|---|---|---|---|
| 桌面PC Forward | MSAA 4x + TAA | 贴图层+Shader层即可 | TAA先测试植被抖动 |
| 桌面PC Forward+ | Shader层频控 + TAA | SMAA | Forward+不支持MSAA |
| 移动端Forward | 贴图层压高频 | Shader层钳制Mip | 慎开TAA,耗电且可能抖动 |
| 移动端Forward+ | 贴图层+Shader层 | 不开后处理 | Forward+移动端GPU吃力 |
| VR(URP) | MSAA强制4x+ | Shader层频控 | 任何后处理都谨慎 |
这个表是我项目里实际用过的组合逻辑,不是标准答案,但能给出一套相对安全的起点。
6. 实测之后的几条重要结论
在这里整理几个我踩过的坑,以及反复测试后得到的结论。这些内容比方案本身更值得记住,因为大部分团队并不是不知道方案,而是被错误经验带偏了。
6.1 别迷信"贴图里加大噪点"
网上有一种说法:往贴图里叠加随机噪点可以打散摩尔纹规律。实测下来,噪点确实能打散规则波纹,但代价是把原本平滑的远景区域变成密密麻麻的颗粒闪烁,观感从"水波纹"变成"脏雪花",而且噪点颗粒在压缩之后会二次混叠,出现新的彩色杂点。
正确的方向应该是降低贴图的高频对比,而不是增加随机信号。要记住摩尔纹是"信号打架",减少其中一方的能量才是根本。
6.2 摩尔纹不可能完全消除
接受这个现实能省大量调试时间。摩尔纹只能被抑制到"静止且微弱"的状态,想让它完全消失,代价往往是画面发糊、细节尽失。
从视觉舒适度排序来看:
- 静止的微弱纹理条纹(最可接受)
- 不明显的微滚动条纹
- 明显的静态环形波纹
- 随镜头滚动的波纹(最伤眼)
所以调参的时候,优先消灭"滚动感",其次再压"存在感"。滚动感是摄像机移动时波纹跟着变化的动态现象,比静态条纹更容易让玩家注意到。
6.3 Mipmap Bias别乱调负值
不少追求远景锐度的项目会把Global Mipmap Bias调到-1甚至-2,让远处贴图更清晰。这个操作对摩尔纹的影响是灾难性的:它等于强制全场景所有物体使用更高分辨率的Mip层级,让远景的高频信号全部返场,纹理会变得"锐利且疯狂闪烁"。
如果某个贴图远景偏糊,正确做法是单独调该贴图的Aniso等级或Mip偏移,而不是动全局Bias。全局Bias是核选项,只能在最后阶段由整体效果负责人决定。
6.4 做一套固定的验收手法
摩尔纹的呈现和摄像机角度、移动速度强相关,靠编辑器里随便转视角根本判断不准。我在项目里会固定三套验收参数,贴在测试用例文档里:
- 斜角45度、距离20米,缓慢平移,检查地表波纹。
- 正对栅栏类物体,距离30米,原地旋转,检查波浪色带。
- 植被区域,距离15米,快速横向移动,检查边缘闪烁。
每次修改都要在这三套条件下截帧对比,才能客观评估效果。没有这套流程,很容易出现"调完觉得好了,玩家一跑又闪回来了"的尴尬。
6.5 预算有限时的优先顺序
如果只能做三件事,我的选择顺序一定是:先把贴图的Mipmap和内容高频压制做好,再给地表和高频材质加Shader层Mip钳制,最后考虑后处理TAA。后处理是兜底而不是首选,因为它的性能成本和平台风险最高。
反过来也是对的:如果贴图层做扎实,很多远景摩尔纹问题根本走不到Shader层就已经解决了,项目省下的性能可以留给更值得用的地方。这个结论是我在多次项目里验证过的,建议各位在动手前先信一次。
