/******************************************************************************/ /* Project - MudBun Publisher - Long Bunny Labs http://LongBunnyLabs.com Author - Ming-Lun "Allen" Chou http://AllenChou.net */ /******************************************************************************/ using System; using System.Runtime.InteropServices; using UnityEngine; namespace MudBun { [StructLayout(LayoutKind.Sequential, Pack = 0)] [Serializable] public struct Aabb { public static readonly int Stride = 6 * sizeof(float); public Vector3 Min; public Vector3 Max; public static Aabb Union(Aabb a, Aabb b) { return new Aabb ( new Vector3 ( Mathf.Min(a.Min.x, b.Min.x), Mathf.Min(a.Min.y, b.Min.y), Mathf.Min(a.Min.z, b.Min.z) ), new Vector3 ( Mathf.Max(a.Max.x, b.Max.x), Mathf.Max(a.Max.y, b.Max.y), Mathf.Max(a.Max.z, b.Max.z) ) ); } public static bool Intersects(Aabb a, Aabb b) { return a.Min.x <= b.Max.x && a.Max.x >= b.Min.x && a.Min.y <= b.Max.y && a.Max.y >= b.Min.y && a.Min.z <= b.Max.z && a.Max.z >= b.Min.z; } private static readonly Aabb s_empty = new Aabb(float.MaxValue * Vector3.one, float.MinValue * Vector3.one); public static Aabb Empty => s_empty; public bool IsEmpty => (Min.x >= Max.x || Min.y >= Max.y || Min.z >= Max.z); public float HalfArea { get { Vector3 e = Max - Min; return e.x * e.y + e.y * e.z + e.z * e.x; } } public Vector3 Center => (0.5f * (Min + Max)); public Vector3 Size => (Max - Min); public Vector3 Extent => (0.5f * (Max - Min)); public Aabb(Vector3 min, Vector3 max) { Min = min; Max = max; } public void Include(Vector3 p) { Min.x = Mathf.Min(Min.x, p.x); Min.y = Mathf.Min(Min.y, p.y); Min.z = Mathf.Min(Min.z, p.z); Max.x = Mathf.Max(Max.x, p.x); Max.y = Mathf.Max(Max.y, p.y); Max.z = Mathf.Max(Max.z, p.z); } public void Include(Aabb aabb) { Min.x = Mathf.Min(Min.x, aabb.Min.x); Min.y = Mathf.Min(Min.y, aabb.Min.y); Min.z = Mathf.Min(Min.z, aabb.Min.z); Max.x = Mathf.Max(Max.x, aabb.Max.x); Max.y = Mathf.Max(Max.y, aabb.Max.y); Max.z = Mathf.Max(Max.z, aabb.Max.z); } public void Expand(float r) { Min.x -= r; Min.y -= r; Min.z -= r; Max.x += r; Max.y += r; Max.z += r; } public void Expand(Vector3 r) { Min.x -= r.x; Min.y -= r.y; Min.z -= r.z; Max.x += r.x; Max.y += r.y; Max.z += r.z; } public void Rotate(Quaternion q) { Vector3 oldExtents = Extent; Vector3 newExtents = Vector3.zero; newExtents = VectorUtil.Max(newExtents, VectorUtil.Abs(q * new Vector3( oldExtents.x, oldExtents.y, oldExtents.z))); newExtents = VectorUtil.Max(newExtents, VectorUtil.Abs(q * new Vector3(-oldExtents.x, oldExtents.y, oldExtents.z))); newExtents = VectorUtil.Max(newExtents, VectorUtil.Abs(q * new Vector3( oldExtents.x, -oldExtents.y, oldExtents.z))); newExtents = VectorUtil.Max(newExtents, VectorUtil.Abs(q * new Vector3( oldExtents.x, oldExtents.y, -oldExtents.z))); Vector3 newCenter = q * Center; Min = newCenter - newExtents; Max = newCenter + newExtents; } public void Transform(Transform transform) { Vector3 center = transform.TransformPoint(Center); Vector3 extent = VectorUtil.CompMul(Extent, transform.localScale); if (transform.parent != null) extent = VectorUtil.CompMul(extent, transform.parent.lossyScale); Min = -extent; Max = extent; Rotate(transform.rotation); Min += center; Max += center; } public bool Contains(Vector3 p) { return p.x >= Min.x && p.y >= Min.y && p.z >= Min.z && p.x <= Max.x && p.y <= Max.y && p.z <= Max.z; } public bool Contains(Aabb rhs) { return Min.x <= rhs.Min.x && Min.y <= rhs.Min.y && Min.z <= rhs.Min.z && Max.x >= rhs.Max.x && Max.y >= rhs.Max.y && Max.z >= rhs.Max.z; } // Real-time Collision Detection, p179. public float RayCast(Vector3 from, Vector3 to, float maxFraction = 1.0f) { float tMin = float.MinValue; float tMax = float.MaxValue; Vector3 d = to - from; Vector3 absD = VectorUtil.Abs(d); for (int i = 0; i < 3; ++i) { float dComp = VectorUtil.GetComopnent(d, i); float absDComp = VectorUtil.GetComopnent(absD, i); float fromComp = VectorUtil.GetComopnent(from, i); float minComp = VectorUtil.GetComopnent(Min, i); float maxComp = VectorUtil.GetComopnent(Max, i); if (absDComp < float.Epsilon) { // parallel? if (fromComp < minComp || maxComp < fromComp) return float.MinValue; } else { float invD = 1.0f / dComp; float t1 = (minComp - fromComp) * invD; float t2 = (maxComp - fromComp) * invD; if (t1 > t2) { float temp = t1; t1 = t2; t2 = temp; } tMin = Mathf.Max(tMin, t1); tMax = Mathf.Min(tMax, t2); if (tMin > tMax) return float.MinValue; } } // does the ray start inside the box? // does the ray intersect beyond the max fraction? if (tMin < 0.0f || maxFraction < tMin) return float.MinValue; // intersection detected return tMin; } } }