关于 urp-postprocessing
urp-postprocessing 是通过 Volume 框架设置、配置和调试 URP 后期处理效果的技能,面向在运行中的 Unity Editor 中操作项目的用户。它提供前置检查、代码指导、效果配方和故障排查步骤。
主要功能
- 01检查 URP 与相机前置条件
- 02配置 Volume 配置文件与覆盖项
- 03效果属性和 API 指导
- 04排查效果未生效的清单
- 05多种视觉风格的效果配方
适用场景
- 01设置全局或局部 Volume
- 02配置 Bloom 或 Color Adjustments
- 03诊断相机为何未应用 Volume
- 04实现电影、恐怖或清爽风格
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ unity-technologies/ unity-agent-plugin --skill urp-postprocessing安装后在 Claude Code 中输入/urp-postprocessing确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
SECURITY.mdreferences/code-templates.mdeffect-reference.md详细介绍
帮助用户使用 URP 的 Volume 框架设置、配置和调试后处理效果。
目标:设置完成后,用户应获得正常运行的视觉效果,且控制台中没有错误。
0. 前提条件:能够运行 C# 的 Editor
Volume 配置文件、VolumeParameter.overrideState 和摄像机的后处理标志都属于 Editor/运行时对象状态——以下检查和编辑都需要在运行中的 Editor 内执行 C#。
unity-cli 技能负责帮助你完成这些准备工作——安装 CLI、确认已连接的 Editor、添加项目的 com.unity.pipeline 包、区分确实缺失的 Editor 和卡在 Safe Mode 中的 Editor,以及查找 Editor 的命令目录。请先遵循该技能;不要在这里重新推导这些内容。你特别需要 script eval,而不只是能够连接到 Editor:该命令是否存在取决于 Pipeline 包版本,而非 CLI。如果缺少该命令,请说明情况并停止。
使用 script eval 命令,通过已连接的 Editor 运行 C#。请从 unity command --format json 中查找参数格式,不要自行假设——内联形式为
unity command script eval --caller plugin --skill urp-postprocessing --code '<snippet>';某些 Pipeline 版本还会注册 script eval_file,用于运行文件中的代码片段。尝试使用 script eval_file 前,请先检查命令目录;该命令经常不存在。 unity command 默认超时时间为 30 秒。
向 script eval 传递 C#
script eval 编译的是语句块,而非文件。这会导致两个后果,且都会引发编译错误而非警告:
- 不能使用
using指令。 编译器会将using UnityEngine;视为资源释放语句并拒绝它(CS0210)。 - 类型必须写出完整限定名。 无法解析不带限定名的
AssetDatabase或Volume(CS0246/CS0103),而不带限定名的Object会与object产生歧义(CS0104)。
下面以文件形式编写的代码片段——为了便于阅读而包含 using,或是准备保存到项目中的代码——在传递给 script eval 前,都要为其中的类型补上限定名。
0. 预检
配置任何效果前,请确认所有检查均已通过。先修复未通过的项目。
- URP 是当前启用的渲染管线——如果不是,请告知用户并停止。
- URP Asset 已启用 HDR——色调映射需要 HDR。HDR 能让 Bloom 达到最佳效果;在 SDR 下 Bloom 仍可使用,但
threshold必须小于 1。 - 摄像机已启用后处理——
renderPostProcessing必须为true(默认为false)。摄像机堆叠:只有CameraRenderType.Base摄像机(或堆叠中的最后一个Overlay)应启用后处理。还要确认 Renderer 的 PostProcessData 资源不为 null——如果为 null,后处理通道将不存在。 - Volume 所在的 GameObject 层包含在摄像机的 Volume Layer Mask 中——
volumeLayerMask默认仅包含第 0 层“Default”。必须将 Volume 的GameObject.layer包含在其中,否则摄像机将忽略该 Volume。 - Volume 已存在,且
enabled = true、配置文件有效,并至少包含一个覆盖项——Volume组件必须已启用,且profile(或sharedProfile)不为 null,并至少有一个VolumeComponent的属性设置了overrideState = true。
预检代码片段
运行以下代码,以编程方式验证设置:
// `script eval` compiles a statement block, not a file: no `using` directives are
// allowed, so every type is fully qualified.
var report = new System.Text.StringBuilder();
// 1. Check URP is active — a hard stop, so throw: it fails the eval loudly
var urpAsset = UnityEngine.Rendering.Universal.UniversalRenderPipeline.asset;
if (urpAsset == null)
throw new System.Exception("URP is not the active render pipeline.");
// 2. Check HDR
if (!urpAsset.supportsHDR)
report.AppendLine("Warning: HDR is disabled on the URP Asset. Tonemapping won't work; Bloom requires threshold < 1.");
// 3. Check camera post-processing
var cam = UnityEngine.Camera.main;
if (cam == null)
throw new System.Exception("No Main Camera found.");
if (!cam.TryGetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>(out var camData))
throw new System.Exception("Missing UniversalAdditionalCameraData on camera. Is URP active?");
if (!camData.renderPostProcessing)
report.AppendLine("Warning: Post-processing is disabled on the camera. Enable via camData.renderPostProcessing = true.");
// 4. Check volume layer mask
var volumes = UnityEngine.Object.FindObjectsByType<UnityEngine.Rendering.Volume>(UnityEngine.FindObjectsSortMode.None);
foreach (var vol in volumes)
{
if (!vol.enabled) { report.AppendLine($"Warning: Volume '{vol.name}' is disabled."); continue; }
if ((camData.volumeLayerMask & (1 << vol.gameObject.layer)) == 0)
report.AppendLine($"Warning: Volume '{vol.name}' on layer {vol.gameObject.layer} is not in camera's volumeLayerMask.");
// 5. Check profile and overrides
var profile = vol.sharedProfile;
if (profile == null) { report.AppendLine($"Warning: Volume '{vol.name}' has no profile assigned."); continue; }
if (profile.components.Count == 0)
report.AppendLine($"Warning: Volume '{vol.name}' profile has no overrides.");
}
// Return the findings: logs land in the Editor console, the returned value comes back to you
return report.Length == 0 ? "Post-processing setup looks correct." : report.ToString();
1. Volume 设置
效果通过在 VolumeProfile(一个 ScriptableObject)上添加 VolumeComponent 覆盖项来实现。
全局 Volume(最常见):带有 Volume 组件的 GameObject,设置 isGlobal = true 并分配 profile。所有 volumeLayerMask 包含该 Volume 所在图层的摄像机都会受到影响。
局部 Volume(可选,但优先级更高):带有触发器 Collider 和 Volume 组件的 GameObject,设置 isGlobal = false。属性:
priority(float)— 数值越高,在 Volume 重叠时越能覆盖低优先级的 Volume。blendDistance(float)— 开始混合的外部距离,单位为世界单位(0 = 不混合,在 Collider 边界处瞬间过渡)。weight(float,0–1)— 缩放 Volume 的整体影响程度。
2. 后处理效果
所有效果都是 VolumeComponent 子类,通过 profile.Add<T>() 作为覆盖项添加到 VolumeProfile。使用 profile.Has<T>() 或 profile.TryGet<T>(out var t) 检查是否存在。使用 profile.Remove<T>() 移除。
每个属性都是 VolumeParameter。设置 value 之前,必须先设置 overrideState = true,否则 Volume 系统会忽略该属性。
配置特定效果时,请查阅完整 API 参考:
- references/effect-reference.md — 按效果列出的所有 VolumeComponent 属性(Bloom、Tonemapping、ColorAdjustments、DepthOfField、Vignette、MotionBlur、FilmGrain、ChromaticAberration、SplitToning、LensDistortion、WhiteBalance、PaniniProjection、LiftGammaGain、ShadowsMidtonesHighlights、ColorCurves、ChannelMixer)
代码模板:
- references/code-templates.md — 全局 Volume 设置、摄像机后处理和 Profile 修改模板
3. 防止幻觉规则
必需的 Usings
这些规则适用于向项目中编写 .cs 文件。传递给 script eval 的代码片段无法携带这些内容 — 请改为限定类型的命名空间(见上文“向 script eval 传递 C# 代码”)。
using UnityEngine.Rendering; // Volume, VolumeProfile, VolumeComponent, VolumeParameter
using UnityEngine.Rendering.Universal; // Bloom, Tonemapping, ColorAdjustments, UniversalRenderPipeline, etc.
错误 → 正确 API 对照
| 错误 | 正确 |
|---|---|
PostProcessVolume | Volume(来自 UnityEngine.Rendering) |
PostProcessLayer | UniversalAdditionalCameraData.renderPostProcessing(bool) |
UnityEngine.Rendering.PostProcessing | UnityEngine.Rendering.Universal |
profile.GetSetting<T>() | profile.TryGet<T>(out var t)(返回 bool) |
profile.AddSettings<T>() | profile.Add<T>()(返回 T;若已存在则抛出异常 — 请先检查 profile.Has<T>()) |
volume.sharedProfile(用于运行时修改) | volume.profile(自动将资源克隆为实例) |
VolumeManager.instance.stack.GetComponent<T>() | volume.profile.TryGet<T>(out var t) |
关键事实
- 对每个要设置的
VolumeParameter,都必须设置overrideState = true。Volume 系统会跳过overrideState为false的参数。这是脚本编写中最常见的错误。 sharedProfile= 直接返回资源(编辑会保存到磁盘)。profile= 如有需要,会自动克隆为实例(适合在运行时安全编辑)。使用volume.HasInstantiatedProfile()检查。profile.Add<T>(bool overrides = false)— 传入true可自动为所添加组件的所有参数启用overrideState。
4. 调试清单
后处理不起作用时,请按顺序检查:
cam.TryGetComponent<UniversalAdditionalCameraData>(out var data)是否成功,且data.renderPostProcessing是否为true?- 场景中是否存在 Volume,并且已为其指定非空的
profile(或sharedProfile)? - 是否通过
profile.Add<T>()添加了覆盖项,并将每个已设置属性的overrideState设为true? - Volume 的
GameObject.layer是否包含在相机的data.volumeLayerMask中?(默认掩码仅包含第 0 层 “Default”。) volume.isGlobal = true(用于全局 Volume),或者相机是否位于本地 Volume 的触发Collider内?- 相机的
data.renderType是否为CameraRenderType.Base,而不是Overlay?(Overlay 相机会叠加到 Base 相机的输出上。) UniversalRenderPipeline.asset.supportsHDR是否为true?Bloom 和 Tonemapping 必须启用此项。- 是否在 Game 视图中查看?Scene 视图的工具栏中有单独的后处理开关。
5. 常用配方
格式:效果 属性=值。Bloom 的值依次为 threshold/intensity/scatter。
电影感(影片): Tonemapping mode=ACES,ColorAdjustments contrast=15 saturation=-10,Bloom threshold=0.9 intensity=0.5 scatter=0.7,Vignette intensity=0.3 smoothness=0.4,FilmGrain type=Medium1 intensity=0.2
风格化/鲜艳: Tonemapping mode=Neutral,ColorAdjustments saturation=20 contrast=10,Bloom threshold=0.8 intensity=1.5 scatter=0.6,SplitToning highlights=warm shadows=cool
恐怖/阴暗: ColorAdjustments postExposure=-0.5 saturation=-30 contrast=20,Vignette intensity=0.5 smoothness=0.3 color=dark-red,FilmGrain type=Large01 intensity=0.4,ChromaticAberration intensity=0.15
清爽/移动端: Tonemapping mode=Neutral,ColorAdjustments postExposure=0.2,Bloom threshold=1.0 intensity=0.3(微妙效果)。在移动端避免使用 FilmGrain、MotionBlur、DepthOfField。
6. 最终确认
设置完成后,向用户报告:
Post-Processing Setup Complete
- Volume: [Global/Local] on "[GameObject Name]"
- Profile: [Asset Path]
- Effects: [List with key property=value pairs]
- Camera: [Name] — renderPostProcessing=true, volumeLayerMask includes layer [N]
View results in Game view (not Scene view).
Undo all changes with Edit > Undo (Ctrl+Z).