GameTech/URP 渲染实战
源码 / shaders/Ch17/Shatter.glsl
shaders/Ch17/Shatter.glsl
// 碎裂与吸附重组:每个三角形是一块碎片,围绕自己的中心旋转、沿面法线飞出并受“重力”下落。(GLSL 版)
// _Progress 从 0 到 1 是碎裂;反过来从 1 到 0 播放,就是碎片飞回来“吸附”成形。
// 碎片开始运动的时间由它在 _SweepDir 方向上的位置决定,形成一道扫过模型的“裂解前沿”。
Shader "Cookbook/Ch17/Shatter"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        GLSLINCLUDE
        uniform vec4 _BaseColor, _GlowColor;
        uniform vec4 _SweepDir;
        uniform float _Progress, _Spread, _Distance, _Spin, _Gravity, _Shrink;
        #include "Ch17/VertexAnimCommon.glsl"

        // URP Core 的 GeometricTools.hlsl 里的 RotationFromAxisAngle(绕单位轴 A 旋转)。
        // HLSL 的 float3x3(...) 按行构造,GLSL 的 mat3(...) 按列构造,所以外面套一个 transpose
        mat3 RotationFromAxisAngle(vec3 A, float sinAngle, float cosAngle)
        {
            float c = cosAngle, s = sinAngle;
            return transpose(mat3(
                A.x * A.x * (1.0 - c) + c,       A.x * A.y * (1.0 - c) - A.z * s, A.x * A.z * (1.0 - c) + A.y * s,
                A.x * A.y * (1.0 - c) + A.z * s, A.y * A.y * (1.0 - c) + c,       A.y * A.z * (1.0 - c) - A.x * s,
                A.x * A.z * (1.0 - c) - A.y * s, A.y * A.z * (1.0 - c) + A.x * s, A.z * A.z * (1.0 - c) + c));
        }

        void Deform(inout VAAttributes v)
        {
            vec3 center = v.uv1.xyz;
            float rnd = v.uv1.w;
            vec3 faceN = v.uv2.xyz;

            // 1) 这块碎片自己的进度 p:沿扫描方向越靠前越早开始,再加一点随机
            // 物体空间坐标大致在 -1..1,映射到 0..1 后乘以 _Spread
            float start = saturate(dot(center, normalize(_SweepDir.xyz)) * 0.5 + 0.5) * _Spread + rnd * 0.2;
            float p = saturate(_Progress * (1.0 + _Spread + 0.2) - start);
            float ease = p * p * (3.0 - 2.0 * p);                  // smoothstep 曲线,起步柔和

            // 2) 绕碎片中心、绕一根随机轴旋转,并逐渐缩小
            vec3 axis = normalize(vec3(rnd - 0.5, fract(rnd * 7.13) - 0.5, fract(rnd * 3.71) - 0.5) + 1e-4);
            float angle = ease * _Spin * (0.5 + rnd);
            mat3 R = RotationFromAxisAngle(axis, sin(angle), cos(angle));
            vec3 local = (R * (v.positionOS.xyz - center)) * (1.0 - ease * _Shrink);

            // 3) 沿面法线飞出 + 抛物线下落(物体空间的 -Y)
            vec3 offset = faceN * ease * _Distance * (0.6 + rnd) + vec3(0.0, 1.0, 0.0) * (0.3 * ease - _Gravity * ease * ease);

            v.positionOS.xyz = center + local + offset;
            v.normalOS = R * v.normalOS;                         // 法线跟着碎片一起转
            v.uv2.w = p;                                         // 进度交给片元做发光
        }

        #include "Ch17/VertexAnimPasses.glsl"
        ENDGLSL

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode"="UniversalForwardOnly" }
            Cull Off    // 碎片翻转后会露出背面
            GLSLPROGRAM
            #ifdef VERTEX
            void main() { VAForwardVert(); }
            #endif
            #ifdef FRAGMENT
            void main()
            {
                vec3 N = normalize(normalWS) * (gl_FrontFacing ? 1.0 : -1.0);
                vec3 col = VALighting(_BaseColor.rgb, N, positionWS, 0.6, 64.0);
                // 刚脱离的碎片最亮,飞远后逐渐冷却
                float p = extra.w;
                float glow = saturate(p * 6.0) * (1.0 - p);
                fragColor = vec4(col + _GlowColor.rgb * glow, 1.0);
            }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On ZTest LEqual ColorMask 0 Cull Off
            GLSLPROGRAM
            #ifdef VERTEX
            void main() { VAShadowVert(); }
            #endif
            #ifdef FRAGMENT
            void main() { VANullFrag(); }
            #endif
            ENDGLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On ColorMask R Cull Off
            GLSLPROGRAM
            #ifdef VERTEX
            void main() { VADepthVert(); }
            #endif
            #ifdef FRAGMENT
            void main() { VANullFrag(); }
            #endif
            ENDGLSL
        }
    }
}