{"id":20142,"plugin_id":"plugins_6aa1c02597c081918e358d72f65bd772","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:16:01.853Z","digest":"c2511f9eb14c70527669ddc7dee99868d5b419ec7e7813494595f5ae886f4c70","against":null,"payload":{"description":"Sets up, configures, and debugs URP post-processing effects using the Volume framework. Use when the user asks about bloom, tonemapping, color adjustments, depth of field, vignette, motion blur, or other Volume overrides in a URP project.","included_files":[{"relative_path":"references/code-templates.md","size_in_bytes":7397},{"relative_path":"references/effect-reference.md","size_in_bytes":5501}],"name":"urp-postprocessing","skill_md_contents":"---\nname: urp-postprocessing\ndescription: Sets up, configures, and debugs URP post-processing effects using the Volume framework. Use when the user asks about bloom, tonemapping, color adjustments, depth of field, vignette, motion blur, or other Volume overrides in a URP project.\nrequired_packages:\n  com.unity.render-pipelines.universal: \">=14.0.0\"\n---\n\nHelp the user set up, configure, and debug post-processing effects using URP's Volume framework.\n\n**Goal: The user should have a working visual result with zero console errors after setup.**\n\n## 0. Prerequisite: an Editor you can run C# in\n\nVolume profiles, `VolumeParameter.overrideState`, and the camera's post-processing flags are\nEditor/runtime object state — the checks and edits below all run C# inside a live Editor.\n\n**The `unity-cli` skill owns getting you there** — installing the CLI, confirming a connected\nEditor, adding the project's `com.unity.pipeline` package, telling a genuinely absent Editor\napart from one stuck in Safe Mode, and discovering the Editor's command catalog. Follow it\nfirst; don't re-derive any of it here. You need `eval` in particular, not just a reachable\nEditor: its presence depends on the Pipeline package version, not on the CLI. If it's\nmissing, say so and stop.\n\nRun C# through the connected Editor with the `eval` command. Discover its parameter shape\nfrom `unity command --format json` rather than assuming one — the inline form is\n`unity command eval --caller plugin --skill urp-postprocessing --code '<snippet>'`, and some Pipeline versions also register\n`eval_file` for running a snippet from a file. **Check the catalog before reaching for\n`eval_file`; it is frequently absent.** `unity command` defaults to a 30 second timeout.\n\n### Passing C# to `eval`\n\n`eval` compiles a **statement block, not a file**. Two consequences, both of which cause a\ncompile error rather than a warning:\n\n- **No `using` directives.** The compiler reads `using UnityEngine;` as a resource-disposal\n  statement and rejects it (`CS0210`).\n- **Types must be fully qualified.** A bare `AssetDatabase` or `Volume` does not resolve\n  (`CS0246` / `CS0103`), and a bare `Object` is ambiguous with `object` (`CS0104`).\n\nWhere a snippet below is written as a file — with usings, for readability, or because it is\nmeant to be saved into the project — qualify the types before passing it to `eval`.\n\n## 0. Pre-Flight Checks\n\nBefore configuring any effect, **verify all checks**. Fix failures first.\n\n1. **URP is the active render pipeline** — If not, inform the user and stop.\n2. **HDR is enabled on the URP Asset** — Required for Tonemapping. Bloom works best with HDR; in SDR it still works but `threshold` must be < 1.\n3. **Camera has post-processing enabled** — `renderPostProcessing` must be `true` (defaults to `false`). Camera Stacking: only a `CameraRenderType.Base` camera (or the last `Overlay` in the stack) should enable post-processing. Also verify the Renderer's PostProcessData asset is not null — if it is, the post-process pass won't exist.\n4. **The Volume's GameObject layer is in the Camera's Volume Layer Mask** — `volumeLayerMask` defaults to layer 0 \"Default\" only. The Volume's `GameObject.layer` must be included, otherwise the camera ignores it.\n5. **Volume exists with `enabled = true`, a valid Profile, and at least one override** — The `Volume` component must be enabled, have a non-null `profile` (or `sharedProfile`), and at least one `VolumeComponent` with `overrideState = true` on its properties.\n\n### Pre-Flight Check Snippet\n\nRun this to verify the setup programmatically:\n\n```csharp\n// `eval` compiles a statement block, not a file: no `using` directives are\n// allowed, so every type is fully qualified.\nvar report = new System.Text.StringBuilder();\n\n// 1. Check URP is active — a hard stop, so throw: it fails the eval loudly\nvar urpAsset = UnityEngine.Rendering.Universal.UniversalRenderPipeline.asset;\nif (urpAsset == null)\n    throw new System.Exception(\"URP is not the active render pipeline.\");\n\n// 2. Check HDR\nif (!urpAsset.supportsHDR)\n    report.AppendLine(\"Warning: HDR is disabled on the URP Asset. Tonemapping won't work; Bloom requires threshold < 1.\");\n\n// 3. Check camera post-processing\nvar cam = UnityEngine.Camera.main;\nif (cam == null)\n    throw new System.Exception(\"No Main Camera found.\");\nif (!cam.TryGetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>(out var camData))\n    throw new System.Exception(\"Missing UniversalAdditionalCameraData on camera. Is URP active?\");\nif (!camData.renderPostProcessing)\n    report.AppendLine(\"Warning: Post-processing is disabled on the camera. Enable via camData.renderPostProcessing = true.\");\n\n// 4. Check volume layer mask\nvar volumes = UnityEngine.Object.FindObjectsByType<UnityEngine.Rendering.Volume>(UnityEngine.FindObjectsSortMode.None);\nforeach (var vol in volumes)\n{\n    if (!vol.enabled) { report.AppendLine($\"Warning: Volume '{vol.name}' is disabled.\"); continue; }\n    if ((camData.volumeLayerMask & (1 << vol.gameObject.layer)) == 0)\n        report.AppendLine($\"Warning: Volume '{vol.name}' on layer {vol.gameObject.layer} is not in camera's volumeLayerMask.\");\n    // 5. Check profile and overrides\n    var profile = vol.sharedProfile;\n    if (profile == null) { report.AppendLine($\"Warning: Volume '{vol.name}' has no profile assigned.\"); continue; }\n    if (profile.components.Count == 0)\n        report.AppendLine($\"Warning: Volume '{vol.name}' profile has no overrides.\");\n}\n\n// Return the findings: logs land in the Editor console, the returned value comes back to you\nreturn report.Length == 0 ? \"Post-processing setup looks correct.\" : report.ToString();\n```\n\n## 1. Volume Setup\n\nEffects are added as **VolumeComponent overrides** on a **VolumeProfile** (a `ScriptableObject`).\n\n**Global Volume** (most common): GameObject with `Volume` component, `isGlobal = true`, `profile` assigned. Affects every camera whose `volumeLayerMask` includes the Volume's layer.\n\n**Local Volume (optional, but takes precedence)**: GameObject with trigger `Collider` + `Volume` component, `isGlobal = false`. Properties:\n- `priority` (float) — higher values override lower when volumes overlap.\n- `blendDistance` (float) — outer distance in world units to start blending from (0 = no blend, instant transition at collider boundary).\n- `weight` (float, 0–1) — scales the volume's overall influence.\n\n## 2. Post-Processing Effects\n\nAll effects are `VolumeComponent` subclasses added as overrides on a `VolumeProfile` via `profile.Add<T>()`. Check existence with `profile.Has<T>()` or `profile.TryGet<T>(out var t)`. Remove with `profile.Remove<T>()`.\n\nEvery property is a `VolumeParameter`. You **must** set `overrideState = true` before setting `value`, otherwise the Volume system ignores it.\n\nWhen configuring a specific effect, load the full API reference:\n- [references/effect-reference.md](references/effect-reference.md) — All VolumeComponent properties by effect (Bloom, Tonemapping, ColorAdjustments, DepthOfField, Vignette, MotionBlur, FilmGrain, ChromaticAberration, SplitToning, LensDistortion, WhiteBalance, PaniniProjection, LiftGammaGain, ShadowsMidtonesHighlights, ColorCurves, ChannelMixer)\n\nFor code templates:\n- [references/code-templates.md](references/code-templates.md) — Global Volume setup, camera post-processing, and profile modification templates\n\n## 3. Anti-Hallucination Rules\n\n### Required Usings\n\nThese apply when you write a `.cs` file into the project. **A snippet passed to `eval` cannot\ncarry them** — qualify the types instead (see \"Passing C# to `eval`\" above).\n\n```csharp\nusing UnityEngine.Rendering;           // Volume, VolumeProfile, VolumeComponent, VolumeParameter\nusing UnityEngine.Rendering.Universal;  // Bloom, Tonemapping, ColorAdjustments, UniversalRenderPipeline, etc.\n```\n\n### Wrong → Correct API Mapping\n\n| WRONG | CORRECT |\n|-------|---------|\n| `PostProcessVolume` | `Volume` (from `UnityEngine.Rendering`) |\n| `PostProcessLayer` | `UniversalAdditionalCameraData.renderPostProcessing` (bool) |\n| `UnityEngine.Rendering.PostProcessing` | `UnityEngine.Rendering.Universal` |\n| `profile.GetSetting<T>()` | `profile.TryGet<T>(out var t)` (returns bool) |\n| `profile.AddSettings<T>()` | `profile.Add<T>()` (returns T; throws if already exists — check `profile.Has<T>()` first) |\n| `volume.sharedProfile` (to modify at runtime) | `volume.profile` (auto-clones the asset into an instance) |\n| `VolumeManager.instance.stack.GetComponent<T>()` | `volume.profile.TryGet<T>(out var t)` |\n\n### Key Facts\n- **`overrideState = true`** is required on every `VolumeParameter` you set. The volume system skips parameters where `overrideState` is `false`. This is the #1 scripting mistake.\n- **`sharedProfile`** = returns the asset directly (edits persist to disk). **`profile`** = auto-clones into an instance if needed (safe for runtime edits). Check with `volume.HasInstantiatedProfile()`.\n- **`profile.Add<T>(bool overrides = false)`** — pass `true` to auto-enable `overrideState` on all parameters of the added component.\n\n## 4. Debugging Checklist\n\nWhen post-processing isn't working, check in order:\n\n1. `cam.TryGetComponent<UniversalAdditionalCameraData>(out var data)` succeeds and `data.renderPostProcessing` is `true`?\n2. Volume exists in scene with a non-null `profile` (or `sharedProfile`) assigned?\n3. Overrides added via `profile.Add<T>()` AND `overrideState = true` on each property you set?\n4. Volume's `GameObject.layer` is included in camera's `data.volumeLayerMask`? (Default mask is layer 0 \"Default\" only.)\n5. `volume.isGlobal = true` (for global), or camera is inside the Volume's trigger `Collider` (for local)?\n6. Camera `data.renderType` is `CameraRenderType.Base`, not `Overlay`? (Overlay cameras composite onto the Base camera's output.)\n7. `UniversalRenderPipeline.asset.supportsHDR` is `true`? Required for Bloom and Tonemapping.\n8. Viewing in **Game view**? Scene view has a separate post-processing toggle in its toolbar.\n\n## 5. Common Recipes\n\nFormat: Effect property=value. Bloom values are threshold/intensity/scatter.\n\n**Cinematic (Film):** 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\n\n**Stylized/Vibrant:** Tonemapping mode=Neutral, ColorAdjustments saturation=20 contrast=10, Bloom threshold=0.8 intensity=1.5 scatter=0.6, SplitToning highlights=warm shadows=cool\n\n**Horror/Dark:** 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\n\n**Clean/Mobile:** Tonemapping mode=Neutral, ColorAdjustments postExposure=0.2, Bloom threshold=1.0 intensity=0.3 (subtle). Avoid FilmGrain, MotionBlur, DepthOfField on mobile.\n\n## 6. Final Confirmation\n\nAfter setup, report to user:\n\n```\nPost-Processing Setup Complete\n- Volume: [Global/Local] on \"[GameObject Name]\"\n- Profile: [Asset Path]\n- Effects: [List with key property=value pairs]\n- Camera: [Name] — renderPostProcessing=true, volumeLayerMask includes layer [N]\n\nView results in Game view (not Scene view).\nUndo all changes with Edit > Undo (Ctrl+Z).\n```\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}