You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
5.7 KiB
C#

/******************************************************************************/
/*
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;
}
}
}