GameTech/URP 渲染实战
源码 / shaders/Ch26/KawaseBlur.glsl
shaders/Ch26/KawaseBlur.glsl
// 案例 26.3:Kawase(Pass 0)与 Dual Kawase(Pass 1 下采样 / Pass 2 上采样)。
Shader "Cookbook/Ch26/KawaseBlur"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
        ZTest Always ZWrite Off Cull Off

        GLSLINCLUDE
        // _BlitTexture_TexelSize:源纹理(_BlitTexture)的纹素大小,Core.glsl 已声明
        uniform float _KawaseOffset;            // 由 cmd.SetGlobalFloat 逐次设置,不要放进 Properties

        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
        vec4 Tap(vec2 uv) { return texture(_BlitTexture, uv); }

        // 经典 Kawase:在对角线 4 个点各采一次(每次双线性 = 4 个纹素平均),第 i 次迭代偏移 i+0.5
        vec4 FragKawase()
        {
            vec2 uv = texcoord;
            vec2 d = _BlitTexture_TexelSize.xy * _KawaseOffset;
            vec4 c = Tap(uv + vec2( d.x,  d.y));
            c += Tap(uv + vec2(-d.x,  d.y));
            c += Tap(uv + vec2( d.x, -d.y));
            c += Tap(uv + vec2(-d.x, -d.y));
            return c * 0.25;
        }

        // Dual Kawase 下采样:中心权重 4 + 四个对角各 1,共 5 次采样,输出到一半分辨率
        vec4 FragDown()
        {
            vec2 uv = texcoord;
            vec2 h = _BlitTexture_TexelSize.xy * 0.5 * _KawaseOffset;
            vec4 c = Tap(uv) * 4.0;
            c += Tap(uv - h);
            c += Tap(uv + h);
            c += Tap(uv + vec2(h.x, -h.y));
            c += Tap(uv - vec2(h.x, -h.y));
            return c * (1.0 / 8.0);
        }

        // Dual Kawase 上采样:菱形 4 点(权重 1)+ 对角 4 点(权重 2),共 8 次采样,输出到两倍分辨率
        vec4 FragUp()
        {
            vec2 uv = texcoord;
            vec2 h = _BlitTexture_TexelSize.xy * 0.5 * _KawaseOffset;
            vec4 c = Tap(uv + vec2(-h.x * 2.0, 0.0));
            c += Tap(uv + vec2( h.x * 2.0, 0.0));
            c += Tap(uv + vec2(0.0, -h.y * 2.0));
            c += Tap(uv + vec2(0.0,  h.y * 2.0));
            c += Tap(uv + vec2(-h.x,  h.y)) * 2.0;
            c += Tap(uv + vec2( h.x,  h.y)) * 2.0;
            c += Tap(uv + vec2( h.x, -h.y)) * 2.0;
            c += Tap(uv + vec2(-h.x, -h.y)) * 2.0;
            return c * (1.0 / 12.0);
        }
        #endif
        ENDGLSL

        Pass
        {
            Name "Kawase"
            GLSLPROGRAM
            #ifdef FRAGMENT
            void main() { fragColor = FragKawase(); }
            #endif
            ENDGLSL
        }
        Pass
        {
            Name "DualDown"
            GLSLPROGRAM
            #ifdef FRAGMENT
            void main() { fragColor = FragDown(); }
            #endif
            ENDGLSL
        }
        Pass
        {
            Name "DualUp"
            GLSLPROGRAM
            #ifdef FRAGMENT
            void main() { fragColor = FragUp(); }
            #endif
            ENDGLSL
        }
    }
}