using System.Collections.Generic; using UnityEngine; /// Shared mesh/bounds/hierarchy helpers. public static class GeometryUtil { /// Depth-first hierarchy search by name; checks itself first. public static Transform FindDeep(Transform root, string name) { if (root.name == name) return root; for (int i = 0; i < root.childCount; i++) { var found = FindDeep(root.GetChild(i), name); if (found) return found; } return null; } /// Divides a world scale back out of a freshly baked mesh so it is true unit-scale local /// geometry (BakeMesh freezes the transform's lossyScale into the vertices). No-op at scale 1; /// is reused so nothing is allocated per bake. public static void RescaleToUnitScale(Mesh baked, Vector3 lossyScale, List scratch) { if (lossyScale.x == 1f && lossyScale.y == 1f && lossyScale.z == 1f) return; float ix = lossyScale.x != 0f ? 1f / lossyScale.x : 0f; float iy = lossyScale.y != 0f ? 1f / lossyScale.y : 0f; float iz = lossyScale.z != 0f ? 1f / lossyScale.z : 0f; baked.GetVertices(scratch); for (int i = 0; i < scratch.Count; i++) { Vector3 v = scratch[i]; v.x *= ix; v.y *= iy; v.z *= iz; scratch[i] = v; } baked.SetVertices(scratch); baked.RecalculateBounds(); } /// World AABB enclosing a local AABB after an affine transform (encapsulates the 8 transformed corners). public static Bounds TransformBounds(Matrix4x4 m, Bounds local) { Vector3 mn = local.min, mx = local.max; Vector3 c0 = m.MultiplyPoint3x4(mn); Bounds b = new Bounds(c0, Vector3.zero); b.Encapsulate(m.MultiplyPoint3x4(new Vector3(mx.x, mn.y, mn.z))); b.Encapsulate(m.MultiplyPoint3x4(new Vector3(mn.x, mx.y, mn.z))); b.Encapsulate(m.MultiplyPoint3x4(new Vector3(mn.x, mn.y, mx.z))); b.Encapsulate(m.MultiplyPoint3x4(new Vector3(mx.x, mx.y, mn.z))); b.Encapsulate(m.MultiplyPoint3x4(new Vector3(mx.x, mn.y, mx.z))); b.Encapsulate(m.MultiplyPoint3x4(new Vector3(mn.x, mx.y, mx.z))); b.Encapsulate(m.MultiplyPoint3x4(mx)); return b; } }