URP 渲染实战 / 第 27 章 URP 内置后处理全解析 / 案例 27.1
案例 27.1受击反馈与低血量去色入门
目标:游戏逻辑调用 OnHit() 时,屏幕边缘闪一下暗红色暗角并带一点色差,随后逐渐恢复;血量低于 30% 时画面逐渐去色。所有效果都放在一个专用的高优先级全局 Volume 上,和场景的美术 Volume 互不干扰。
Assets/Cookbook/Ch27/PostFxController.cs(节选:setup)
void OnEnable() { m_Volume = GetComponent<Volume>(); // profile(而不是 sharedProfile)会在第一次访问时克隆一份运行时实例,改它不会污染磁盘上的资源 var profile = m_Volume.profile; m_Vignette = GetOrAdd<Vignette>(profile); m_CA = GetOrAdd<ChromaticAberration>(profile); m_Color = GetOrAdd<ColorAdjustments>(profile); } static T GetOrAdd<T>(VolumeProfile profile) where T : VolumeComponent { if (!profile.TryGet(out T comp)) comp = profile.Add<T>(); comp.active = true; return comp; }
Assets/Cookbook/Ch27/PostFxController.cs(节选:update)
void Update() { m_Hit = Mathf.Max(0f, m_Hit - hitDecay * Time.deltaTime); // Override(x) 同时做两件事:overrideState = true,value = x。 // 只改 .value 而 overrideState 为 false 时,这个参数不参与混合,改了等于没改。 m_Vignette.color.Override(hitColor); m_Vignette.intensity.Override(Mathf.Lerp(0.2f, 0.55f, m_Hit)); m_Vignette.smoothness.Override(0.6f); m_CA.intensity.Override(m_Hit * 0.8f); // 低血量:血量低于 30% 后逐渐去色 float lowHp = Mathf.InverseLerp(0.3f, 0f, health); m_Color.saturation.Override(Mathf.Lerp(0f, -80f, lowHp)); }
几个关键点:volume.profile 会克隆一份运行时 Profile,修改它不会弄脏资源文件,但要记得在销毁时释放;修改参数用 Override(value),它同时把 overrideState 设为 true——只赋 .value 而没勾 override 的参数不参与混合,这是“脚本改了没效果”的头号原因;TryGet 找不到组件时用 Add 添加,并确认 active 为 true。
如果想知道所有 Volume 混合之后的最终值(例如让 UI 随 Bloom 强度变化),读 VolumeManager.instance.stack:
Assets/Cookbook/Ch27/PostFxController.cs(节选:read)
默认栈由正在渲染的相机每帧更新,多相机时要注意读取时机;也可以用 VolumeManager.instance.CreateStack() 建立自己的栈,再 VolumeManager.instance.Update(stack, trigger, layerMask) 手动更新。URP Asset 的 Volume Update Mode 设为 Via Scripting 时,相机不会每帧自动更新 Volume,需要调用 UniversalAdditionalCameraData.UpdateVolumeStack(),在 Volume 很多、参数很少变化的项目里可以省下 CPU。