GameTech/URP 渲染实战
源码 / Ch26/LensEffects.cs
Ch26/LensEffects.cs
// 案例 26.6:两个“镜头类”效果——色差(Chromatic Aberration)与暗角(Vignette)。
// 各自独立的 Volume + Feature,演示多个自定义后处理如何叠加与排序。
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace Cookbook.Ch26
{
    [Serializable, VolumeComponentMenuForRenderPipeline("Cookbook/My Chromatic Aberration", typeof(UniversalRenderPipeline))]
    public sealed class MyChromaticAberration : VolumeComponent, IPostProcessComponent
    {
        public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
        [Tooltip("沿径向分几段采样;3 = 只取 RGB 三次,越多色散越平滑")]
        public ClampedIntParameter samples = new ClampedIntParameter(6, 3, 16);
        public bool IsActive() => intensity.value > 0f;
        public bool IsTileCompatible() => false;
    }

    [Serializable, VolumeComponentMenuForRenderPipeline("Cookbook/My Vignette", typeof(UniversalRenderPipeline))]
    public sealed class MyVignette : VolumeComponent, IPostProcessComponent
    {
        public ColorParameter color = new ColorParameter(Color.black, false, false, true);
        public Vector2Parameter center = new Vector2Parameter(new Vector2(0.5f, 0.5f));
        public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
        public ClampedFloatParameter smoothness = new ClampedFloatParameter(0.5f, 0.05f, 1f);
        [Tooltip("勾选后按屏幕宽高比修正成正圆")]
        public BoolParameter rounded = new BoolParameter(false);
        public bool IsActive() => intensity.value > 0f;
        public bool IsTileCompatible() => false;
    }

    public class MyChromaticAberrationFeature : PostFeatureBase
    {
        protected override string ShaderName => "Cookbook/Ch26/MyChromaticAberration";
        protected override PostPassBase CreatePass(Material m) => new Pass(m);

        class Pass : SimplePostPass<MyChromaticAberration>
        {
            static readonly int s_Params = Shader.PropertyToID("_CAParams");
            public Pass(Material m) : base(m, "Ch26 Chromatic Aberration") { }
            protected override void Apply(MyChromaticAberration v, ref RenderingData rd)
                => material.SetVector(s_Params, new Vector4(v.intensity.value, v.samples.value, 0, 0));
        }
    }

    public class MyVignetteFeature : PostFeatureBase
    {
        protected override string ShaderName => "Cookbook/Ch26/MyVignette";
        protected override PostPassBase CreatePass(Material m) => new Pass(m);

        class Pass : SimplePostPass<MyVignette>
        {
            static readonly int s_Color = Shader.PropertyToID("_VignetteColor");
            static readonly int s_Params = Shader.PropertyToID("_VignetteParams");  // xy 中心, z 强度, w 柔和度
            static readonly int s_Rounded = Shader.PropertyToID("_VignetteRounded");
            public Pass(Material m) : base(m, "Ch26 Vignette") { }
            protected override void Apply(MyVignette v, ref RenderingData rd)
            {
                material.SetColor(s_Color, v.color.value);
                var c = v.center.value;
                material.SetVector(s_Params, new Vector4(c.x, c.y, v.intensity.value, v.smoothness.value));
                material.SetFloat(s_Rounded, v.rounded.value ? 1f : 0f);
            }
        }
    }
}