quality-control/Assets/Plugins/Interaction/Runtime/Utils/BoundsUtils.cs

113 lines
3.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Nothke.Utils
{
public static class BoundsUtils
{
// static list for caching, never deallocates
static List<Collider> colliderCache = new List<Collider>();
public static Bounds GetObjectSpaceColliderBounds(GameObject go, bool includeInactive = false)
{
Transform t = go.transform;
var rootW2L = t.worldToLocalMatrix;
go.GetComponentsInChildren(includeInactive, colliderCache);
if (colliderCache.Count == 0)
{
Debug.LogError("Attempting to get bounds of the object but it has no colliders");
return default;
}
Bounds goBounds = GetBoundsInRootSpace(colliderCache[0]);
for (int i = 1; i < colliderCache.Count; i++)
{
Bounds b = GetBoundsInRootSpace(colliderCache[i]);
goBounds.Encapsulate(b);
}
return goBounds;
Bounds GetBoundsInRootSpace(Collider col)
{
Bounds b = col.GetLocalBounds();
Matrix4x4 l2w = col.transform.localToWorldMatrix;
Matrix4x4 local = rootW2L * l2w;
return TransformBounds(local, b);
}
}
public static Bounds GetLocalBounds(this Collider collider)
{
if (collider is BoxCollider)
{
BoxCollider box = (BoxCollider)collider;
return new Bounds(box.center, box.size);
}
else if (collider is SphereCollider)
{
var center = ((SphereCollider)collider).center;
var radius = ((SphereCollider)collider).radius;
Vector3 size = new Vector3(radius * 2, radius * 2, radius * 2);
return new Bounds(center, size);
}
else if (collider is CapsuleCollider)
{
var capsule = (CapsuleCollider)collider;
var r = capsule.radius;
var h = capsule.height;
Vector3 size;
switch (capsule.direction)
{
case 0: size = new Vector3(h, r * 2, r * 2); break;
case 1: size = new Vector3(r * 2, h, r * 2); break;
case 2: size = new Vector3(r * 2, r * 2, h); break;
default: size = default; break;
}
return new Bounds(capsule.center, size);
}
else if (collider is MeshCollider)
{
return ((MeshCollider)collider).sharedMesh.bounds;
}
Debug.LogError("Attempting to get bounds of an unknown collider type");
return new Bounds();
}
public static Bounds TransformBounds(in Matrix4x4 mat, in Bounds bounds)
{
// Find 8 corners of the bounds
Vector3 p0 = bounds.min;
Vector3 p1 = bounds.max;
Vector3 p2 = new Vector3(p0.x, p0.y, p1.z);
Vector3 p3 = new Vector3(p0.x, p1.y, p0.z);
Vector3 p4 = new Vector3(p1.x, p0.y, p0.z);
Vector3 p5 = new Vector3(p0.x, p1.y, p1.z);
Vector3 p6 = new Vector3(p1.x, p0.y, p1.z);
Vector3 p7 = new Vector3(p1.x, p1.y, p0.z);
Bounds b = new Bounds(mat * p0, Vector3.zero);
b.Encapsulate(mat * p1);
b.Encapsulate(mat * p2);
b.Encapsulate(mat * p3);
b.Encapsulate(mat * p4);
b.Encapsulate(mat * p5);
b.Encapsulate(mat * p6);
b.Encapsulate(mat * p7);
return b;
}
public static void DrawBoundsGizmos(in Bounds bounds)
{
Gizmos.DrawWireCube(bounds.center, bounds.size);
}
}
}