// Copyright (c) 2014-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2010-2014 SharpDX - Alexandre Mutel #pragma once #include "Vector3.h" #include "Matrix.h" #include "CollisionsHelper.h" // Oriented Bounding Box (OBB) is a rectangular block, much like an AABB (Bounding Box) but with an arbitrary orientation in 3D space. API_STRUCT(InBuild) struct FLAXENGINE_API OrientedBoundingBox { public: // Half lengths of the box along each axis. Vector3 Extents; // The matrix which aligns and scales the box, and its translation vector represents the center of the box. Matrix Transformation; public: /// /// Empty constructor. /// OrientedBoundingBox() { } // Init // @param bb The BoundingBox to create from OrientedBoundingBox(const BoundingBox& bb); // Init // @param extents The half lengths of the box along each axis. // @param transformation The matrix which aligns and scales the box, and its translation vector represents the center of the box. OrientedBoundingBox(const Vector3& extents, const Matrix& transformation) { Extents = extents; Transformation = transformation; } OrientedBoundingBox(const Vector3& extents, const Matrix3x3& rotationScale, const Vector3& translation); // Init // @param minimum The minimum vertex of the bounding box. // @param maximum The maximum vertex of the bounding box. OrientedBoundingBox(const Vector3& minimum, const Vector3& maximum) { const Vector3 center = minimum + (maximum - minimum) / 2.0f; Extents = maximum - center; Matrix::Translation(center, Transformation); } // Init // @param points The points that will be contained by the box. // @param pointCount Amount of the points in th array. OrientedBoundingBox(Vector3 points[], int32 pointCount); public: String ToString() const; public: // Gets the eight corners of the bounding box. void GetCorners(Vector3 corners[8]) const; // The size of the OBB if no scaling is applied to the transformation matrix. Vector3 GetSizeUnscaled() const { return Extents * 2.0f; } // Returns the size of the OBB taking into consideration the scaling applied to the transformation matrix. Vector3 GetSize() const; // Returns the square size of the OBB taking into consideration the scaling applied to the transformation matrix. // @returns The size of the consideration. Vector3 GetSizeSquared() const; // Gets the center of the OBB. Vector3 GetCenter() const { return Transformation.GetTranslation(); } /// /// Gets the AABB which contains all OBB corners. /// /// The result BoundingBox GetBoundingBox() const; /// /// Gets the AABB which contains all OBB corners. /// /// The result. void GetBoundingBox(BoundingBox& result) const; public: // Transforms this box using a transformation matrix. // @param mat The transformation matrix. void Transform(const Matrix& matrix); // Scales the OBB by scaling its Extents without affecting the Transformation matrix. // By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. // @param scaling Scale to apply to the box. void Scale(const Vector3& scaling) { Extents *= scaling; } // Scales the OBB by scaling its Extents without affecting the Transformation matrix. // By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. // @param scaling Scale to apply to the box. void Scale(float scaling) { Extents *= scaling; } // Translates the OBB to a new position using a translation vector. // @param translation the translation vector. void Translate(const Vector3& translation) { Transformation.SetTranslation(Transformation.GetTranslation() + translation); } public: FORCE_INLINE bool operator==(const OrientedBoundingBox& other) const { return Extents == other.Extents && Transformation == other.Transformation; } FORCE_INLINE bool operator!=(const OrientedBoundingBox& other) const { return Extents != other.Extents || Transformation != other.Transformation; } FORCE_INLINE OrientedBoundingBox operator*(const Matrix& matrix) const { OrientedBoundingBox result = *this; result.Transform(matrix); return result; } private: static void GetRows(const Matrix& mat, Vector3 rows[3]) { rows[0] = Vector3(mat.M11, mat.M12, mat.M13); rows[1] = Vector3(mat.M21, mat.M22, mat.M23); rows[2] = Vector3(mat.M31, mat.M32, mat.M33); } public: /// /// Creates the centered box (axis aligned). /// /// The center. /// The size. /// The result. static void CreateCentered(const Vector3& center, const Vector3& size, OrientedBoundingBox& result) { result.Extents = size / 2.0f; Matrix::Translation(center, result.Transformation); } /// /// Creates the centered box (axis-aligned). /// /// The center. /// The size. /// The result. static OrientedBoundingBox CreateCentered(const Vector3& center, const Vector3& size) { OrientedBoundingBox result; result.Extents = size / 2.0f; Matrix::Translation(center, result.Transformation); return result; } public: // Determines whether a OBB contains a point. // @param point The point to test. // @returns The type of containment the two objects have. ContainmentType Contains(const Vector3& point, float* distance = nullptr) const; // Determines whether a OBB contains an array of points. // @param pointsCnt Amount of points to test. // @param points The points array to test. // @returns The type of containment. ContainmentType Contains(int32 pointsCnt, Vector3 points[]) const; // Determines whether a OBB contains a BoundingSphere. // @param sphere The sphere to test. // @param ignoreScale Optimize the check operation by assuming that OBB has no scaling applied. // @returns The type of containment the two objects have. ContainmentType Contains(const BoundingSphere& sphere, bool ignoreScale = false) const; // Determines whether there is an intersection between a Ray and a OBB. // @param ray The ray to test. // @param point When the method completes, contains the point of intersection, or Vector3.Zero if there was no intersection. // @returns Whether the two objects intersected. bool Intersects(const Ray& ray, Vector3& point) const; // Determines if there is an intersection between the current object and a Ray. // @param ray The ray to test. // @param distance When the method completes, contains the distance of the intersection, or 0 if there was no intersection. // @returns Whether the two objects intersected. bool Intersects(const Ray& ray, float& distance) const; // Determines if there is an intersection between the current object and a Ray. // @param ray The ray to test. // @param distance When the method completes, contains the distance of the intersection, or 0 if there was no intersection. // @param normal When the method completes, contains the intersection surface normal vector, or Vector3::Up if there was no intersection. // @returns Whether the two objects intersected. bool Intersects(const Ray& ray, float& distance, Vector3& normal) const; // Determines whether there is an intersection between a Ray and a OBB. // @param ray The ray to test. // @returns Whether the two objects intersected. bool Intersects(const Ray& ray) const { Vector3 point; return Intersects(ray, point); } }; template<> struct TIsPODType { enum { Value = true }; }; DEFINE_DEFAULT_FORMATTING(OrientedBoundingBox, "Center: {0}, Size: {1}", v.GetCenter(), v.GetSize());