diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 60a97885..e001867a 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -106,7 +106,7 @@ Components: Transform Component: Translate: {x: 0, y: 5, z: 0} - Rotate: {x: -0, y: 0, z: -0} + Rotate: {x: -0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: @@ -130,8 +130,7 @@ DrawColliders: false Colliders: - Is Trigger: false - Type: Sphere - Radius: 1 + Type: Box Friction: 0.400000006 Bounciness: 0 Density: 1 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 622a2d37..cf5cdeb1 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -344,24 +344,24 @@ namespace SHADE //collider->IsTrigger if (shape->GetType() == SHCollisionShape::Type::BOX) { - //SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - // - //const auto* BOX = reinterpret_cast(collider->GetShape()); - //SHEditorWidgets::DragVec3 - //( - // "Half Extents", { "X", "Y", "Z" }, - // [BOX] { return BOX->GetRelativeExtents(); }, - // [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); + SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); + + auto* box = reinterpret_cast(shape); + SHEditorWidgets::DragVec3 + ( + "Half Extents", { "X", "Y", "Z" }, + [box] { return box->GetRelativeExtents(); }, + [box](SHVec3 const& vec) { box->SetRelativeExtents(vec); }); } else if (shape->GetType() == SHCollisionShape::Type::SPHERE) { SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto* SPHERE = reinterpret_cast(shape); + auto* sphere = reinterpret_cast(shape); SHEditorWidgets::DragFloat ( "Radius", - [SPHERE] { return SPHERE->GetRelativeRadius(); }, - [SPHERE](float const& value) { SPHERE->SetRelativeRadius(value); }); + [sphere] { return sphere->GetRelativeRadius(); }, + [sphere](float const& value) { sphere->SetRelativeRadius(value); }); } else if (shape->GetType() == SHCollisionShape::Type::CAPSULE) { @@ -410,7 +410,7 @@ namespace SHADE { if (ImGui::Selectable("Box Collider")) { - //component->AddBoundingBox(); + component->GetCollider()->AddBoxCollisionShape(SHVec3::One); } if (ImGui::Selectable("Sphere Collider")) { diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp index 8a44457f..30683216 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHBox.cpp + * \file SHAABB.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Implementation for a 3-Dimensional Axis Aligned Bounding Box * @@ -26,12 +26,12 @@ namespace SHADE SHAABB::SHAABB() noexcept { - type = Type::BOX; + type = Type::AABB; } SHAABB::SHAABB(const SHVec3& c, const SHVec3& hE) noexcept { - type = Type::BOX; + type = Type::AABB; Center = c; Extents = hE; @@ -43,7 +43,7 @@ namespace SHADE if (this == &rhs) return; - type = Type::BOX; + type = Type::AABB; Center = rhs.Center; Extents = rhs.Extents; @@ -51,7 +51,7 @@ namespace SHADE SHAABB::SHAABB(SHAABB&& rhs) noexcept { - type = Type::BOX; + type = Type::AABB; Center = rhs.Center; Extents = rhs.Extents; @@ -63,7 +63,7 @@ namespace SHADE SHAABB& SHAABB::operator=(const SHAABB& rhs) noexcept { - if (rhs.type != Type::BOX) + if (rhs.type != Type::AABB) { SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") } @@ -78,7 +78,7 @@ namespace SHADE SHAABB& SHAABB::operator=(SHAABB&& rhs) noexcept { - if (rhs.type != Type::BOX) + if (rhs.type != Type::AABB) { SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") } @@ -100,7 +100,7 @@ namespace SHADE return Center; } - SHVec3 SHAABB::GetWorldExtents() const noexcept + SHVec3 SHAABB::GetExtents() const noexcept { return Extents; } @@ -124,9 +124,9 @@ namespace SHADE Center = newCenter; } - void SHAABB::SetWorldExtents(const SHVec3& newWorldExtents) noexcept + void SHAABB::SetExtents(const SHVec3& newHalfExtents) noexcept { - Extents = newWorldExtents; + Extents = newHalfExtents; } void SHAABB::SetMin(const SHVec3& min) noexcept diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.h b/SHADE_Engine/src/Math/Geometry/SHAABB.h index 46608ded..76e0b2b7 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.h +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.h @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHBox.h + * \file SHAABB.h * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Interface for a 3-Dimensional Axis Aligned Bounding Box * @@ -54,21 +54,21 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] SHVec3 GetMin () const noexcept; - [[nodiscard]] SHVec3 GetMax () const noexcept; - [[nodiscard]] std::vector GetVertices () const noexcept; + [[nodiscard]] SHVec3 GetCenter () const noexcept; + [[nodiscard]] SHVec3 GetExtents () const noexcept; + [[nodiscard]] SHVec3 GetMin () const noexcept; + [[nodiscard]] SHVec3 GetMax () const noexcept; + [[nodiscard]] std::vector GetVertices () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCenter (const SHVec3& newCenter) noexcept; - void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; - void SetMin (const SHVec3& min) noexcept; - void SetMax (const SHVec3& max) noexcept; - void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; + void SetCenter (const SHVec3& newCenter) noexcept; + void SetExtents (const SHVec3& newHalfExtents) noexcept; + void SetMin (const SHVec3& min) noexcept; + void SetMax (const SHVec3& max) noexcept; + void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp new file mode 100644 index 00000000..9dacc623 --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHBox.cpp @@ -0,0 +1,169 @@ +/**************************************************************************************** + * \file SHBox.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a 3-Dimensional Oriented Bounding Box + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHBox.h" +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Math/SHRay.h" +#include "Math/SHQuaternion.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHBox::SHBox() noexcept + { + type = Type::BOX; + } + + SHBox::SHBox(const SHVec3& c, const SHVec3& hE, const SHQuaternion& o) noexcept + { + type = Type::BOX; + + Center = c; + Extents = hE; + Orientation = o; + } + + + SHBox::SHBox(const SHBox& rhs) noexcept + { + if (this == &rhs) + return; + + type = Type::BOX; + + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + } + + SHBox::SHBox(SHBox&& rhs) noexcept + { + type = Type::BOX; + + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHBox& SHBox::operator=(const SHBox& rhs) noexcept + { + if (rhs.type != Type::BOX) + { + SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") + } + else if (this != &rhs) + { + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + } + + return *this; + } + + SHBox& SHBox::operator=(SHBox&& rhs) noexcept + { + if (rhs.type != Type::BOX) + { + SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") + } + else + { + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + } + + return *this; + } + + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + std::vector SHBox::GetVertices() const noexcept + { + std::vector vertices; + vertices.resize(8); + GetCorners(vertices.data()); + return vertices; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHBox::TestPoint(const SHVec3& point) const noexcept + { + return BoundingOrientedBox::Contains(point); + } + + SHRaycastResult SHBox::Raycast(const SHRay& ray) const noexcept + { + SHRaycastResult result; + + result.hit = Intersects(ray.position, ray.direction, result.distance); + if (result.hit) + { + result.position = ray.position + ray.direction * result.distance; + result.angle = SHVec3::Angle(ray.position, result.position); + } + + return result; + } + + bool SHBox::Contains(const SHBox& rhs) const noexcept + { + return BoundingOrientedBox::Contains(rhs) == CONTAINS; + } + + float SHBox::Volume() const noexcept + { + return 8.0f * (Extents.x * Extents.y * Extents.z); + } + + float SHBox::SurfaceArea() const noexcept + { + return 8.0f * ((Extents.x * Extents.y) + + (Extents.x * Extents.z) + + (Extents.y * Extents.z)); + } + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept + { + return lhs.Intersects(rhs); + } + + SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept + { + SHBox result; + CreateFromPoints(result, numVertices, vertices, stride); + return result; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h new file mode 100644 index 00000000..bb1098bc --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHBox.h @@ -0,0 +1,135 @@ +/**************************************************************************************** + * \file SHBox.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a 3-Dimensional Oriented Bounding Box + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include + +// Project Headers +#include "SHShape.h" +#include "SH_API.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHBox : public SHShape, + public DirectX::BoundingOrientedBox + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr size_t NUM_VERTICES = 8; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + ~SHBox () override = default; + + SHBox () noexcept; + SHBox (const SHVec3& center, const SHVec3& halfExtents, const SHQuaternion& orientation) noexcept; + SHBox (const SHBox& rhs) noexcept; + SHBox (SHBox&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHBox& operator= (const SHBox& rhs) noexcept; + SHBox& operator= (SHBox&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] std::vector GetVertices () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Checks if a point is inside the box. + * @param point + * The point to check. + * @return + * True if the point is inside the box. + */ + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + + /** + * @brief + * Casts a ray against the box. + * @param ray + * The ray to cast. + * @return + * The result of the raycast.
+ * See the corresponding header for the contents of the raycast result object. + */ + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + + /** + * @brief + * Checks if an entire other box is contained by this box. + * @param rhs + * The box to check. + * @return + * True if the other sphere is completely contained by this box. + */ + [[nodiscard]] bool Contains (const SHBox& rhs) const noexcept; + + /** + * @brief + * Calculates the volume of the box. + */ + [[nodiscard]] float Volume () const noexcept; + + /** + * @brief + * Calculates the surface area of the box. + */ + [[nodiscard]] float SurfaceArea () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Checks if two boxes are intersecting. + * @return + * True if they are intersecting. + */ + [[nodiscard]] static bool Intersect (const SHBox& lhs, const SHBox& rhs) noexcept; + + /** + * @brief + * Builds a box from a set of vertices. + * @param vertices + * The vertices to build a box from. + * @param numVertices + * The number of vertices in the set to build from. + * @param stride + * The stride between each vertex, in the instance there is data in between each + * vertex that does not define the geometry of the object. + * @return + * An box that contains all the vertices in the set. + */ + [[nodiscard]] static SHBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h index 812cb169..2b644917 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -30,10 +30,9 @@ namespace SHADE enum class Type { - BOX - , SPHERE - , CAPSULE - , CONVEX_HULL + SPHERE + , AABB + , BOX , COUNT , NONE = -1 diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp index 021f0a6a..1f4645df 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.cpp +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -40,6 +40,10 @@ namespace SHADE : XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w ) {} + SHQuaternion::SHQuaternion(const XMFLOAT4& xmfloat4) noexcept + : XMFLOAT4( xmfloat4 ) + {} + SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept : XMFLOAT4( _x, _y, _z, _w ) {} diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h index 93c546ca..3342c4cb 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.h +++ b/SHADE_Engine/src/Math/SHQuaternion.h @@ -47,9 +47,10 @@ namespace SHADE SHQuaternion (const SHQuaternion& rhs) = default; SHQuaternion (SHQuaternion&& rhs) = default; - SHQuaternion () noexcept; - SHQuaternion (const SHVec4& vec4) noexcept; - SHQuaternion (float x, float y, float z, float w) noexcept; + SHQuaternion () noexcept; + SHQuaternion (const SHVec4& vec4) noexcept; + SHQuaternion (const XMFLOAT4& xmfloat4) noexcept; + SHQuaternion (float x, float y, float z, float w) noexcept; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index 5fa93021..127494cb 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -204,6 +204,8 @@ namespace SHADE removeLeaf(INDEX_TO_REMOVE); freeNode(INDEX_TO_REMOVE); + + nodeMap.erase(id); } const std::vector& SHAABBTree::Query(SHCollisionShapeID id, const SHAABB& AABB) const noexcept @@ -404,6 +406,13 @@ namespace SHADE } const int32_t PARENT = nodes[index].parent; + + if (PARENT == NULL_NODE) + { + freeNode(index); + return; + } + const int32_t GRANDPARENT = nodes[PARENT].parent; const int32_t SIBLING = nodes[PARENT].left == index ? nodes[PARENT].right : nodes[PARENT].left; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp new file mode 100644 index 00000000..67e497a8 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -0,0 +1,265 @@ +/**************************************************************************************** + * \file SHBoxCollisionShape.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Box Collision Shape. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHBoxCollisionShape.h" + +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Math/SHMatrix.h" +#include "Physics/Collision/SHCollider.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHBoxCollisionShape::SHBoxCollisionShape(SHCollisionShapeID id) noexcept + : SHCollisionShape (id, SHCollisionShape::Type::BOX) + , SHBox () + , relativeExtents { SHVec3::One } + , scale { SHVec3::One } + {} + + SHBoxCollisionShape::SHBoxCollisionShape(const SHBoxCollisionShape& rhs) noexcept + : SHCollisionShape (rhs.id, SHCollisionShape::Type::BOX) + , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) + , relativeExtents { rhs.relativeExtents } + , scale { rhs.scale } + { + + material = rhs.material; + collider = rhs.collider; + transform = rhs.transform; + rotationOffset = rhs.rotationOffset; + flags = rhs.flags; + // Since all collision tags are taken from the matrix, we do not need to do a deep copy here. + collisionTag = rhs.collisionTag; + } + + SHBoxCollisionShape::SHBoxCollisionShape(SHBoxCollisionShape&& rhs) noexcept + : SHCollisionShape (rhs.id, SHCollisionShape::Type::BOX) + , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) + , relativeExtents { rhs.relativeExtents } + , scale { rhs.scale } + { + + material = rhs.material; + collider = rhs.collider; + transform = rhs.transform; + rotationOffset = rhs.rotationOffset; + flags = rhs.flags; + // Since all collision tags are taken from the matrix, we do not need to do a deep copy here. + collisionTag = rhs.collisionTag; + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHBoxCollisionShape& SHBoxCollisionShape::operator=(const SHBoxCollisionShape& rhs) noexcept + { + if (this == &rhs) + return *this; + + // Collision Shape Properties + + id = rhs.id; + material = rhs.material; + collider = rhs.collider; + transform = rhs.transform; + rotationOffset = rhs.rotationOffset; + flags = rhs.flags; + // Since all collision tags are taken from the matrix, we do not need to do a deep copy here. + collisionTag = rhs.collisionTag; + + // Box Properties + + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + + // Local Properties + + relativeExtents = rhs.relativeExtents; + scale = rhs.scale; + + return *this; + } + + SHBoxCollisionShape& SHBoxCollisionShape::operator=(SHBoxCollisionShape&& rhs) noexcept + { + // Collision Shape Properties + + id = rhs.id; + material = rhs.material; + collider = rhs.collider; + transform = rhs.transform; + rotationOffset = rhs.rotationOffset; + flags = rhs.flags; + // Since all collision tags are taken from the matrix, we do not need to do a deep copy here. + collisionTag = rhs.collisionTag; + + // Box Properties + + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + + // Local Properties + + relativeExtents = rhs.relativeExtents; + scale = rhs.scale; + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3 SHBoxCollisionShape::GetCenter() const noexcept + { + return Center; + } + + SHVec3 SHBoxCollisionShape::GetWorldExtents() const noexcept + { + return Extents; + } + + SHVec3 SHBoxCollisionShape::GetRelativeExtents() const noexcept + { + return relativeExtents; + } + + SHQuaternion SHBoxCollisionShape::GetOrientation() const noexcept + { + return Orientation; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHBoxCollisionShape::SetCenter(const SHVec3& newCenter) noexcept + { + Center = newCenter; + } + + void SHBoxCollisionShape::SetWorldExtents(const SHVec3& newWorldExtents) noexcept + { + Extents = newWorldExtents; + + // Recompute Relative radius + relativeExtents = 2.0f * Extents / scale; + } + + void SHBoxCollisionShape::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept + { + relativeExtents = newRelativeExtents; + + // Recompute world radius + Extents = relativeExtents * scale * 0.5f; + } + + void SHBoxCollisionShape::SetOrientation(const SHQuaternion& newOrientation) noexcept + { + Orientation = newOrientation; + } + + + void SHBoxCollisionShape::SetScale(const SHVec3& newScale) noexcept + { + scale = SHVec3::Abs(newScale); + + // Recompute world radius + Extents = relativeExtents * scale * 0.5f; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHBoxCollisionShape::ComputeTransforms() noexcept + { + const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); + + SetScale(PARENT_TRANSFORM.scale); + + // Recompute center + const SHQuaternion FINAL_ROT = PARENT_TRANSFORM.orientation * transform.orientation; + const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(PARENT_TRANSFORM.position); + + Center = SHVec3::Transform(transform.position, TRS); + } + + bool SHBoxCollisionShape::TestPoint(const SHVec3& point) const noexcept + { + return SHBox::TestPoint(point); + } + + SHRaycastResult SHBoxCollisionShape::Raycast(const SHRay& ray) const noexcept + { + return SHBox::Raycast(ray); + } + + SHMatrix SHBoxCollisionShape::GetInertiaTensor(float mass) const noexcept + { + static constexpr float ONE_OVER_TWELVE = (1.0f / 12.0f); + + const float H2_PLUS_D2 = Extents.y * Extents.y + Extents.z * Extents.z; + const float W2_PLUS_H2 = Extents.x * Extents.x + Extents.y * Extents.y; + const float W2_PLUS_D2 = Extents.x * Extents.x + Extents.z * Extents.z; + + SHMatrix result; + result.m[0][0] = ONE_OVER_TWELVE * mass * H2_PLUS_D2; + result.m[1][1] = ONE_OVER_TWELVE * mass * W2_PLUS_H2; + result.m[2][2] = ONE_OVER_TWELVE * mass * W2_PLUS_D2; + return result; + } + + SHMatrix SHBoxCollisionShape::ComputeWorldTransform() const noexcept + { + const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); + const SHQuaternion ROTATION = PARENT_TRANSFORM.orientation * transform.orientation; + const SHVec3 SCALE = SHVec3{ Extents } *2.0f; + + return SHMatrix::Transform + ( + Center + , ROTATION + , SCALE + ); + } + + SHAABB SHBoxCollisionShape::ComputeAABB() const noexcept + { + SHVec3 min{ std::numeric_limits::max() }; + SHVec3 max{ std::numeric_limits::lowest() }; + + const auto& VERTICES = GetVertices(); + for (auto& vtx : VERTICES) + { + min = SHVec3::Min({ vtx, min }); + max = SHVec3::Max({ vtx, max }); + } + + const SHVec3 HALF_EXTENTS = (max - min) * 0.5f; + const SHVec3 CENTROID = min + HALF_EXTENTS; + + return SHAABB{ CENTROID, HALF_EXTENTS }; + } + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h new file mode 100644 index 00000000..35da5e6e --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h @@ -0,0 +1,158 @@ +/**************************************************************************************** + * \file SHBoxCollisionShape.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Box Collision Shape. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +// Project Headers +#include "Math/Geometry/SHBox.h" +#include "SHCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates the information to create a box. + */ + struct SHBoxCreateInfo + { + public: + SHVec3 Center = SHVec3::Zero; + SHVec3 Extents = SHVec3::One * 0.5f; + SHVec3 RelativeExtents = SHVec3::One; + SHQuaternion Orientation = SHQuaternion::Identity; + SHVec3 Scale = SHVec3::One; + }; + + /** + * @brief + * Encapsulate a Box Collision Shape used for Physics Simulations. + */ + class SH_API SHBoxCollisionShape final : public SHCollisionShape + , private SHBox + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHCollider; + friend class SHCollision; + friend class SHCompositeCollider; + friend class SHCollisionShapeFactory; + + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHBoxCollisionShape (SHCollisionShapeID id) noexcept; + SHBoxCollisionShape (const SHBoxCollisionShape& rhs) noexcept; + SHBoxCollisionShape (SHBoxCollisionShape&& rhs) noexcept; + + ~SHBoxCollisionShape () override = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHBoxCollisionShape& operator= (const SHBoxCollisionShape& rhs) noexcept; + SHBoxCollisionShape& operator= (SHBoxCollisionShape&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHVec3 GetCenter () const noexcept; + [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; + [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetCenter (const SHVec3& newCenter) noexcept; + void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; + void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept; + void SetOrientation (const SHQuaternion& newOrientation) noexcept; + void SetScale (const SHVec3& newScale) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Recomputes the transform of this box. + */ + void ComputeTransforms () noexcept override; + + /** + * @brief + * Tests if a point is inside the box. + * @param point + * The point to test. + * @return + * True if the point is inside the box. + */ + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + + /** + * @brief + * Casts a ray against this box. + * @param ray + * The ray to cast. + * @return + * An object holding the results of the raycast.
+ * See the corresponding header for the contents of the object. + */ + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + + /** + * @brief + * Computes the inertia tensor of the box. + * @param mass + * The mass of the sphere. + * @return + * The inertia tensor of the box. + */ + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; + + /** + * @brief + * Computes the transformation matrix of the box. + * @return + * The transformation matrix of the box. + */ + [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; + + /** + * @brief + * Computes the a tight-fitting AABB that contains this box. + * @return + * A tight-fitting AABB that contains this box. + */ + [[nodiscard]] SHAABB ComputeAABB () const noexcept override; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHVec3 relativeExtents; + SHVec3 scale; // Intended to be passed in by the base collider. + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp index d6ef5f0d..97409cf0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp @@ -24,6 +24,10 @@ namespace SHADE // Free all shapes in each container for (auto* sphereCollisionShape : spheres | std::views::values) DestroyShape(sphereCollisionShape); + + // Free all shapes in each container + for (auto* boxCollisionShape : boxes | std::views::values) + DestroyShape(boxCollisionShape); } /*-----------------------------------------------------------------------------------*/ @@ -48,6 +52,26 @@ namespace SHADE return spheres.find(id)->second; } + SHBoxCollisionShape* SHCollisionShapeFactory::CreateBox(SHCollisionShapeID id, const SHBoxCreateInfo& createInfo) + { + const auto RESULT = boxes.emplace(id, new SHBoxCollisionShape{ id }); + if (RESULT.second) + { + SHBoxCollisionShape* box = RESULT.first->second; + + box->Center = createInfo.Center; + box->Extents = createInfo.Extents; + box->relativeExtents = createInfo.RelativeExtents; + box->Orientation = createInfo.Orientation; + box->scale = createInfo.Scale; + + return box; + } + + return boxes.find(id)->second; + } + + void SHCollisionShapeFactory::DestroyShape(SHCollisionShape* shape) { switch (shape->GetType()) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h index f5820317..c82d7e26 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h @@ -14,6 +14,7 @@ // Project Header #include "SHSphereCollisionShape.h" +#include "SHBoxCollisionShape.h" namespace SHADE { @@ -49,10 +50,22 @@ namespace SHADE * @param createInfo * The info to create the sphere with. * @return - * A newly sphere collision shape. + * A new sphere collision shape. */ SHSphereCollisionShape* CreateSphere (SHCollisionShapeID id, const SHSphereCreateInfo& createInfo); + /** + * @brief + * Creates a box collision shape. + * @param id + * The ID of the shape. + * @param createInfo + * The info to create the box with. + * @return + * A new box collision shape. + */ + SHBoxCollisionShape* CreateBox (SHCollisionShapeID id, const SHBoxCreateInfo& createInfo); + /** * @brief * Destroys a collision shape. @@ -63,7 +76,7 @@ namespace SHADE * @param shape * The shape to destroy. */ - void DestroyShape (SHCollisionShape* shape); + void DestroyShape (SHCollisionShape* shape); private: /*---------------------------------------------------------------------------------*/ @@ -74,13 +87,15 @@ namespace SHADE // Since we are not instancing shapes (yet?), I'd rather not iterate through an entire vector to find the shape. using Spheres = std::unordered_map; + using Boxes = std::unordered_map; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ Spheres spheres; - // TODO: Add boxes, capsules and hulls + Boxes boxes; + // TODO: Add capsules and hulls }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 6e119cd1..a1ebf6a3 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -93,7 +93,7 @@ namespace SHADE * @brief * Recomputes the transform of this sphere. */ - void ComputeTransforms () noexcept override; + void ComputeTransforms () noexcept override; /** * @brief @@ -103,7 +103,7 @@ namespace SHADE * @return * True if the point is inside the sphere. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; /** * @brief @@ -114,7 +114,7 @@ namespace SHADE * An object holding the results of the raycast.
* See the corresponding header for the contents of the object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; /** * @brief @@ -124,11 +124,23 @@ namespace SHADE * @return * The inertia tensor of the sphere. */ - [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; - [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; + /** + * @brief + * Computes the transformation matrix of the sphere. + * @return + * The transformation matrix of the sphere. + */ + [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; - [[nodiscard]] SHAABB ComputeAABB () const noexcept override; + /** + * @brief + * Computes the a tight-fitting AABB that contains this sphere. + * @return + * A tight-fitting AABB that contains this sphere. + */ + [[nodiscard]] SHAABB ComputeAABB () const noexcept override; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 7d7d1a60..4ce819ac 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -332,6 +332,60 @@ namespace SHADE return static_cast(NEW_INDEX); } + int SHCollider::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset) + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add new shape!", entityID) + return -1; + } + + // Compute center + const SHQuaternion FINAL_ROT = transform.orientation * SHQuaternion::FromEuler(rotOffset); + const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(transform.position); + + // Create Sphere + const SHBoxCreateInfo BOX_CREATE_INFO + { + .Center = SHVec3::Transform(posOffset, TRS) + , .Extents = relativeExtents * SHVec3::Abs(transform.scale) * 0.5f + , .RelativeExtents = relativeExtents + , .Orientation = FINAL_ROT + , .Scale = SHVec3::Abs(transform.scale) + }; + + const uint32_t NEW_INDEX = static_cast(shapes.size()); + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; + + SHBoxCollisionShape* box = shapeFactory->CreateBox(NEW_SHAPE_ID, BOX_CREATE_INFO); + + // Set offsets + box->collider = this; + box->SetPositionOffset(posOffset); + box->SetRotationOffset(rotOffset); + + shapes.emplace_back(box); + + if (broadphase) + broadphase->Insert(NEW_SHAPE_ID, box->ComputeAABB()); + + // Broadcast Event for adding a shape + const SHPhysicsColliderAddedEvent EVENT_DATA + { + .entityID = entityID + , .colliderType = SHCollisionShape::Type::BOX + , .colliderIndex = static_cast(NEW_INDEX) + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + + if (rigidBody) + rigidBody->ComputeMassData(); + + return static_cast(NEW_INDEX); + } + + void SHCollider::RemoveCollisionShape(int index) { if (!shapeFactory) diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 51b33cfb..3d80118e 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -123,19 +123,34 @@ namespace SHADE /** * @brief * Adds a sphere collision shape. + * @param relativeRadius + * The relative radius is constructed with respect to the world scale.
+ * Radius = max(scale.x, scale.y, scale.z) * 0.5 * relativeRadius * @param posOffset * The position offset of the sphere from the center of the collider. Defaults to a Zero Vector. * @param rotOffset * The rotation offset of the sphere from the rotation of the collider. Defaults to a Zero Vector. - * @param relativeRadius - * The relative radius is constructed with respect to the world scale.
- * Radius = max(scale.x, scale.y, scale.z) * 0.5 * relativeRadius * @return * The index of the newly added shape. */ - int AddSphereCollisionShape (float relativeRadius, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); + int AddSphereCollisionShape (float relativeRadius, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); - // TODO: Add Box & Capsule + /** + * @brief + * Adds a box collision shape. + * @param relativeExtents + * The relative extents are constructed with respect to the world scale.
+ * Extents = scale * 0.5 * relativeExtents + * @param posOffset + * The position offset of the box from the center of the collider. Defaults to a Zero Vector. + * @param rotOffset + * The rotation offset of the box from the rotation of the collider. Defaults to a Zero Vector. + * @return + * The index of the newly added shape. + */ + int AddBoxCollisionShape (const SHVec3& relativeExtents, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); + + // TODO: Add Capsule /** * @brief @@ -146,13 +161,13 @@ namespace SHADE * @throws * Invalid argument for out-of-range indices. */ - void RemoveCollisionShape (int index); + void RemoveCollisionShape (int index); /** * @brief * Recomputes the transforms for all shapes in this composite collider. */ - void RecomputeShapes () noexcept; + void RecomputeShapes () noexcept; protected: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index 8aad19f5..f4a72f82 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -98,7 +98,7 @@ namespace SHADE for (auto& aabb : BROADPHASE_AABBS) { // Compute AABB Transform - const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f); + const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetExtents() * 2.0f); debugDrawSystem->DrawWireCube(TRS, AABB_COLOUR); } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 9940ad20..f0add8f2 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -133,11 +133,11 @@ namespace SHADE case SHCollisionShape::Type::SPHERE: { debugDrawSystem->DrawWireSphere(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true); - break; } case SHCollisionShape::Type::BOX: { + debugDrawSystem->DrawWireCube(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true); break; } case SHCollisionShape::Type::CAPSULE: diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 59ee532a..909aa665 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -132,8 +132,8 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - //const auto* BOX = reinterpret_cast(rhs.GetShape()); - //node[HalfExtents] = BOX->GetRelativeExtents(); + const auto& BOX = dynamic_cast(rhs); + node[HalfExtents] = BOX.GetRelativeExtents(); } break; case SHCollisionShape::Type::SPHERE: @@ -170,7 +170,11 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - + if (node[HalfExtents].IsDefined()) + { + auto* box = dynamic_cast(&rhs); + box->SetRelativeExtents(node[HalfExtents].as()); + } } break; case SHCollisionShape::Type::SPHERE: diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 3dd1446e..79140d2b 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -137,12 +137,12 @@ namespace SHADE } Vector3 BoxCollider::HalfExtents::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + //return Convert::ToCLI(getNativeCollisionShape().GetExtents()); return Vector3::Zero; } void BoxCollider::HalfExtents::set(Vector3 value) { - //getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); + //getNativeCollisionShape().SetExtents(Convert::ToNative(value)); } Vector3 BoxCollider::Min::get() {