GameTech/URP 渲染实战
源码 / shaders/Ch26/MyChromaticAberration.glsl
shaders/Ch26/MyChromaticAberration.glsl
// 案例 26.6:色差。沿径向把 R、G、B 采样到不同位置;采样数 > 3 时用“光谱权重”做平滑色散。
Shader "Cookbook/Ch26/MyChromaticAberration"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
        ZTest Always ZWrite Off Cull Off
        Pass
        {
            Name "ChromaticAberration"
            GLSLPROGRAM
            uniform vec4 _CAParams;   // x 强度, y 采样数

            VARYING vec2 texcoord;
            #ifdef VERTEX
            // Blit.hlsl 的 Vert:用 gl_VertexID 生成盖住全屏的大三角形(_BlitTexture、_BlitTexture_TexelSize 等在 Core.glsl 里声明)
            void main()
            {
                vec2 p = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);
                texcoord = p * _BlitScaleBias.xy + _BlitScaleBias.zw;
                gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
            }
            #endif

            #ifdef FRAGMENT
            // t ∈ [0,1] 映射到 红→绿→蓝 的权重(三段帐篷函数),所有样本的权重之和按通道归一化
            vec3 SpectrumWeight(float t)
            {
                float r = saturate(1.0 - abs(t * 2.0));
                float g = saturate(1.0 - abs(t * 2.0 - 1.0));
                float b = saturate(1.0 - abs(t * 2.0 - 2.0));
                return vec3(r, g, b);
            }

            vec4 Frag()
            {
                vec2 uv = texcoord;
                vec2 d = uv - 0.5;
                // 偏移随半径平方增长:中心几乎无色差,边缘最强(和真实镜头的横向色差一致)
                vec2 offset = d * dot(d, d) * _CAParams.x * 0.15;

                int n = int(_CAParams.y);
                vec3 sum = vec3(0.0), wsum = vec3(0.0);
                for (int i = 0; i < n; i++)
                {
                    float t = float(i) / float(n - 1);         // 0 = 红(向外)… 1 = 蓝(向内)
                    vec3 w = SpectrumWeight(t);
                    vec2 suv = uv + offset * (0.5 - t) * 2.0;
                    sum += texture(_BlitTexture, suv).rgb * w;
                    wsum += w;
                }
                return vec4(sum / max(wsum, vec3(1e-4)), 1.0);
            }
            void main() { fragColor = Frag(); }
            #endif
            ENDGLSL
        }
    }
}