GameTech/URP 渲染实战
源码 / Ch17/Shatter.shader
Ch17/Shatter.shader
// 碎裂与吸附重组:每个三角形是一块碎片,围绕自己的中心旋转、沿面法线飞出并受“重力”下落。
// _Progress 从 0 到 1 是碎裂;反过来从 1 到 0 播放,就是碎片飞回来“吸附”成形。
// 碎片开始运动的时间由它在 _SweepDir 方向上的位置决定,形成一道扫过模型的“裂解前沿”。
Shader "Cookbook/Ch17/Shatter"
{
    Properties
    {
        _BaseColor ("Color", Color) = (0.75, 0.78, 0.85, 1)
        [HDR] _GlowColor ("Glow Color", Color) = (2.5, 0.9, 0.3, 1)
        _Progress ("Progress", Range(0, 1)) = 0.4
        _SweepDir ("Sweep Direction", Vector) = (0, 1, 0, 0)
        _Spread ("Sweep Spread", Range(0, 2)) = 1
        _Distance ("Fly Distance", Range(0, 3)) = 0.8
        _Spin ("Spin (radians)", Range(0, 20)) = 8
        _Gravity ("Gravity", Range(0, 3)) = 0.6
        _Shrink ("Shrink", Range(0, 1)) = 0.6
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl"
        CBUFFER_START(UnityPerMaterial)
            half4 _BaseColor, _GlowColor;
            float4 _SweepDir;
            float _Progress, _Spread, _Distance, _Spin, _Gravity, _Shrink;
        CBUFFER_END
        #include "Assets/Cookbook/Ch17/VertexAnimCommon.hlsl"

        void Deform(inout VAAttributes v)
        {
            float3 center = v.uv1.xyz;
            float rnd = v.uv1.w;
            float3 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) 绕碎片中心、绕一根随机轴旋转,并逐渐缩小
            float3 axis = normalize(float3(rnd - 0.5, frac(rnd * 7.13) - 0.5, frac(rnd * 3.71) - 0.5) + 1e-4);
            float angle = ease * _Spin * (0.5 + rnd);
            float3x3 R = RotationFromAxisAngle(axis, sin(angle), cos(angle));
            float3 local = mul(R, v.positionOS.xyz - center) * (1.0 - ease * _Shrink);

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

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

        #include "Assets/Cookbook/Ch17/VertexAnimPasses.hlsl"
        ENDHLSL

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode"="UniversalForwardOnly" }
            Cull Off    // 碎片翻转后会露出背面
            HLSLPROGRAM
            #pragma vertex VAForwardVert
            #pragma fragment frag
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
            #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
            half4 frag(VAVaryings i, FRONT_FACE_TYPE face : FRONT_FACE_SEMANTIC) : SV_Target
            {
                float3 N = normalize(i.normalWS) * IS_FRONT_VFACE(face, 1.0, -1.0);
                half3 col = VALighting(_BaseColor.rgb, N, i.positionWS, 0.6h, 64.0h);
                // 刚脱离的碎片最亮,飞远后逐渐冷却
                half p = i.extra.w;
                half glow = saturate(p * 6.0h) * (1.0h - p);
                return half4(col + _GlowColor.rgb * glow, 1);
            }
            ENDHLSL
        }

        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode"="ShadowCaster" }
            ZWrite On ZTest LEqual ColorMask 0 Cull Off
            HLSLPROGRAM
            #pragma vertex VAShadowVert
            #pragma fragment VANullFrag
            ENDHLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode"="DepthOnly" }
            ZWrite On ColorMask R Cull Off
            HLSLPROGRAM
            #pragma vertex VADepthVert
            #pragma fragment VANullFrag
            ENDHLSL
        }
    }
}