做游戏画面优化和质感调优的时候,后处理往往是最容易出效果、也最容易翻车的一环。很多开发者习惯把 Bloom、Color Grading、景深一股脑全打开,结果画面要么糊成一片,要么脏得没法看。问题通常不在某一个参数没调好,而是对 Unity 后处理整条链路缺少一个完整的认知。这篇笔记按我实际项目里的使用经验,把 Unity 后处理核心效果的原理、参数方向、组合顺序和常见坑一次性说清楚,适合刚接触后处理、想提升画面表现、或者准备做移动端效果裁剪的 Unity 开发者和技术美术参考。
1. 先把底层逻辑理清楚:后处理到底在“处理”什么
1.1 一个全屏 Pass 和一条渲染管线
后处理的本质,是在场景正常渲染完成后,对已经写好的整张屏幕图像再做一次或多次全屏处理。你可以把它想象成拍照流程里的“修图”阶段:相机已经拍到了画面,这时候你再加滤镜、调亮度、柔化背景,最后才输出给人看。
Unity 有两条主流的后处理入口。旧版内置渲染管线通常用 Post Processing Stack,在 Camera 上挂组件然后配 Profile;URP/HDRP 则把后处理整合进 Volume 框架,通过 Volume 组件和 Profile 管理效果,参数可以在运行时叠加和过渡。不管用哪一套,底层做的事情都一样:把那个全屏 Pass 当成一个可编排的流水线,每个效果就是流水线上的一个岗位。
我在实际项目里更推荐用 Volume 这套逻辑做事,因为它天然支持局部效果和全局效果切换。比如玩家走进一个洞穴,可以让全局 Volume 的暗角和色彩调整权重慢慢变化,或者让另一个局部 Volume 覆盖洞口区域。这种按区域、按权重叠加的能力,在内置管线栈里实现起来非常折腾,但在 URP 里基本就是配置一次的事。
后处理还有一个容易被忽略的前提:输入图像的质量。如果你的相机没有开 HDR,很多后处理效果在第一步就输了。这里说的 HDR 不是手机拍照那个 HDR,而是渲染缓冲里允许像素值突破 1.0。普通 LDR 图像里最亮也只能是纯白,画面中的“高光区域”和“普通亮部”没有区分,Bloom 这类依赖亮度阈值的效果就无从谈起。
1.2 线性空间、HDR 与管线选型
先讲色彩空间。Unity 项目设置里可以选择 Gamma 还是 Linear。如果你做的是偏真实风格、对光影有要求的项目,尽量把项目切到 Linear。线性空间下的光照计算更符合物理规律,后处理里的亮度提取、颜色混合也会更合理。Gamma 空间下调 Bloom,高光容易偏橘、偏脏,因为颜色在非线性空间混合时会产生意外的偏移。
再讲 HDR。在相机设置里开启 HDR 后,后处理栈会拿到一张浮点精度的屏幕纹理,所有超过 1.0 的亮度信息都能被保留。这也是 Bloom 效果能够出现干净高光扩散的原因:只有最亮的小面积区域才应该被提取出来发光,而不是整张脸都像涂了荧光粉。
管线选型方面,我的建议是:新项目尽量留在 URP 之上。URP 的后处理基于 Scriptable Render Pipeline,所有效果都在 Volume Overrides 里勾选启用,性能可视化的调节粒度很细。HDRP 当然画面上限更高,但它要求的硬件和美术资源规格也更高,对小团队和移动端项目有点重。老项目如果实在停留在内置管线,也可以把 Post Processing Stack 的 Profile 管理起来,但注意它和 URP 的参数类型有些差异,不推荐两边混用。
管线确认之后,后面所有效果参数才有讨论意义。很多“调了半天还是不对”的问题,根因就是项目还在 Gamma 空间、相机没开 HDR、平台又不支持线性渲染,后处理根本没有条件工作。
2. 核心效果逐个拆解:原理、参数与画面手感
2.1 Bloom:阈值和 Scatter,决定电影感还是霓虹灯廉价感
Bloom 是所有后处理效果里感知最强的,没有之一。它的原理分三步:从画面里提取超过指定亮度阈值的区域,对提取结果做模糊扩散,再把模糊结果叠加回原图。听起来简单,但三个步骤的质量会直接决定最终观感。
第一个关键参数是 Threshold,阈值。阈值决定了什么亮度才算“高光”。我见过很多新手把它拉到 0.5 甚至更低,结果整个画面每一个亮部都在发光,场景像掉进碱性水池。正常电影感的做法是让阈值保持在 1 到 1.5 之间,让画面里只有太阳、灯、镜面高光这种本身就足够亮的像素参与扩散。
第二个关键参数是 Intensity,强度。强度控制扩散后叠回原图的比例,通常不需要太高。0.3 到 0.6 之间做轻微的光晕提升就已经很自然,拉满的话会直接变成霓虹灯招牌。
第三个是 Scatter,扩散程度。这个参数控制高光向外散开的柔和程度。Scatter 越高,光晕越松散,适合柔和夜景;Scatter 越低,高光边缘越清晰,容易产生“描边感”。如果发现 Bloom 看起来像被描了一层荧光边,大概率是 Scatter 太低,同时模糊迭代次数不够。
我在项目里还会特别注意 Bloom 的 Clamp 参数。Clamp 可以限制最终叠加亮度,避免画面因为 Bloom 直接被顶到过曝。移动端上,Bloom 的开销主要集中在多次降采样和模糊,阈值和迭代次数不要贪高,宁可让光晕小一点,也别把帧率拖垮。
2.2 Color Grading 与 Tonemapping:调色不是为了“更艳”
Color Grading 是后处理里最容易被误用成“饱和度拉满”的效果。它不是单纯的滤镜,而是一整套颜色空间控制:曝光补偿、对比度、饱和度、颜色滤片、通道混合、曲线和分区调色。真正做画面质感,要先想清楚你的场景主色调是什么,再通过颜色分级让画面形成记忆点,而不是无脑加红加绿。
URP 的 Color Adjustments 里有几个值得反复调的参数:Post Exposure、Contrast、Saturation、Color Filter。Post Exposure 可以理解为曝光补偿,但它是 HDR 尺度的调整,比直接改相机曝光更后置。Contrast 拉高会让画面更“硬”,但需要配合暗部细节,否则黑位会死黑。Saturation 我一般只在 0 到正负 10 之间微调,大幅拉高饱和度是画面显得业余的最快方式。
真正能提升画面完成度的,往往不是 Color Adjustments,而是 Split Toning 和 Color Curves。Split Toning 可以分别给高光和阴影染色,比如高光轻微偏黄、阴影轻微偏蓝,这是电影里最常见的冷暖对比手法。Color Curves 可以精确控制亮部、暗部、中间调的响应曲线,适合做柔和的高光压缩和暗部提亮。阴影、中调、高光这组曲线一旦调好了,画面立刻会有“被设计过”的感觉。
Tonemapping 是紧接着色彩分级的关键一环。Tonemapping 负责把浮点的 HDR 颜色映射回 0 到 1 的 LDR 显示范围。URP 里常见的模式有 Neutral 和 ACES。ACES 的默认映射对高光压缩比较激进,会让颜色更收敛,质感接近电影工业,但也会导致本来明快的颜色变灰一点。Neutral 更温和,适合卡通和风格化项目。不要一开始就追求 ACES,先把两个模式切换对比,看哪种更符合项目调性。
2.3 Depth of Field 和 Motion Blur:景深与运动模糊
景深模拟的是镜头的聚焦特性。它的核心是“离焦点越远越模糊”,因此必须依赖场景深度信息。Unity 后处理的 Depth of Field 有两种常用模式:Gaussian 和 Bokeh。Gaussian 性能更好,散景是柔和的高斯模糊形状,适合移动端和性能敏感项目;Bokeh 会生成真实的光圈散景形状,画面更华丽,但开销成倍增加。
景深的关键参数是 Focus Distance、Aperture 和 Focal Length。Focus Distance 是焦点所在距离,Aperture 模拟光圈大小,数值越小景深越浅,背景越模糊,也越容易出现光斑。Focal Length 影响模糊区域的变化速率,数值越大,远近模糊差异越夸张。
我踩过的坑是:把 Focus Distance 设成了固定值,但角色一转头或者镜头一变焦,焦点就不在目标身上,画面一片糊。正确思路是不要硬设固定距离,而是把焦点跟随主相机的目标对象,或者设置焦点变换目标。URP 里可以按世界坐标计算焦点距离,也可以挂脚本动态更新 Focus Distance。
Motion Blur 模拟相机快门时间内的物体运动轨迹。它依赖速度缓冲,需要把相机和物体的运动信息传到一个速度纹理上。Motion Blur 的参数主要是 Intensity 和 Clamp。Intensity 决定运动模糊强度,Clamp 控制采样范围上限,避免快速旋转时产生极度夸张的拖尾。
运动模糊在移动端和低帧率项目里要慎重。帧率越低,每一帧的运动跨度越大,Motion Blur 越容易变成“糊成一团”,玩家反而会觉得头晕。我通常只在高品质 PC/主机场景或过场动画里开 Motion Blur,并且把 Clamp 控制在 0.3 以下,让拖尾只是轻微附着,不破坏清晰度。
2.4 AO、SSR 与抗锯齿:容易被忽略的“质感三件套”
Ambient Occlusion 常被简称为 AO,模拟物体接触部分的阴影遮蔽。墙角、物体缝隙、角色与地面接触处看起来更“实”,靠的就是 AO。它比 Bloom 低调,但对画面立体感的提升非常明显。URP 中的 AO 在不同版本里入口略有差别,有些版本在 Renderer Feature 里单独开关,有些版本直接挂在 Volume Override 下,需要按项目实际版本查找。
AO 的参数主要是 Intensity、Radius 和 Quality。Radius 决定周围多大范围内计算遮蔽,太大会在物体周围出现一圈“脏晕”,太小又几乎看不到效果。我习惯把 Intensity 控制在 0.3 到 0.8 之间,Radius 按场景尺度微调。AO 不是越深越好,它的作用是“暗示接触阴影”,做得太强会让模型像被煤灰糊过。
SSR 即屏幕空间反射,会利用屏幕像素做反射计算。它对移动端来说非常昂贵,而且经常出现采样边缘缺失、反射拖影之类的问题。URP 默认没有提供完整的屏幕空间反射,HDRP 支持这个能力。如果项目跑在 URP 里,追求反射质感更可靠的做法是用反射探针和低分辨率反射平面做近似,节省性能,画面也足够稳。
抗锯齿放在后处理里,是因为它需要在最终图像上消除锯齿边缘。FXAA 最便宜但会稍微糊化细节,SMAA 边缘判断更准但开销稍高,TAA 效果最好但可能带来重影。实际项目里,PC 端我倾向开 TAA 配合动态分辨率稳定画面,移动端会用 FXAA 或 MSAA 先做一层基础抗锯齿,再配合少量后处理。
3. 效果之间不是逐个堆叠,而是组链路
3.1 后处理栈内执行顺序为什么重要
很多人以为后处理效果可以随便开,每个效果独立生效。其实在渲染管线里,每个后处理效果是有固定执行顺序的。Unity 后处理栈大致遵循:先做输入画面的稳定类处理,比如抗锯齿;再做基于几何信息的屏幕空间效果,比如 AO、SSR;然后是基于深度和运动的模糊类效果,比如景深、运动模糊;接着是 HDR 相关的光效和色彩处理,比如 Bloom、色调映射、色彩分级;最后才是颗粒感、暗角、色差这些风格化修饰。
这个顺序会直接影响最终观感。比如 Bloom 应该发生在色调映射之前,因为 Bloom 需要用到超过 1.0 的高亮信息,如果先把 HDR 压成 LDR,那高光细节早就丢了。又比如暗角放最后是为了不干扰前面的颜色处理。你在调参时不一定需要记住每个官方顺序,但至少要明白一个原则:高动态区域相关的东西要在色调映射之前,屏幕边角修饰放在最后。
我在项目架构里会把后处理当成一个“有层次的叠加过程”,而不是一次性把十几个 Override 全部打勾。允许参与实际渲染的效果数量越少,画面越容易控制。你可以在编辑器里临时打开所有效果预览组合,但最终发布版本一定要做一次效果裁剪。
3.2 效果组合的选择与避坑清单
不同风格的画面,合适的效果组合完全不同。写实风格项目通常需要 Bloom、AO、Tonemapping、轻微 Vignette 和 Color Grading 的配合;卡通渲染更依赖抗锯齿和色彩分级,Bloom 只用来做角色边缘的光感,不宜过度;恐怖项目暗角和色差可以明显一点,但景深和运动模糊要克制。
组合效果时最需要注意的是“效果之间的参数互相影响”。举个例子,Bloom 会把画面整体往亮了拉,如果你同时把 Color Grading 的曝光补偿调高,那整个画面很容易过曝。反过来,Tonemapping 选择 ACES 会让高光变灰,视觉上可能要补偿一点饱和度。调参的顺序建议是:先固定 Tone Mapping,再调 Color Grading,接着调 Bloom,最后调暗角和颗粒。这样每一步都有基准,不会越调越乱。
下面是我建议的一个避坑检查清单:
- 确认相机开启 HDR,项目使用线性颜色空间。
- Bloom 的 Threshold 不低于 1,避免大面积发光。
- Tonemapping 先设定模式,不要再反复切换。
- AO 的 Radius 不要超过场景最小缝隙的合理尺度。
- TAA 和 Motion Blur 不要同时拉高,否则画面拖影严重。
- Vignette 强度控制在 0.3 以内,明显暗角容易让人感到压抑。
如果你发现画面越调越浑浊,多半是某个后处理效果叠加了太多层。这时候不要继续在这个效果身上死磕,先把所有效果关掉,从零一个个开回来,逐个判断哪个是罪魁祸首。这个方法听起来笨,却是排查后处理问题最直接的方式。
4. 从零搭一套可复用的后处理 Profile(实操)
4.1 Global Volume vs Local Volume
在 URP 体系里,Volume 组件负责定义后处理作用范围和权重。Global Volume 作用于整个场景,适合基础画面风格;Local Volume 需要挂一个碰撞体,玩家进入范围后才会触发效果,适合区域事件、房间切换、洞穴变暗这类场景。
实际项目中我会同时维护两套 Profile:一套是全局通用的 BaseProfile,负责色调映射、色彩分级、Bloom 底子;另一套是区域 FallbackProfile,通过叠加权重做过渡。比如玩家靠近毒雾区域,局部 Volume 可以把 Bloom 阈值降低、颜色往绿色偏移,并用 Vignette 暗示危险。
需要注意的是,多个 Volume 叠加时效果并不是简单相加,而是按优先级和权重混合。如果全局有一个 Bloom,局部也有一个 Bloom,两者的参数会根据权重插值。混乱的 Volume 层级会让你找不到真实生效参数,所以命名和分层一定要规范。
4.2 一套起步参数表(URP 为例)
下面这套参数不能照搬到每个项目,但它是一个非常稳定的起步基准,适合写实风格的第三人称或第一人称视角项目。它把画面压在一个相对克制、干净的范围,然后再根据项目风格微调。
| 效果模块 | 参数 | 推荐起始值 | 说明 |
|---|---|---|---|
| Bloom | Threshold | 1.1 | 只让高亮区域发光 |
| Bloom | Intensity | 0.5 | 光晕强度和场景氛围匹配 |
| Bloom | Scatter | 0.4 | 让光晕柔和扩散 |
| Tone Mapping | Mode | ACES | 对高光做电影式压缩 |
| Color Adjustments | Post Exposure | 0 | 配合场景灯光再微调 |
| Color Adjustments | Contrast | 5 | 轻微提升立体感 |
| Color Adjustments | Saturation | 0 | 建议只做小幅微调 |
| Depth of Field | Mode | Bokeh | 品质项目可选,移动端慎用 |
| Depth of Field | Focus Distance | 跟随主目标 | 动态更新,不要固定值 |
| Depth of Field | Aperture | 4.0 | 不要小于 2.0,否则太糊 |
| Vignette | Intensity | 0.25 | 暗角只做轻微压边 |
| Film Grain | Intensity | 0.15 | 提升胶片感,只在小范围用 |
如果你做的是移动端,可以直接把 Depth of Field 关掉,Bloom 的 Iteration 和 Downsample 设保守一点,Vignette 强度降到 0.1。很多高端画质的参数在移动端不是“可以接受”与否的问题,而是会让帧率直接掉到不可玩。
4.3 运行时动态控制效果参数
后处理参数最常见的动态需求是:玩家进入不同状态后,画面风格过渡变化。比如受伤时颜色变红、暗角加重;瞄准时景深焦点变化。这一步不需要动画师去调 Volume 权重,只要在脚本里拿到 VolumeProfile 并 Override 参数即可。
下面是一段 URP 下的简单示例,演示运行时修改 Bloom 强度:
using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class PostProcessController : MonoBehaviour { [SerializeField] private Volume volume; private Bloom bloom; void Awake() { if (volume == null) volume = GetComponent<Volume>(); // 尽量避免直接修改 Asset Profile,先实例化一份运行时 Profile volume.profile = Instantiate(volume.profile); if (volume.profile.TryGet<Bloom>(out var bloomOverride)) { bloom = bloomOverride; } } public void SetBloomIntensity(float value) { if (bloom != null) { bloom.intensity.Override(value); } } }这里有一个非常容易踩的坑:如果直接用volume.profile上的 Bloom 对象改参数,你修改的是原始 Profile 资源本身,运行停止后资源也被污染了。正确做法是先Instantiate(volume.profile),让运行时脚本只改那份临时实例。这样才能保证编辑器里的原始资产不被运行时调试数据弄脏。
4.4 性能预算和移动端取舍
后处理不是免费午餐。每个效果都在消耗 GPU 时间,叠加多了再强的显卡也会被拖低帧率。做性能优化时我通常会把后处理效果分成三个开销等级:
| 开销等级 | 效果示例 | 建议 |
|---|---|---|
| 低 | Vignette、Film Grain、Chromatic Aberration | 可以常开,参数克制即可 |
| 中 | Bloom、Color Grading、FXAA/SMAA | 开但控制迭代和采样次数 |
| 高 | Bokeh Depth of Field、Motion Blur、TAA、SSR、全屏 AO | 按平台能力决定是否开启 |
移动端尤其要注意发热和帧率波动。Bloom 的降采样迭代、TAA 的历史帧采样、Bokeh 的散景采样,都是高消耗点。我在移动端项目里的做法是:用 Profiler 抓一段时间帧数据,看每个 Pass 的耗时,然后从最贵的效果开始裁剪。如果画面需要 Bloom,可以只保留两次降采样,并把 Scatter 调高来弥补柔和度。如果画面需要景深,优先用 Gaussian 而不是 Bokeh。
另外,动态分辨率开启时,后处理纹理分辨率也会跟着降,这会让 Bloom 块状感变明显。遇到这种情况,可以考虑给 Bloom 单独指定分辨率缩放模式,不要完全跟着主分辨率走。
5. 常见问题与排查技巧实录
5.1 画面发灰、过曝、泛白
先说发灰。打开后处理后画面像蒙了一层雾,最常见原因是色彩管理不对。检查项目是否切到 Linear 空间,相机是否开启 HDR;再看 Tonemapping 是否处于启用状态。没有 Tonemapping 的情况下,HDR 亮度直出到 LDR,超亮部分会被硬裁掉,视觉上就是一块块灰白。
另一个原因是你同时开了 Bloom 和 Color Adjustments 的高曝光补偿。Bloom 会把亮部进一步扩散,曝光补偿再抬高,高光自然就爆了。处理思路是先把 Color Adjustments 调回 0,关掉 Bloom,看基准画面是否正常,再逐个恢复。
5.2 Bloom 块状、边缘生硬
如果你看到 Bloom 不是一个柔和光晕,而是一块一块跟着高光边缘走的色块,多半是降采样次数不够和 Scatter 太低。Bloom 内部需要把高光图逐步缩小后做模糊,如果缩小层级少,光晕扩散范围就有限。可以把 Scatter 往上调,如果还不行,就需要增加 Bloom 的迭代次数或模糊半径。
块状感也可能来自 HDR 开启但阈值太高,导致只有极少数像素参与发光。提取出来的区域本身就不连续,再扩散也变不成平滑光晕。把 Threshold 降到合理范围,保证高光区域有一定连续性。
5.3 编辑器正常、真机效果丢失或发黑
这类问题在移动端非常典型。最常见原因是真机 API 不支持某些纹理格式或渲染特性。景深依赖深度纹理,如果 URP 的 Depth Texture 没有开启,编辑器里可能显示正常,真机上却拿不到深度信息,效果直接消失。
发黑的另一个常见原因是 Bloom 的输入依赖 HDR,而移动端在某些图形 API 下默认不启用 HDR。真机上如果画面里所有后处理效果都异常,优先检查相机 HDR 选项和渲染管线资产的 Color Grading 模式。还需要注意移动端的 OpenGL ES 3.0 和高通平台对浮点纹理位置的处理方式,有些效果需要适配不同 Pass 的分辨率缩放。
5.4 运行时调节参数没有生效
运行时修改 Bloom、Color Grading 这些参数不生效,先看 Volume 组件是否启用了isGlobal,或者物体的 Layer 是否在 Volume Mask 里。如果 Volume 没有匹配任何可见物体,它就不会参与计算。
再看你的修改代码是否调用了Override方法。Volume Profile 里的参数是一个FloatParameter类型,不能直接赋值,必须用.Override(value)才会把覆盖开关打开。很多人只赋值不 Override,看起来代码没报错,但实际效果一直是默认值。
最后一个容易被忽略的是 Volume 的 Weight。如果 Weight 是 0,哪怕参数全部正确,效果也不会生效。过渡动画一般都要从一个权重变化到另一个权重,调权重时顺便确认一下参数 Override 状态。
5.5 定位性能热区的通用步骤
如果某台设备帧率不稳定,不要凭感觉关效果。先在 Frame Debugger 里看后处理一共占用多少个 Pass,再用 Profiler 抓 GPU 具体耗时。URP 会显示每个后处理 Pass 的耗时开销,重点看 RenderScale 是否远高于预期。
个人经验里,排查后处理问题最有效的路径永远是“先关到零,再顺序开启”。把所有 Override 全部取消勾选,画面回到白纸状态,然后一个模块一个模块打开,每次打开后分别观察画面表现和帧耗时。这个过程看起来很笨,但能帮你快速定位是哪个效果、哪个参数组合引发了异常,比盲调有用得多。
最后再分享一个我自己的小习惯:每套后处理 Profile 都会单独复制一份备份。调参时我会记录下“当前项目风格关键词”和对应参数范围,比如“冷色调写实:AcES + 色温 -10 + Bloom 0.4”,避免下次打开工程又重新从头摸索。后处理没有唯一标准答案,但如果你能把链路逻辑和参数影响范围理解透,配合几次刻意练习,很快就能找到属于自己的那一套稳定配方。