mirror of
https://github.com/nothke/quality-control.git
synced 2024-11-10 12:53:43 +00:00
113 lines
3.8 KiB
C#
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|