GameTech/URP 渲染实战
源码 / shaders/Ch21/Flipbook.glsl
shaders/Ch21/Flipbook.glsl
// 案例 21.2:序列帧动画(Flipbook)——按时间算帧号,可选帧间混合;附带图集调试视图(GLSL 版,对应 Ch21/Flipbook.shader)
Shader "Cookbook/Ch21/Flipbook"
{
    SubShader
    {
        Tags { "RenderType"="Transparent" "RenderPipeline"="UniversalPipeline" "Queue"="Transparent" "IgnoreProjector"="True" }

        Pass
        {
            Name "Unlit"
            Tags { "LightMode"="UniversalForward" }
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            Cull Off
            GLSLPROGRAM
            #pragma shader_feature_local_fragment _FLIPBOOK_BLEND
            #pragma shader_feature_local_fragment _DEBUG_ATLAS
            #pragma multi_compile_instancing
            #include "Ch21/UVAnim.glsl"

            uniform vec4 _BaseMap_ST;
            uniform vec4 _BaseColor;
            uniform vec4 _Grid;
            uniform float _FPS, _Frame;
            uniform sampler2D _BaseMap;

            VARYING vec2 uv;
            VARYING vec4 vColor;

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

            #ifdef FRAGMENT
            vec4 frag()
            {
                float frame = _Time.y * _FPS + _Frame;       // 连续的“帧号”,小数部分就是两帧之间的进度

            #if defined(_DEBUG_ATLAS)
                // 调试:整张图集 + 网格线;当前帧描橙框,下一帧描蓝框
                vec4 atlas = texture(_BaseMap, uv);
                vec3 bg = mix(vec3(0.12, 0.16, 0.2), atlas.rgb, atlas.a);
                vec2 cell = uv * _Grid.xy;
                vec2 f = fract(cell);
                float line_ = step(min(min(f.x, 1.0 - f.x), min(f.y, 1.0 - f.y)), 0.015);
                float idx = (_Grid.y - 1.0 - floor(cell.y)) * _Grid.x + floor(cell.x);
                float total = _Grid.x * _Grid.y;
                float cur = Ch21Fmod(floor(frame), total), nxt = Ch21Fmod(floor(frame) + 1.0, total);
                float border = step(min(min(f.x, 1.0 - f.x), min(f.y, 1.0 - f.y)), 0.05);
                bg = mix(bg, vec3(0.5, 0.55, 0.6), line_);
                bg = mix(bg, vec3(1.0, 0.45, 0.15), border * float(idx == cur));
                bg = mix(bg, vec3(0.25, 0.6, 1.0), border * float(idx == nxt));
                return vec4(bg, 1.0);
            #endif

                vec2 uvA = FlipbookUV(uv, frame, _Grid.xy);
                vec4 c = texture(_BaseMap, uvA);
            #if defined(_FLIPBOOK_BLEND)
                // 帧间混合:再采一张“下一帧”,按小数部分线性插值。代价是多一次采样
                vec2 uvB = FlipbookUV(uv, frame + 1.0, _Grid.xy);
                vec4 cB = texture(_BaseMap, uvB);
                c = mix(c, cB, fract(frame));
            #endif
                c *= _BaseColor * vColor;
                return c;
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }
    }
}