GameTech/URP 渲染实战
源码 / shaders/Ch21/Flowmap.glsl
shaders/Ch21/Flowmap.glsl
// 案例 21.3:Flowmap——用一张“流向图”驱动贴图沿任意方向流动,双相位消除跳变(GLSL 版,对应 Ch21/Flowmap.shader)
Shader "Cookbook/Ch21/Flowmap"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        Pass
        {
            Name "Unlit"
            Tags { "LightMode"="UniversalForwardOnly" }   // 自定义表面混合,没有 GBuffer Pass:Deferred 下也走前向
            GLSLPROGRAM
            #pragma multi_compile_instancing
            #include "Ch21/UVAnim.glsl"

            uniform vec4 _BaseMap_ST;
            uniform float _FlowStrength;
            uniform float _Speed, _Phase;
            uniform float _Mode, _UseRamp, _Intensity;
            uniform sampler2D _BaseMap;
            uniform sampler2D _FlowMap;
            uniform sampler2D _RampTex;

            VARYING vec2 uv;

            #ifdef VERTEX
            void main()
            {
                gl_Position = TransformObjectToHClip(positionOS.xyz);
                uv = texcoord0.xy;
            }
            #endif

            #ifdef FRAGMENT
            vec4 frag()
            {
                vec4 flowTex = texture(_FlowMap, uv);
                if (_Mode < 0.5) return vec4(flowTex.rg, 0.0, 1.0);          // 直接显示流向图

                // RG 存的是 0..1,映射回 -1..1 的方向向量(0.5 灰 = 静止)
                vec2 flow = (flowTex.rg * 2.0 - 1.0) * _FlowStrength;
                float t = (_Time.y + _Phase) * _Speed;
                vec2 uvB = TransformTex(uv, _BaseMap_ST);

                vec4 c;
                if (_Mode < 1.5)
                {
                    // 单相位:UV 沿流向越漂越远,到 fract 归零时整张图“啪”地跳回原位
                    c = texture(_BaseMap, uvB - flow * fract(t));
                }
                else
                {
                    FlowSample fs = FlowUV(uvB, flow, t);
                    vec4 c0 = texture(_BaseMap, fs.uv0);
                    vec4 c1 = texture(_BaseMap, fs.uv1);
                    c = c0 * fs.w0 + c1 * (1.0 - fs.w0);
                }

                if (_UseRamp > 0.5)
                {
                    float k = smoothstep(0.2, 0.9, c.r);
                    c.rgb = texture(_RampTex, vec2(k, 0.5)).rgb * (k * k * _Intensity);
                }
                return vec4(c.rgb, 1.0);
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }
    }
}