123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #pragma once
- #include <Jolt/Geometry/Triangle.h>
- #include <Jolt/Geometry/IndexedTriangle.h>
- #include <Jolt/Geometry/Plane.h>
- #include <Jolt/Math/Mat44.h>
- JPH_NAMESPACE_BEGIN
- /// Axis aligned box
- class [[nodiscard]] AABox
- {
- public:
- JPH_OVERRIDE_NEW_DELETE
- /// Constructor
- AABox() : mMin(Vec3::sReplicate(FLT_MAX)), mMax(Vec3::sReplicate(-FLT_MAX)) { }
- AABox(Vec3Arg inMin, Vec3Arg inMax) : mMin(inMin), mMax(inMax) { }
- AABox(Vec3Arg inCenter, float inRadius) : mMin(inCenter - Vec3::sReplicate(inRadius)), mMax(inCenter + Vec3::sReplicate(inRadius)) { }
- /// Create box from 2 points
- static AABox sFromTwoPoints(Vec3Arg inP1, Vec3Arg inP2) { return AABox(Vec3::sMin(inP1, inP2), Vec3::sMax(inP1, inP2)); }
- /// Get bounding box of size 2 * FLT_MAX
- static AABox sBiggest()
- {
- return AABox(Vec3::sReplicate(-FLT_MAX), Vec3::sReplicate(FLT_MAX));
- }
- /// Comparison operators
- bool operator == (const AABox &inRHS) const { return mMin == inRHS.mMin && mMax == inRHS.mMax; }
- bool operator != (const AABox &inRHS) const { return mMin != inRHS.mMin || mMax != inRHS.mMax; }
- /// Reset the bounding box to an empty bounding box
- void SetEmpty()
- {
- mMin = Vec3::sReplicate(FLT_MAX);
- mMax = Vec3::sReplicate(-FLT_MAX);
- }
- /// Check if the bounding box is valid (max >= min)
- bool IsValid() const
- {
- return mMin.GetX() <= mMax.GetX() && mMin.GetY() <= mMax.GetY() && mMin.GetZ() <= mMax.GetZ();
- }
- /// Encapsulate point in bounding box
- void Encapsulate(Vec3Arg inPos)
- {
- mMin = Vec3::sMin(mMin, inPos);
- mMax = Vec3::sMax(mMax, inPos);
- }
- /// Encapsulate bounding box in bounding box
- void Encapsulate(const AABox &inRHS)
- {
- mMin = Vec3::sMin(mMin, inRHS.mMin);
- mMax = Vec3::sMax(mMax, inRHS.mMax);
- }
- /// Encapsulate triangle in bounding box
- void Encapsulate(const Triangle &inRHS)
- {
- Vec3 v = Vec3::sLoadFloat3Unsafe(inRHS.mV[0]);
- Encapsulate(v);
- v = Vec3::sLoadFloat3Unsafe(inRHS.mV[1]);
- Encapsulate(v);
- v = Vec3::sLoadFloat3Unsafe(inRHS.mV[2]);
- Encapsulate(v);
- }
- /// Encapsulate triangle in bounding box
- void Encapsulate(const VertexList &inVertices, const IndexedTriangle &inTriangle)
- {
- for (uint32 idx : inTriangle.mIdx)
- Encapsulate(Vec3(inVertices[idx]));
- }
- /// Intersect this bounding box with inOther, returns the intersection
- AABox Intersect(const AABox &inOther) const
- {
- return AABox(Vec3::sMax(mMin, inOther.mMin), Vec3::sMin(mMax, inOther.mMax));
- }
- /// Make sure that each edge of the bounding box has a minimal length
- void EnsureMinimalEdgeLength(float inMinEdgeLength)
- {
- Vec3 min_length = Vec3::sReplicate(inMinEdgeLength);
- mMax = Vec3::sSelect(mMax, mMin + min_length, Vec3::sLess(mMax - mMin, min_length));
- }
-
- /// Widen the box on both sides by inVector
- void ExpandBy(Vec3Arg inVector)
- {
- mMin -= inVector;
- mMax += inVector;
- }
- /// Get center of bounding box
- Vec3 GetCenter() const
- {
- return 0.5f * (mMin + mMax);
- }
- /// Get extent of bounding box (half of the size)
- Vec3 GetExtent() const
- {
- return 0.5f * (mMax - mMin);
- }
- /// Get size of bounding box
- Vec3 GetSize() const
- {
- return mMax - mMin;
- }
- /// Get surface area of bounding box
- float GetSurfaceArea() const
- {
- Vec3 extent = mMax - mMin;
- return 2.0f * (extent.GetX() * extent.GetY() + extent.GetX() * extent.GetZ() + extent.GetY() * extent.GetZ());
- }
- /// Get volume of bounding box
- float GetVolume() const
- {
- Vec3 extent = mMax - mMin;
- return extent.GetX() * extent.GetY() * extent.GetZ();
- }
- /// Check if this box contains another box
- bool Contains(const AABox &inOther) const
- {
- return UVec4::sAnd(Vec3::sLessOrEqual(mMin, inOther.mMin), Vec3::sGreaterOrEqual(mMax, inOther.mMax)).TestAllXYZTrue();
- }
- /// Check if this box contains a point
- bool Contains(Vec3Arg inOther) const
- {
- return UVec4::sAnd(Vec3::sLessOrEqual(mMin, inOther), Vec3::sGreaterOrEqual(mMax, inOther)).TestAllXYZTrue();
- }
- /// Check if this box overlaps with another box
- bool Overlaps(const AABox &inOther) const
- {
- return !UVec4::sOr(Vec3::sGreater(mMin, inOther.mMax), Vec3::sLess(mMax, inOther.mMin)).TestAnyXYZTrue();
- }
- /// Check if this box overlaps with a plane
- bool Overlaps(const Plane &inPlane) const
- {
- Vec3 normal = inPlane.GetNormal();
- float dist_normal = inPlane.SignedDistance(GetSupport(normal));
- float dist_min_normal = inPlane.SignedDistance(GetSupport(-normal));
- return dist_normal * dist_min_normal <= 0.0f; // If both support points are on the same side of the plane we don't overlap
- }
- /// Translate bounding box
- void Translate(Vec3Arg inTranslation)
- {
- mMin += inTranslation;
- mMax += inTranslation;
- }
- /// Transform bounding box
- AABox Transformed(Mat44Arg inMatrix) const
- {
- // Start with the translation of the matrix
- Vec3 new_min, new_max;
- new_min = new_max = inMatrix.GetTranslation();
-
- // Now find the extreme points by considering the product of the min and max with each column of inMatrix
- for (int c = 0; c < 3; ++c)
- {
- Vec3 col = inMatrix.GetColumn3(c);
- Vec3 a = col * mMin[c];
- Vec3 b = col * mMax[c];
- new_min += Vec3::sMin(a, b);
- new_max += Vec3::sMax(a, b);
- }
- // Return the new bounding box
- return AABox(new_min, new_max);
- }
- /// Scale this bounding box, can handle non-uniform and negative scaling
- AABox Scaled(Vec3Arg inScale) const
- {
- return AABox::sFromTwoPoints(mMin * inScale, mMax * inScale);
- }
- /// Calculate the support vector for this convex shape.
- Vec3 GetSupport(Vec3Arg inDirection) const
- {
- return Vec3::sSelect(mMax, mMin, Vec3::sLess(inDirection, Vec3::sZero()));
- }
- /// Get the vertices of the face that faces inDirection the most
- template <class VERTEX_ARRAY>
- void GetSupportingFace(Vec3Arg inDirection, VERTEX_ARRAY &outVertices) const
- {
- outVertices.resize(4);
- int axis = inDirection.Abs().GetHighestComponentIndex();
- if (inDirection[axis] < 0.0f)
- {
- switch (axis)
- {
- case 0:
- outVertices[0] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
- outVertices[1] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
- outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
- outVertices[3] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
- break;
- case 1:
- outVertices[0] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
- outVertices[1] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
- outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
- outVertices[3] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
- break;
- case 2:
- outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
- outVertices[1] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
- outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
- outVertices[3] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
- break;
- }
- }
- else
- {
- switch (axis)
- {
- case 0:
- outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
- outVertices[1] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
- outVertices[2] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
- outVertices[3] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
- break;
- case 1:
- outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
- outVertices[1] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
- outVertices[2] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
- outVertices[3] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
- break;
- case 2:
- outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
- outVertices[1] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
- outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
- outVertices[3] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
- break;
- }
- }
- }
- /// Get the closest point on or in this box to inPoint
- Vec3 GetClosestPoint(Vec3Arg inPoint) const
- {
- return Vec3::sMin(Vec3::sMax(inPoint, mMin), mMax);
- }
- /// Get the squared distance between inPoint and this box (will be 0 if in Point is inside the box)
- inline float GetSqDistanceTo(Vec3Arg inPoint) const
- {
- return (GetClosestPoint(inPoint) - inPoint).LengthSq();
- }
- /// Bounding box min and max
- Vec3 mMin;
- Vec3 mMax;
- };
- JPH_NAMESPACE_END
|