Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
6 changed files with 665 additions and 1 deletions
Showing only changes of commit 6cd203179a - Show all commits

View File

@ -1,4 +1,4 @@
Start in Fullscreen: false Start in Fullscreen: false
Starting Scene ID: 97158628 Starting Scene ID: 97402985
Window Size: {x: 1920, y: 1080} Window Size: {x: 1920, y: 1080}
Window Title: SHADE Engine Window Title: SHADE Engine

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,3 @@
Name: PhysicsSandbox
ID: 97402985
Type: 5

View File

@ -0,0 +1,96 @@
/****************************************************************************************
* \file SHRigidBody.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Rigid Body.
*
* \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 "SHRigidBody.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHRigidBody::SHRigidBody(EntityID eid, Type type) noexcept
: entityID { eid }
, bodyType { type }
, invMass { type == Type::DYNAMIC ? 1.0f : 0.0f }
, linearDrag { type != Type::STATIC ? 0.01f : 0.0f }
, gravityScale { 1.0f }
, flags { 0U }
{
// Set default flags
flags |= 1U << 0; // Body is active
flags |= 1U << 2; // Sleeping is enabled
flags |= 1U << 3; // Gravity is enabled
// TODO: Compute inertia if body is dynamic
}
SHRigidBody::SHRigidBody(const SHRigidBody& rhs) noexcept
: entityID { rhs.entityID }
, bodyType { rhs.bodyType }
, invMass { rhs.invMass }
, linearDrag { rhs.linearDrag }
, gravityScale { rhs.gravityScale }
, flags { rhs.flags }
{
// All other properties are defaulted to 0 to not carry over any potential errors / invalid values.
}
SHRigidBody::SHRigidBody(SHRigidBody&& rhs) noexcept
: entityID { rhs.entityID }
, bodyType { rhs.bodyType }
, invMass { rhs.invMass }
, linearDrag { rhs.linearDrag }
, gravityScale { rhs.gravityScale }
, flags { rhs.flags }
{
// All other properties are defaulted to 0 to not carry over any potential errors / invalid values.
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
SHRigidBody& SHRigidBody::operator=(const SHRigidBody& rhs) noexcept
{
// Handle self assignment
if (this == &rhs)
return *this;
entityID = rhs.entityID;
bodyType = rhs.bodyType;
invMass = rhs.invMass;
linearDrag = rhs.linearDrag;
gravityScale = rhs.gravityScale;
flags = rhs.flags;
// All other properties are defaulted to 0 to not carry over any potential errors / invalid values.
return *this;
}
SHRigidBody& SHRigidBody::operator=(SHRigidBody&& rhs) noexcept
{
entityID = rhs.entityID;
bodyType = rhs.bodyType;
invMass = rhs.invMass;
linearDrag = rhs.linearDrag;
gravityScale = rhs.gravityScale;
flags = rhs.flags;
// All other properties are defaulted to 0 to not carry over any potential errors / invalid values.
return *this;
}
} // namespace SHADE

View File

@ -0,0 +1,189 @@
/****************************************************************************************
* \file SHRigidBody.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Rigid Body.
*
* \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 "ECS_Base/SHECSMacros.h"
#include "Math/Vector/SHVec3.h"
namespace SHADE
{
/**
* @brief
* Encapsulates a Rigid Body used in Physics Simulations
*/
class SHRigidBody
{
private:
/*-----------------------------------------------------------------------------------*/
/* Friends */
/*-----------------------------------------------------------------------------------*/
friend class SHRigidBodyComponent;
public:
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
enum class Type
{
STATIC // Immovable body with infinite mass
, KINEMATIC // Only movable by setting velocity, unaffected by forces. Has infinite mass.
, DYNAMIC // Affected by forces.
};
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-----------------------------------------------------------------------------------*/
SHRigidBody (EntityID eid, Type type) noexcept;
SHRigidBody (const SHRigidBody& rhs) noexcept;
SHRigidBody (SHRigidBody&& rhs) noexcept;
/*-----------------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------------*/
SHRigidBody& operator= (const SHRigidBody& rhs) noexcept;
SHRigidBody& operator= (SHRigidBody&& rhs) noexcept;
/*-----------------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------------*/
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] float GetMass () const noexcept;
[[nodiscard]] float GetLinearDrag () const noexcept;
[[nodiscard]] float GetGravityScale () const noexcept;
[[nodiscard]] const SHVec3& GetAccumulatedForce () const noexcept;
[[nodiscard]] const SHVec3& GetLinearVelocity () const noexcept;
[[nodiscard]] const SHVec3& GetAngularVelocity () const noexcept;
// Flags
[[nodiscard]] bool IsActive () const noexcept;
[[nodiscard]] bool IsSleeping () const noexcept;
[[nodiscard]] bool IsSleepingEnabled () const noexcept;
[[nodiscard]] bool IsGravityEnabled () const noexcept;
[[nodiscard]] bool IsAutoMassEnabled () const noexcept;
[[nodiscard]] bool GetFreezePositionX () const noexcept;
[[nodiscard]] bool GetFreezePositionY () const noexcept;
[[nodiscard]] bool GetFreezePositionZ () const noexcept;
[[nodiscard]] bool GetFreezeRotationX () const noexcept;
[[nodiscard]] bool GetFreezeRotationY () const noexcept;
[[nodiscard]] bool GetFreezeRotationZ () const noexcept;
/*-----------------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------------*/
/**
* @brief
* Changing the type from non-Dynamic to Dynamic will set the default mass.
*/
void SetType (Type newType) noexcept;
/**
* @brief
* Mass is only modifiable for Dynamic bodies.
* @param newMass
* The new mass to set. Values below 0 will be ignored.
*/
void SetMass (float newMass) noexcept;
/**
* @brief
* Drag is only modifiable for non-Static bodies.
* @param newLinearDrag
* The new drag to set. Values below 0 will be ignored.
*/
void SetLinearDrag (float newLinearDrag) noexcept;
void SetGravityScale (float newGravityScale) noexcept;
void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept;
// Flags
void SetIsActive (bool isActive) noexcept;
void SetIsSleeping (bool isSleeping) noexcept;
void SetSleepingEnabled (bool enableSleeping) noexcept;
void SetGravityEnabled (bool enableGravity) noexcept;
void SetAutoMassEnabled (bool enableAutoMass) noexcept;
void SetFreezePositionX (bool freezePositionX) noexcept;
void SetFreezePositionY (bool freezePositionY) noexcept;
void SetFreezePositionZ (bool freezePositionZ) noexcept;
void SetFreezeRotationX (bool freezeRotationX) noexcept;
void SetFreezeRotationY (bool freezeRotationY) noexcept;
void SetFreezeRotationZ (bool freezeRotationZ) noexcept;
/*-----------------------------------------------------------------------------------*/
/* Member Functions */
/*-----------------------------------------------------------------------------------*/
/**
* @brief
* Adds a force to the body with an offset from it's center of mass.
* @param force
* The force to add to the body.
* @param pos
* The position from the center of mass to offset the force. Defaults to zero.
*/
void AddForce (const SHVec3& force, const SHVec3& pos = SHVec3::Zero) noexcept;
/**
* @brief
* Adds an impulse to the body with an offset from it's center of mass.
* @param impulse
* The impulse to add to the body.
* @param pos
* The position from the center of mass to offset the impulse. Defaults to zero.
*/
void AddImpulse (const SHVec3& impulse, const SHVec3& pos = SHVec3::Zero) noexcept;
/**
* @brief
* Removes all the forces from the body.
*/
void ClearForces () noexcept;
private:
/*-----------------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------------*/
// The entityID here is only meant for linking with the actual component in the engine.
EntityID entityID;
Type bodyType;
float invMass;
float linearDrag;
float gravityScale;
SHVec3 accumulatedForce;
SHVec3 linearVelocity;
SHVec3 angularVelocity;
// aZ aY aX pZ pY pX 0 0 0 0 0 autoMass enableGravity enableSleeping sleeping active
uint16_t flags;
};
} // namespace SHADE
#include "SHRigidBody.inl"

View File

@ -0,0 +1,375 @@
/****************************************************************************************
* \file SHRigidBody.inl
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for inlined functions of a Rigid Body.
*
* \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
// Primary Header
#include "SHRigidBody.h"
// Project Headers
#include "Math/SHMathHelpers.h"
#include "Tools/Logger/SHLogger.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Getter Functions Definitions */
/*-----------------------------------------------------------------------------------*/
inline SHRigidBody::Type SHRigidBody::GetType() const noexcept
{
return bodyType;
}
inline float SHRigidBody::GetMass() const noexcept
{
return 1.0f/ invMass;
}
inline float SHRigidBody::GetLinearDrag() const noexcept
{
return linearDrag;
}
inline float SHRigidBody::GetGravityScale() const noexcept
{
return gravityScale;
}
inline const SHVec3& SHRigidBody::GetAccumulatedForce() const noexcept
{
return accumulatedForce;
}
inline const SHVec3& SHRigidBody::GetLinearVelocity() const noexcept
{
return linearVelocity;
}
inline const SHVec3& SHRigidBody::GetAngularVelocity() const noexcept
{
return angularVelocity;
}
// Flags
inline bool SHRigidBody::IsActive() const noexcept
{
static constexpr unsigned int FLAG_POS = 0;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::IsSleeping() const noexcept
{
static constexpr unsigned int FLAG_POS = 1;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::IsSleepingEnabled() const noexcept
{
static constexpr unsigned int FLAG_POS = 2;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::IsGravityEnabled() const noexcept
{
static constexpr unsigned int FLAG_POS = 3;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::IsAutoMassEnabled() const noexcept
{
static constexpr unsigned int FLAG_POS = 4;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::GetFreezePositionX() const noexcept
{
static constexpr unsigned int FLAG_POS = 10;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::GetFreezePositionY() const noexcept
{
static constexpr unsigned int FLAG_POS = 11;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::GetFreezePositionZ() const noexcept
{
static constexpr unsigned int FLAG_POS = 12;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::GetFreezeRotationX() const noexcept
{
static constexpr unsigned int FLAG_POS = 13;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::GetFreezeRotationY() const noexcept
{
static constexpr unsigned int FLAG_POS = 14;
return flags & (1U << FLAG_POS);
}
inline bool SHRigidBody::GetFreezeRotationZ() const noexcept
{
static constexpr unsigned int FLAG_POS = 15;
return flags & (1U << FLAG_POS);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Functions Definitions */
/*-----------------------------------------------------------------------------------*/
inline void SHRigidBody::SetType(Type newType) noexcept
{
if (newType == bodyType)
return;
bodyType = newType;
invMass = newType == Type::DYNAMIC ? 1.0f : 0.0f;
}
inline void SHRigidBody::SetMass(float newMass) noexcept
{
if (bodyType != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set mass of a non-Dynamic Body {}", entityID)
return;
}
if (newMass < 0.0f)
{
SHLOG_WARNING("Cannot set mass below 0. Object {}'s mass will remain unchanged.", entityID)
return;
}
invMass = 1.0f / newMass;
// TODO: Recompute inertia tensor
}
inline void SHRigidBody::SetLinearDrag(float newLinearDrag) noexcept
{
if (bodyType == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear drag of a Static Body {}", entityID)
return;
}
if (newLinearDrag < 0.0f)
{
SHLOG_WARNING("Cannot set drag below 0. Object {}'s linear drag will remain unchanged.", entityID)
return;
}
linearDrag = newLinearDrag;
}
inline void SHRigidBody::SetGravityScale(float newGravityScale) noexcept
{
gravityScale = newGravityScale;
}
inline void SHRigidBody::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
{
linearVelocity = newLinearVelocity;
}
inline void SHRigidBody::SetIsActive(bool isActive) noexcept
{
static constexpr unsigned int FLAG_POS = 0;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
isActive ? flags |= VALUE : flags &= ~VALUE;
}
inline void SHRigidBody::SetIsSleeping(bool isSleeping) noexcept
{
static constexpr unsigned int FLAG_POS = 1;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
isSleeping ? flags |= VALUE : flags &= ~VALUE;
}
inline void SHRigidBody::SetSleepingEnabled(bool enableSleeping) noexcept
{
static constexpr unsigned int FLAG_POS = 2;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (enableSleeping)
{
flags |= VALUE;
}
else
{
flags &= ~VALUE;
// Wake the body
SetIsSleeping(false);
}
}
inline void SHRigidBody::SetGravityEnabled(bool enableGravity) noexcept
{
static constexpr unsigned int FLAG_POS = 3;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
enableGravity ? flags |= VALUE : flags &= ~VALUE;
}
inline void SHRigidBody::SetAutoMassEnabled(bool enableAutoMass) noexcept
{
static constexpr unsigned int FLAG_POS = 4;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (enableAutoMass)
{
flags |= VALUE;
// TODO: Compute mass based on collider geometry
}
else
{
flags &= ~VALUE;
// Use default mass of 1
invMass = 1.0f;
}
}
inline void SHRigidBody::SetFreezePositionX(bool freezePositionX) noexcept
{
static constexpr unsigned int FLAG_POS = 10;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (freezePositionX)
{
flags |= VALUE;
// Reset linear velocity along X-axis
linearVelocity.x = 0.0f;
}
else
{
flags &= ~VALUE;
}
}
inline void SHRigidBody::SetFreezePositionY(bool freezePositionY) noexcept
{
static constexpr unsigned int FLAG_POS = 11;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (freezePositionY)
{
flags |= VALUE;
// Reset linear velocity along Y-axis
linearVelocity.y = 0.0f;
}
else
{
flags &= ~VALUE;
}
}
inline void SHRigidBody::SetFreezePositionZ(bool freezePositionZ) noexcept
{
static constexpr unsigned int FLAG_POS = 12;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (freezePositionZ)
{
flags |= VALUE;
// Reset linear velocity along Z-axis
linearVelocity.z = 0.0f;
}
else
{
flags &= ~VALUE;
}
}
inline void SHRigidBody::SetFreezeRotationX(bool freezeRotationX) noexcept
{
static constexpr unsigned int FLAG_POS = 13;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (freezeRotationX)
{
flags |= VALUE;
// Reset angular velocity along X-axis
angularVelocity.x = 0.0f;
}
else
{
flags &= ~VALUE;
}
}
inline void SHRigidBody::SetFreezeRotationY(bool freezeRotationY) noexcept
{
static constexpr unsigned int FLAG_POS = 14;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (freezeRotationY)
{
flags |= VALUE;
// Reset angular velocity along Y-axis
angularVelocity.y = 0.0f;
}
else
{
flags &= ~VALUE;
}
}
inline void SHRigidBody::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{
static constexpr unsigned int FLAG_POS = 15;
static constexpr uint16_t VALUE = 1U << FLAG_POS;
if (freezeRotationZ)
{
flags |= VALUE;
// Reset angular velocity along Z-axis
angularVelocity.z = 0.0f;
}
else
{
flags &= ~VALUE;
}
}
/*-----------------------------------------------------------------------------------*/
/* Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
inline void SHRigidBody::AddForce(const SHVec3& force, const SHVec3& pos) noexcept
{
if (bodyType != Type::DYNAMIC)
return;
accumulatedForce += force;
// Compute torque when force is offset
}
inline void SHRigidBody::AddImpulse(const SHVec3& impulse, const SHVec3& pos) noexcept
{
if (bodyType != Type::DYNAMIC)
return;
linearVelocity += impulse * invMass;
}
inline void SHRigidBody::ClearForces() noexcept
{
accumulatedForce = SHVec3::Zero;
}
} // namespace SHADE