using UnityEngine; namespace ConformalDecals.Util { public struct OrientedBounds { private Bounds _localBounds; public Bounds LocalBounds { get => _localBounds; set => _localBounds = value; } public Vector3 Center { get => _localBounds.center; set => _localBounds.center = value; } public Vector3 Extents { get => _localBounds.extents; set => _localBounds.extents = value; } public Vector3 Min { get => _localBounds.min; set => _localBounds.min = value; } public Vector3 Max { get => _localBounds.max; set => _localBounds.max = value; } public Vector3 Size { get => _localBounds.size; set => _localBounds.size = value; } public Vector3 UnitX { get => OrientationMatrix.GetColumn(0); private set => OrientationMatrix.SetColumn(0, value); } public Vector3 UnitY { get => OrientationMatrix.GetColumn(1); private set => OrientationMatrix.SetColumn(1, value); } public Vector3 UnitZ { get => OrientationMatrix.GetColumn(2); private set => OrientationMatrix.SetColumn(2, value); } public Matrix4x4 OrientationMatrix { get; private set; } public OrientedBounds(Matrix4x4 matrix, Bounds aabb) { Vector3 unitX = matrix.GetColumn(0); Vector3 unitY = matrix.GetColumn(1); Vector3 unitZ = matrix.GetColumn(2); var scale = new Vector3(unitX.magnitude, unitY.magnitude, unitZ.magnitude); _localBounds = new Bounds { center = matrix.MultiplyPoint3x4(aabb.center), extents = new Vector3(aabb.extents.x / scale.x, aabb.extents.y / scale.y, aabb.extents.z / scale.z) }; OrientationMatrix = Matrix4x4.zero; UnitX = unitX / scale.x; UnitY = unitY / scale.y; UnitZ = unitZ / scale.z; } public bool Contains(Vector3 point) { var delta = point - Center; var localPoint = Center + OrientationMatrix.transpose.MultiplyVector(delta); return _localBounds.Contains(localPoint); } public bool Intersects(OrientedBounds other) { // OrientationMatrix should always be orthogonal, // so we can cheat and use the transpose for the inverse var inverseOrientationMatrix = OrientationMatrix.transpose; // matrix expressing other in our coordinate frame var R = inverseOrientationMatrix * other.OrientationMatrix; // compute translation vector t in our coordinate frame var t = inverseOrientationMatrix.MultiplyVector(other.Center - Center); return IntersectOBBSeperatingAxis(R, t, Extents, other.Extents); } public bool Intersects(Bounds other) { // matrix expressing other in our coordinate frame var R = OrientationMatrix.transpose; // compute translation vector t in our coordinate frame var t = R.MultiplyVector(other.center - Center); return IntersectOBBSeperatingAxis(R, t, Extents, other.extents); } private static bool IntersectOBBSeperatingAxis(Matrix4x4 R, Vector3 t, Vector3 a, Vector3 b) { // Compute common subexpressions. Add in an epsilon term to // counteract arithmetic errors when two edges are parallel and // their cross product is (near) null var absR = R; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { absR[i, j] = Mathf.Abs(R[i, j]) + Mathf.Epsilon; } } float ra, rb; // Test axes L = A0, L = A1, L = A2 for (int i = 0; i < 3; i++) { ra = a[i]; rb = b[0] * absR[i, 0] + b[1] * absR[i, 1] + b[2] * absR[i, 2]; if (Mathf.Abs(t[i]) > ra + rb) return false; } // Test axes L = B0, L = B1, L = B2 for (int i = 0; i < 3; i++) { ra = a[0] * absR[0, i] + a[1] * absR[1, i] + a[2] * absR[2, i]; rb = b[i]; if (Mathf.Abs(t[0] * R[0, i] + t[1] * R[1, i] + t[2] * R[2, i]) > ra + rb) return false; } // Test axis L = A0 x B0 ra = a[1] * absR[2, 0] + a[2] * absR[1, 0]; rb = b[1] * absR[0, 2] + b[2] * absR[0, 1]; if (Mathf.Abs(t[2] * R[1, 0] - t[1] * R[2, 0]) > ra + rb) return false; // Test axis L = A0 x B1 ra = a[1] * absR[2, 1] + a[2] * absR[1, 1]; rb = b[0] * absR[0, 2] + b[2] * absR[0, 0]; if (Mathf.Abs(t[2] * R[1, 1] - t[1] * R[2, 1]) > ra + rb) return false; // Test axis L = A0 x B2 ra = a[1] * absR[2, 2] + a[2] * absR[1, 2]; rb = b[0] * absR[0, 1] + b[1] * absR[0, 0]; if (Mathf.Abs(t[2] * R[1, 2] - t[1] * R[2, 2]) > ra + rb) return false; // Test axis L = A1 x B0 ra = a[0] * absR[2, 0] + a[2] * absR[0, 0]; rb = b[1] * absR[1, 2] + b[2] * absR[1, 1]; if (Mathf.Abs(t[0] * R[2, 0] - t[2] * R[0, 0]) > ra + rb) return false; // Test axis L = A1 x B1 ra = a[0] * absR[2, 1] + a[2] * absR[0, 1]; rb = b[0] * absR[1, 2] + b[2] * absR[1, 0]; if (Mathf.Abs(t[0] * R[2, 1] - t[2] * R[0, 1]) > ra + rb) return false; // Test axis L = A1 x B2 ra = a[0] * absR[2, 2] + a[2] * absR[0, 2]; rb = b[0] * absR[1, 1] + b[1] * absR[1, 0]; if (Mathf.Abs(t[2] * R[1, 2] - t[1] * R[2, 2]) > ra + rb) return false; // Test axis L = A2 x B0 ra = a[0] * absR[1, 0] + a[1] * absR[0, 1]; rb = b[1] * absR[2, 2] + b[2] * absR[2, 1]; if (Mathf.Abs(t[1] * R[0, 0] - t[0] * R[1, 0]) > ra + rb) return false; // Test axis L = A2 x B1 ra = a[0] * absR[1, 1] + a[1] * absR[0, 1]; rb = b[0] * absR[2, 2] + b[2] * absR[2, 0]; if (Mathf.Abs(t[1] * R[0, 1] - t[0] * R[1, 1]) > ra + rb) return false; // Test axis L = A2 x B2 ra = a[0] * absR[1, 2] + a[1] * absR[0, 2]; rb = b[0] * absR[2, 1] + b[1] * absR[2, 0]; if (Mathf.Abs(t[1] * R[0, 2] - t[0] * R[1, 2]) > ra + rb) return false; // Since no separating axis is found, the OBBs must be intersecting return true; } } }