Oto faktyczny przykład działania AABB, który pochodzi bezpośrednio z mojego silnika gry:
using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace GrimoireEngine.Framework.Maths
{
public struct BoundingBox : IEquatable<BoundingBox>
{
public Vector3 Min;
public Vector3 Max;
public const int CornerCount = 8;
public static Vector3 MaxVector3
{
get
{
return new Vector3(float.MaxValue);
}
}
public static Vector3 MinVector3
{
get
{
return new Vector3(float.MinValue);
}
}
public static BoundingBox Identity
{
get
{
return new BoundingBox(Vector3.Zero, Vector3.One);
}
}
public static BoundingBox Zero
{
get
{
return new BoundingBox();
}
}
public BoundingBox(Vector3 min, Vector3 max)
{
Min = min;
Max = max;
}
public BoundingBox(
float minX, float minY, float minZ,
float maxX, float maxY, float maxZ)
: this(
new Vector3(minX, minY, minZ),
new Vector3(maxX, maxY, maxZ))
{ }
public bool Collides(BoundingBox box)
{
if (box.Max.X < Min.X
|| box.Min.X > Max.X
|| box.Max.Y < Min.Y
|| box.Min.Y > Max.Y
|| box.Max.Z < Min.Z
|| box.Min.Z > Max.Z)
{
return false;
}
if (box.Min.X >= Min.X
&& box.Max.X <= Max.X
&& box.Min.Y >= Min.Y
&& box.Max.Y <= Max.Y
&& box.Min.Z >= Min.Z
&& box.Max.Z <= Max.Z)
{
return true;
}
return true;
}
public ContainmentType Contains(BoundingBox box)
{
if (box.Max.X < Min.X
|| box.Min.X > Max.X
|| box.Max.Y < Min.Y
|| box.Min.Y > Max.Y
|| box.Max.Z < Min.Z
|| box.Min.Z > Max.Z)
{
return ContainmentType.Disjoint;
}
if (box.Min.X >= Min.X
&& box.Max.X <= Max.X
&& box.Min.Y >= Min.Y
&& box.Max.Y <= Max.Y
&& box.Min.Z >= Min.Z
&& box.Max.Z <= Max.Z)
{
return ContainmentType.Contains;
}
return ContainmentType.Intersects;
}
public bool Collides(BoundingFrustum frustum)
{
int i;
bool contained;
Vector3[] corners = frustum.GetCorners();
for (i = 0; i < corners.Length; i++)
{
if (corners[i].X < Min.X
|| corners[i].X > Max.X
|| corners[i].Y < Min.Y
|| corners[i].Y > Max.Y
|| corners[i].Z < Min.Z
|| corners[i].Z > Max.Z)
{
contained = false;
}
else if (corners[i].X == Min.X
|| corners[i].X == Max.X
|| corners[i].Y == Min.Y
|| corners[i].Y == Max.Y
|| corners[i].Z == Min.Z
|| corners[i].Z == Max.Z)
{
contained = true;
}
else
{
contained = true;
}
if (contained == false)
{
break;
}
}
if (i == corners.Length)
{
return true;
}
if (i != 0)
{
return true;
}
i++;
for (; i < corners.Length; i++)
{
if (corners[i].X < Min.X
|| corners[i].X > Max.X
|| corners[i].Y < Min.Y
|| corners[i].Y > Max.Y
|| corners[i].Z < Min.Z
|| corners[i].Z > Max.Z)
{
contained = false;
}
else if (corners[i].X == Min.X
|| corners[i].X == Max.X
|| corners[i].Y == Min.Y
|| corners[i].Y == Max.Y
|| corners[i].Z == Min.Z
|| corners[i].Z == Max.Z)
{
contained = true;
}
else
{
contained = true;
}
if (contained != true)
{
return true;
}
}
return true;
}
public ContainmentType Contains(BoundingFrustum frustum)
{
int i;
ContainmentType contained;
Vector3[] corners = frustum.GetCorners();
for (i = 0; i < corners.Length; i++)
{
if (corners[i].X < Min.X
|| corners[i].X > Max.X
|| corners[i].Y < Min.Y
|| corners[i].Y > Max.Y
|| corners[i].Z < Min.Z
|| corners[i].Z > Max.Z)
{
contained = ContainmentType.Disjoint;
}
else if (corners[i].X == Min.X
|| corners[i].X == Max.X
|| corners[i].Y == Min.Y
|| corners[i].Y == Max.Y
|| corners[i].Z == Min.Z
|| corners[i].Z == Max.Z)
{
contained = ContainmentType.Intersects;
}
else
{
contained = ContainmentType.Contains;
}
if (contained == ContainmentType.Disjoint)
{
break;
}
}
if (i == corners.Length)
{
return ContainmentType.Contains;
}
if (i != 0)
{
return ContainmentType.Intersects;
}
i++;
for (; i < corners.Length; i++)
{
if (corners[i].X < Min.X
|| corners[i].X > Max.X
|| corners[i].Y < Min.Y
|| corners[i].Y > Max.Y
|| corners[i].Z < Min.Z
|| corners[i].Z > Max.Z)
{
contained = ContainmentType.Disjoint;
}
else if (corners[i].X == Min.X
|| corners[i].X == Max.X
|| corners[i].Y == Min.Y
|| corners[i].Y == Max.Y
|| corners[i].Z == Min.Z
|| corners[i].Z == Max.Z)
{
contained = ContainmentType.Intersects;
}
else
{
contained = ContainmentType.Contains;
}
if (contained != ContainmentType.Contains)
{
return ContainmentType.Intersects;
}
}
return ContainmentType.Contains;
}
public bool Collides(BoundingSphere sphere)
{
if (sphere.Center.X - Min.X >= sphere.Radius
&& sphere.Center.Y - Min.Y >= sphere.Radius
&& sphere.Center.Z - Min.Z >= sphere.Radius
&& Max.X - sphere.Center.X >= sphere.Radius
&& Max.Y - sphere.Center.Y >= sphere.Radius
&& Max.Z - sphere.Center.Z >= sphere.Radius)
{
return true;
}
double dmin = 0;
double e = sphere.Center.X - Min.X;
if (e < 0)
{
if (e < -sphere.Radius)
{
return false;
}
dmin += e * e;
}
else
{
e = sphere.Center.X - Max.X;
if (e > 0)
{
if (e > sphere.Radius)
{
return false;
}
dmin += e * e;
}
}
e = sphere.Center.Y - Min.Y;
if (e < 0)
{
if (e < -sphere.Radius)
{
return false;
}
dmin += e * e;
}
else
{
e = sphere.Center.Y - Max.Y;
if (e > 0)
{
if (e > sphere.Radius)
{
return false;
}
dmin += e * e;
}
}
e = sphere.Center.Z - Min.Z;
if (e < 0)
{
if (e < -sphere.Radius)
{
return false;
}
dmin += e * e;
}
else
{
e = sphere.Center.Z - Max.Z;
if (e > 0)
{
if (e > sphere.Radius)
{
return false;
}
dmin += e * e;
}
}
return dmin <= sphere.Radius * sphere.Radius;
}
public ContainmentType Contains(BoundingSphere sphere)
{
if (sphere.Center.X - Min.X >= sphere.Radius
&& sphere.Center.Y - Min.Y >= sphere.Radius
&& sphere.Center.Z - Min.Z >= sphere.Radius
&& Max.X - sphere.Center.X >= sphere.Radius
&& Max.Y - sphere.Center.Y >= sphere.Radius
&& Max.Z - sphere.Center.Z >= sphere.Radius)
{
return ContainmentType.Contains;
}
double dmin = 0;
double e = sphere.Center.X - Min.X;
if (e < 0)
{
if (e < -sphere.Radius)
{
return ContainmentType.Disjoint;
}
dmin += e * e;
}
else
{
e = sphere.Center.X - Max.X;
if (e > 0)
{
if (e > sphere.Radius)
{
return ContainmentType.Disjoint;
}
dmin += e * e;
}
}
e = sphere.Center.Y - Min.Y;
if (e < 0)
{
if (e < -sphere.Radius)
{
return ContainmentType.Disjoint;
}
dmin += e * e;
}
else
{
e = sphere.Center.Y - Max.Y;
if (e > 0)
{
if (e > sphere.Radius)
{
return ContainmentType.Disjoint;
}
dmin += e * e;
}
}
e = sphere.Center.Z - Min.Z;
if (e < 0)
{
if (e < -sphere.Radius)
{
return ContainmentType.Disjoint;
}
dmin += e * e;
}
else
{
e = sphere.Center.Z - Max.Z;
if (e > 0)
{
if (e > sphere.Radius)
{
return ContainmentType.Disjoint;
}
dmin += e * e;
}
}
return dmin <= sphere.Radius * sphere.Radius ? ContainmentType.Intersects : ContainmentType.Disjoint;
}
public bool Collides(Vector3 point)
{
if (point.X < Min.X
|| point.X > Max.X
|| point.Y < Min.Y
|| point.Y > Max.Y
|| point.Z < Min.Z
|| point.Z > Max.Z)
{
return false;
}
if (point.X == Min.X
|| point.X == Max.X
|| point.Y == Min.Y
|| point.Y == Max.Y
|| point.Z == Min.Z
|| point.Z == Max.Z)
{
return true;
}
return true;
}
public ContainmentType Contains(Vector3 point)
{
ContainmentType result;
if (point.X < Min.X
|| point.X > Max.X
|| point.Y < Min.Y
|| point.Y > Max.Y
|| point.Z < Min.Z
|| point.Z > Max.Z)
{
result = ContainmentType.Disjoint;
}
else if (point.X == Min.X
|| point.X == Max.X
|| point.Y == Min.Y
|| point.Y == Max.Y
|| point.Z == Min.Z
|| point.Z == Max.Z)
{
result = ContainmentType.Intersects;
}
else
{
result = ContainmentType.Contains;
}
return result;
}
public bool Equals(BoundingBox other)
{
return (Min == other.Min) && (Max == other.Max);
}
public override bool Equals(object obj)
{
return (obj is BoundingBox) && Equals((BoundingBox)obj);
}
public Vector3[] GetCorners()
{
return new[] {
new Vector3(Min.X, Max.Y, Max.Z),
new Vector3(Max.X, Max.Y, Max.Z),
new Vector3(Max.X, Min.Y, Max.Z),
new Vector3(Min.X, Min.Y, Max.Z),
new Vector3(Min.X, Max.Y, Min.Z),
new Vector3(Max.X, Max.Y, Min.Z),
new Vector3(Max.X, Min.Y, Min.Z),
new Vector3(Min.X, Min.Y, Min.Z)
};
}
public override int GetHashCode()
{
return Min.GetHashCode() + Max.GetHashCode();
}
public bool Intersects(BoundingBox box)
{
if ((Max.X >= box.Min.X) && (Min.X <= box.Max.X))
{
if ((Max.Y < box.Min.Y) || (Min.Y > box.Max.Y))
{
return false;
}
return (Max.Z >= box.Min.Z) && (Min.Z <= box.Max.Z);
}
return false;
}
public bool Intersects(BoundingFrustum frustum)
{
return frustum.Intersects(this);
}
public bool Intersects(BoundingSphere sphere)
{
if (sphere.Center.X - Min.X > sphere.Radius
&& sphere.Center.Y - Min.Y > sphere.Radius
&& sphere.Center.Z - Min.Z > sphere.Radius
&& Max.X - sphere.Center.X > sphere.Radius
&& Max.Y - sphere.Center.Y > sphere.Radius
&& Max.Z - sphere.Center.Z > sphere.Radius)
{
return true;
}
double dmin = 0;
if (sphere.Center.X - Min.X <= sphere.Radius)
{
dmin += (sphere.Center.X - Min.X) * (sphere.Center.X - Min.X);
}
else if (Max.X - sphere.Center.X <= sphere.Radius)
{
dmin += (sphere.Center.X - Max.X) * (sphere.Center.X - Max.X);
}
if (sphere.Center.Y - Min.Y <= sphere.Radius)
{
dmin += (sphere.Center.Y - Min.Y) * (sphere.Center.Y - Min.Y);
}
else if (Max.Y - sphere.Center.Y <= sphere.Radius)
{
dmin += (sphere.Center.Y - Max.Y) * (sphere.Center.Y - Max.Y);
}
if (sphere.Center.Z - Min.Z <= sphere.Radius)
{
dmin += (sphere.Center.Z - Min.Z) * (sphere.Center.Z - Min.Z);
}
else if (Max.Z - sphere.Center.Z <= sphere.Radius)
{
dmin += (sphere.Center.Z - Max.Z) * (sphere.Center.Z - Max.Z);
}
return dmin <= sphere.Radius * sphere.Radius;
}
public PlaneIntersectionType Intersects(Plane plane)
{
Vector3 positiveVertex;
Vector3 negativeVertex;
if (plane.Normal.X >= 0)
{
positiveVertex.X = Max.X;
negativeVertex.X = Min.X;
}
else
{
positiveVertex.X = Min.X;
negativeVertex.X = Max.X;
}
if (plane.Normal.Y >= 0)
{
positiveVertex.Y = Max.Y;
negativeVertex.Y = Min.Y;
}
else
{
positiveVertex.Y = Min.Y;
negativeVertex.Y = Max.Y;
}
if (plane.Normal.Z >= 0)
{
positiveVertex.Z = Max.Z;
negativeVertex.Z = Min.Z;
}
else
{
positiveVertex.Z = Min.Z;
negativeVertex.Z = Max.Z;
}
float distance = plane.Normal.X * negativeVertex.X + plane.Normal.Y * negativeVertex.Y + plane.Normal.Z * negativeVertex.Z + plane.D;
if (distance > 0)
{
return PlaneIntersectionType.Front;
}
distance = plane.Normal.X * positiveVertex.X + plane.Normal.Y * positiveVertex.Y + plane.Normal.Z * positiveVertex.Z + plane.D;
if (distance < 0)
{
return PlaneIntersectionType.Back;
}
return PlaneIntersectionType.Intersecting;
}
public float? Intersects(Ray ray)
{
return ray.Intersects(this);
}
public static bool operator ==(BoundingBox a, BoundingBox b)
{
return a.Equals(b);
}
public static bool operator !=(BoundingBox a, BoundingBox b)
{
return !a.Equals(b);
}
public override string ToString()
{
return "{{Min:" + Min + " Max:" + Max + "}}";
}
public void DrawImmediate()
{
GL.Begin(PrimitiveType.LineLoop);
GL.Vertex3(Max.X, Max.Y, Min.Z);
GL.Vertex3(Min.X, Max.Y, Min.Z);
GL.Vertex3(Min.X, Min.Y, Min.Z);
GL.Vertex3(Max.X, Min.Y, Min.Z);
GL.End();
GL.Begin(PrimitiveType.LineLoop);
GL.Vertex3(Max.X, Min.Y, Max.Z);
GL.Vertex3(Max.X, Max.Y, Max.Z);
GL.Vertex3(Min.X, Max.Y, Max.Z);
GL.Vertex3(Min.X, Min.Y, Max.Z);
GL.End();
GL.Begin(PrimitiveType.LineLoop);
GL.Vertex3(Max.X, Max.Y, Min.Z);
GL.Vertex3(Max.X, Max.Y, Max.Z);
GL.Vertex3(Min.X, Max.Y, Max.Z);
GL.Vertex3(Min.X, Max.Y, Min.Z);
GL.End();
GL.Begin(PrimitiveType.LineLoop);
GL.Vertex3(Max.X, Min.Y, Max.Z);
GL.Vertex3(Min.X, Min.Y, Max.Z);
GL.Vertex3(Min.X, Min.Y, Min.Z);
GL.Vertex3(Max.X, Min.Y, Min.Z);
GL.End();
}
}
}
Wystarczy usunąć inne metody typu Bounding.