关于 urp-postprocessing
使用 URP 的 Volume 框架配置和调试后处理效果的 Unity 技能。它提供实时编辑器检查、设置指导、效果参考和常见视觉风格配方。
主要功能
- 01检查 URP、HDR、相机和 Volume 前置条件
- 02配置全局及局部 Volume 和配置文件
- 03通过 VolumeComponent 覆盖项添加效果
- 04提供代码模板和视觉风格配方
- 05排查相机与 Volume 配置
适用场景
- 01在 Unity 场景中设置 Bloom 或 Tonemapping
- 02创建按距离混合的局部效果
- 03诊断 Game 视图中后处理效果缺失
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ unity-technologies/ skills --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 和 Editor 卡在安全模式这两种情况,以及发现 Editor 的命令目录。请先按其说明操作;此处不再重复这些内容。你尤其需要 eval,而不仅仅是能连接到 Editor:它是否存在取决于 Pipeline 包版本,而不是 CLI。如果缺少 eval,请说明这一点并停止。
使用 eval 命令通过已连接的 Editor 运行 C#。请通过 unity command --format json 查明其参数形式,不要自行假设——内联形式为 unity command eval --code '<snippet>',某些 Pipeline 版本也会注册 eval_file,用于从文件运行代码片段。使用 eval_file 前请先检查命令目录;它经常不存在。unity command 默认超时时间为 30 秒。
向 eval 传递 C#
eval 编译的是语句块,而不是文件。这会带来两个后果,且都会导致编译错误,而非警告:
- 不能使用
using指令。 编译器会将using UnityEngine;视为资源释放语句并拒绝编译(CS0210)。 - 类型必须使用完全限定名。 单独写
AssetDatabase或Volume无法解析(CS0246/CS0103),而单独写Object会与object冲突(CS0104)。
如果下面的代码片段以文件形式编写——包含 using 语句以便阅读,或因为它要保存到项目中——请先将类型改为完全限定名,再传给 eval。
0. 预检
配置任何效果之前,请验证所有检查项。先修复失败项。
- URP 是当前使用的渲染管线——如果不是,请告知用户并停止。
- URP Asset 已启用 HDR——Tonemapping 需要 HDR。Bloom 在 HDR 下效果最佳;在 SDR 下仍可使用,但
threshold必须小于 1。 - 摄像机已启用后处理——
renderPostProcessing必须为true(默认值为false)。摄像机堆叠:只有CameraRenderType.Base摄像机(或堆叠中的最后一个Overlay)应启用后处理。还要确认 Renderer 的 PostProcessData 资源不为 null——如果为 null,后处理通道将不存在。 - Volume 的 GameObject 图层包含在摄像机的 Volume Layer Mask 中——
volumeLayerMask默认仅包含图层 0“Default”。必须包含 Volume 的GameObject.layer,否则摄像机将忽略它。 - Volume 存在,且
enabled = true、配置文件有效,并至少有一个覆盖项——Volume组件必须已启用,具有非空的profile(或sharedProfile),并且至少有一个VolumeComponent的属性设置了overrideState = true。
预检代码片段
运行以下代码,以程序方式验证设置:
// `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 组件、设置了 isGlobal = true 并分配了 profile 的 GameObject。会影响所有 volumeLayerMask 包含该 Volume 所在图层的摄像机。
局部 Volume(可选,但优先级更高):包含触发器 Collider 和 Volume 组件、设置了 isGlobal = false 的 GameObject。属性:
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。必须先将 overrideState = true,再设置 value,否则 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 设置、摄像机后期处理和配置文件修改模板
3. 防幻觉规则
必需的 Usings
这些适用于在项目中编写 .cs 文件的情况。传递给 eval 的代码片段无法包含这些内容——请改为限定类型名称(参见上文“向 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内(局部 Volume)? - 摄像机的
data.renderType是否为CameraRenderType.Base,而不是Overlay?(Overlay 摄像机会合成到 Base 摄像机的输出上。) UniversalRenderPipeline.asset.supportsHDR是否为true?Bloom 和 Tonemapping 需要此设置。- 是否正在 Game 视图中查看?Scene 视图工具栏中有单独的后期处理开关。
5. 常用配方
格式:效果 属性=值。Bloom 的值依次为阈值/强度/散射。
电影感(胶片): 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=暖色 shadows=冷色
恐怖/暗黑: ColorAdjustments postExposure=-0.5 saturation=-30 contrast=20,Vignette intensity=0.5 smoothness=0.3 color=暗红色,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).