Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
21 changed files with 929 additions and 66 deletions
Showing only changes of commit 0df6e09ed6 - Show all commits

View File

@ -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

View File

@ -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<const SHAABB*>(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<SHBoxCollisionShape*>(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<SHSphereCollisionShape*>(shape);
auto* sphere = reinterpret_cast<SHSphereCollisionShape*>(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"))
{

View File

@ -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

View File

@ -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
*
@ -55,7 +55,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetCenter () const noexcept;
[[nodiscard]] SHVec3 GetWorldExtents () const noexcept;
[[nodiscard]] SHVec3 GetExtents () const noexcept;
[[nodiscard]] SHVec3 GetMin () const noexcept;
[[nodiscard]] SHVec3 GetMax () const noexcept;
[[nodiscard]] std::vector<SHVec3> GetVertices () const noexcept;
@ -65,7 +65,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
void SetCenter (const SHVec3& newCenter) noexcept;
void SetWorldExtents (const SHVec3& newWorldExtents) 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;

View File

@ -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 <SHpch.h>
// 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<SHVec3> SHBox::GetVertices() const noexcept
{
std::vector<SHVec3> 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

View File

@ -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 <DirectXCollision.h>
// 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<SHVec3> 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. <br/>
* 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

View File

@ -30,10 +30,9 @@ namespace SHADE
enum class Type
{
BOX
, SPHERE
, CAPSULE
, CONVEX_HULL
SPHERE
, AABB
, BOX
, COUNT
, NONE = -1

View File

@ -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 )
{}

View File

@ -49,6 +49,7 @@ namespace SHADE
SHQuaternion () noexcept;
SHQuaternion (const SHVec4& vec4) noexcept;
SHQuaternion (const XMFLOAT4& xmfloat4) noexcept;
SHQuaternion (float x, float y, float z, float w) noexcept;
/*---------------------------------------------------------------------------------*/

View File

@ -204,6 +204,8 @@ namespace SHADE
removeLeaf(INDEX_TO_REMOVE);
freeNode(INDEX_TO_REMOVE);
nodeMap.erase(id);
}
const std::vector<SHCollisionShapeID>& 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;

View File

@ -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 <SHpch.h>
// 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<float>::max() };
SHVec3 max{ std::numeric_limits<float>::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

View File

@ -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. <br/>
* 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

View File

@ -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())

View File

@ -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.
@ -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<SHCollisionShapeID, SHSphereCollisionShape*, SHCollisionShapeIDHash>;
using Boxes = std::unordered_map<SHCollisionShapeID, SHBoxCollisionShape*, SHCollisionShapeIDHash>;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
Spheres spheres;
// TODO: Add boxes, capsules and hulls
Boxes boxes;
// TODO: Add capsules and hulls
};
} // namespace SHADE

View File

@ -126,8 +126,20 @@ namespace SHADE
*/
[[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override;
/**
* @brief
* Computes the transformation matrix of the sphere.
* @return
* The transformation matrix of the sphere.
*/
[[nodiscard]] SHMatrix ComputeWorldTransform () 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:

View File

@ -332,6 +332,60 @@ namespace SHADE
return static_cast<int>(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<uint32_t>(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<int>(NEW_INDEX)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
if (rigidBody)
rigidBody->ComputeMassData();
return static_cast<int>(NEW_INDEX);
}
void SHCollider::RemoveCollisionShape(int index)
{
if (!shapeFactory)

View File

@ -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. <br/>
* 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. <br/>
* 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);
// TODO: Add Box & Capsule
/**
* @brief
* Adds a box collision shape.
* @param relativeExtents
* The relative extents are constructed with respect to the world scale. <br/>
* 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

View File

@ -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);
}
}

View File

@ -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:

View File

@ -132,8 +132,8 @@ namespace YAML
{
case SHCollisionShape::Type::BOX:
{
//const auto* BOX = reinterpret_cast<const SHAABB*>(rhs.GetShape());
//node[HalfExtents] = BOX->GetRelativeExtents();
const auto& BOX = dynamic_cast<const SHBoxCollisionShape&>(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<SHBoxCollisionShape*>(&rhs);
box->SetRelativeExtents(node[HalfExtents].as<SHVec3>());
}
}
break;
case SHCollisionShape::Type::SPHERE:

View File

@ -137,12 +137,12 @@ namespace SHADE
}
Vector3 BoxCollider::HalfExtents::get()
{
//return Convert::ToCLI(getNativeCollisionShape<SHAABB>().GetWorldExtents());
//return Convert::ToCLI(getNativeCollisionShape<SHAABB>().GetExtents());
return Vector3::Zero;
}
void BoxCollider::HalfExtents::set(Vector3 value)
{
//getNativeCollisionShape<SHAABB>().SetWorldExtents(Convert::ToNative(value));
//getNativeCollisionShape<SHAABB>().SetExtents(Convert::ToNative(value));
}
Vector3 BoxCollider::Min::get()
{