GameTech/URP 渲染实战
源码 / Ch17/ShatterMesh.cs
Ch17/ShatterMesh.cs
// 为碎裂效果预处理网格:拆开共享顶点(每个三角形独立成“碎片”),
// 把碎片的中心写进 uv1.xyz、随机数写进 uv1.w,面法线写进 uv2.xyz。
// Shader 只要知道“我属于哪块碎片、碎片中心在哪”,就能让三个顶点一起平移、旋转。
using UnityEngine;
using UnityEngine.Rendering;

namespace Cookbook.Ch17
{
    public static class ShatterMesh
    {
        public static Mesh Build(Mesh src, int seed = 3, float boundsPadding = 3f)
        {
            var rnd = new System.Random(seed);
            var sv = src.vertices; var sn = src.normals; var suv = src.uv; var tris = src.triangles;
            int n = tris.Length;
            var v = new Vector3[n]; var nr = new Vector3[n]; var uv = new Vector2[n];
            var uv1 = new Vector4[n]; var uv2 = new Vector4[n]; var idx = new int[n];
            for (int t = 0; t < n; t += 3)
            {
                Vector3 a = sv[tris[t]], b = sv[tris[t + 1]], c = sv[tris[t + 2]];
                Vector3 center = (a + b + c) / 3f;
                Vector3 face = Vector3.Cross(b - a, c - a).normalized;     // Unity 的绕序下这就是朝外的面法线
                float r = (float)rnd.NextDouble();
                for (int k = 0; k < 3; k++)
                {
                    int i = t + k, s = tris[i];
                    v[i] = sv[s]; nr[i] = sn.Length > 0 ? sn[s] : face; uv[i] = suv.Length > 0 ? suv[s] : Vector2.zero;
                    uv1[i] = new Vector4(center.x, center.y, center.z, r);
                    uv2[i] = new Vector4(face.x, face.y, face.z, 0);
                    idx[i] = i;
                }
            }
            var m = new Mesh { name = src.name + "_Shatter", indexFormat = IndexFormat.UInt32 };
            m.vertices = v; m.normals = nr; m.uv = uv; m.SetUVs(1, uv1); m.SetUVs(2, uv2); m.triangles = idx;
            m.RecalculateBounds();
            var bounds = m.bounds; bounds.Expand(boundsPadding);   // 碎片会飞出原包围盒
            m.bounds = bounds;
            return m;
        }
    }
}