Implemented a custom physics engine #316

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

View File

@ -14,7 +14,7 @@
Mass: 10 Mass: 10
Drag: 1 Drag: 1
Angular Drag: 1 Angular Drag: 1
Use Gravity: false Use Gravity: true
Gravity Scale: 1 Gravity Scale: 1
Interpolate: true Interpolate: true
Sleeping Enabled: true Sleeping Enabled: true
@ -48,7 +48,7 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Camera Component: Camera Component:
Position: {x: 0, y: 2, z: 5} Position: {x: 0, y: 2, z: 3}
Pitch: 0 Pitch: 0
Yaw: 0 Yaw: 0
Roll: 0 Roll: 0
@ -70,12 +70,12 @@
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true IsActive: true
RigidBody Component: RigidBody Component:
Type: Static Type: Dynamic
Auto Mass: false Auto Mass: false
Mass: .inf Mass: 1
Drag: 0.00999999978 Drag: 0.00999999978
Angular Drag: 0.00999999978 Angular Drag: 0.00999999978
Use Gravity: true Use Gravity: false
Gravity Scale: 1 Gravity Scale: 1
Interpolate: true Interpolate: true
Sleeping Enabled: true Sleeping Enabled: true

View File

@ -185,6 +185,13 @@ namespace Sandbox
#endif #endif
SHSceneManager::SceneUpdate(0.016f); SHSceneManager::SceneUpdate(0.016f);
#ifdef SHEDITOR #ifdef SHEDITOR
static bool drawBP = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::RIGHT_CTRL))
{
drawBP = !drawBP;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBP);
}
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, SHFrameRateController::GetRawDeltaTime()); SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, SHFrameRateController::GetRawDeltaTime());
editor->PollPicking(); editor->PollPicking();
#else #else

View File

@ -199,7 +199,7 @@ namespace SHADE
bool SHBox::Contains(const SHBox& rhs) const noexcept bool SHBox::Contains(const SHBox& rhs) const noexcept
{ {
return BoundingBox::Contains(rhs); return BoundingBox::Contains(rhs) == CONTAINS;
} }
float SHBox::Volume() const noexcept float SHBox::Volume() const noexcept

View File

@ -107,7 +107,7 @@ namespace SHADE
const std::vector<SHBox>& SHAABBTree::GetAABBs() const noexcept const std::vector<SHBox>& SHAABBTree::GetAABBs() const noexcept
{ {
static std::vector<SHBox> aabbs; static AABBs aabbs;
static std::stack<int32_t> nodeIndices; static std::stack<int32_t> nodeIndices;
aabbs.clear(); aabbs.clear();

View File

@ -28,6 +28,12 @@ namespace SHADE
class SH_API SHAABBTree class SH_API SHAABBTree
{ {
public: public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using AABBs = std::vector<SHBox>;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -55,7 +61,7 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] const std::vector<SHBox>& GetAABBs () const noexcept; [[nodiscard]] const AABBs& GetAABBs () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Member Functions */ /* Member Functions */
@ -116,7 +122,7 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static constexpr float AABB_EXTENSION = 0.2f; static constexpr float AABB_EXTENSION = 0.1f;
// For quick access // For quick access
std::unordered_map<SHCollisionShapeID, int32_t, SHCollisionShapeIDHash> nodeMap; std::unordered_map<SHCollisionShapeID, int32_t, SHCollisionShapeIDHash> nodeMap;

View File

@ -125,7 +125,7 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
const SHVec3& SHSphereCollisionShape::GetCenter() const noexcept SHVec3 SHSphereCollisionShape::GetCenter() const noexcept
{ {
return Center; return Center;
} }

View File

@ -72,9 +72,9 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] const SHVec3& GetCenter () const noexcept; [[nodiscard]] SHVec3 GetCenter () const noexcept;
[[nodiscard]] float GetWorldRadius () const noexcept; [[nodiscard]] float GetWorldRadius () const noexcept;
[[nodiscard]] float GetRelativeRadius () const noexcept; [[nodiscard]] float GetRelativeRadius () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */

View File

@ -35,12 +35,13 @@ namespace SHADE
SHCollisionShape* A = nullptr; SHCollisionShape* A = nullptr;
SHCollisionShape* B = nullptr; SHCollisionShape* B = nullptr;
uint32_t numContacts = 0;
SHCollisionState state = SHCollisionState::INVALID;
SHVec3 normal; SHVec3 normal;
SHVec3 tangents[SHContact::NUM_TANGENTS]; SHVec3 tangents[SHContact::NUM_TANGENTS];
SHContact contacts[MAX_NUM_CONTACTS]; SHContact contacts[MAX_NUM_CONTACTS];
uint32_t numContacts = 0;
SHCollisionState state;
}; };
} }

View File

@ -25,8 +25,8 @@ namespace SHADE
bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept
{ {
const SHSphereCollisionShape& SPHERE_A = dynamic_cast<const SHSphereCollisionShape&>(A); const SHSphereCollisionShape& SPHERE_A = reinterpret_cast<const SHSphereCollisionShape&>(A);
const SHSphereCollisionShape& SPHERE_B = dynamic_cast<const SHSphereCollisionShape&>(B); const SHSphereCollisionShape& SPHERE_B = reinterpret_cast<const SHSphereCollisionShape&>(B);
return SHSphere::Intersect(SPHERE_A, SPHERE_B); return SHSphere::Intersect(SPHERE_A, SPHERE_B);
} }
@ -34,10 +34,10 @@ namespace SHADE
bool SHCollision::SphereVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept bool SHCollision::SphereVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept
{ {
// Convert to spheres // Convert to spheres
const SHSphereCollisionShape& SPHERE_A = dynamic_cast<const SHSphereCollisionShape&>(A); const SHSphereCollisionShape& SPHERE_A = reinterpret_cast<const SHSphereCollisionShape&>(A);
const SHSphereCollisionShape& SPHERE_B = dynamic_cast<const SHSphereCollisionShape&>(B); const SHSphereCollisionShape& SPHERE_B = reinterpret_cast<const SHSphereCollisionShape&>(B);
const SHVec3 A_TO_B = SPHERE_B.GetCenter() - SPHERE_A.GetCenter(); const SHVec3 A_TO_B = SPHERE_B.GetCenter() - SPHERE_A.GetCenter();
const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared(); const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared();
const float COMBINED_RADIUS = (SPHERE_A.GetWorldRadius() + SPHERE_B.GetWorldRadius()); const float COMBINED_RADIUS = (SPHERE_A.GetWorldRadius() + SPHERE_B.GetWorldRadius());

View File

@ -39,6 +39,11 @@ namespace SHADE
/* Getter Functions Definitions */ /* Getter Functions Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
const SHAABBTree::AABBs& SHPhysicsWorld::GetBroadphaseAABBs() const noexcept
{
return broadphase.GetAABBs();
}
const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept
{ {
static TriggerEvents triggerEvents; static TriggerEvents triggerEvents;
@ -153,8 +158,13 @@ namespace SHADE
* Get collider's rigid body * Get collider's rigid body
* Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep * Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep
*/ */
}
void SHPhysicsWorld::UpdateBroadphase(SHCollider* collider) noexcept
{
auto& shapes = collider->GetCollisionShapes();
for (auto* shape : shapes)
broadphase.Update(shape->id, shape->ComputeAABB());
} }
void SHPhysicsWorld::Step(float dt) void SHPhysicsWorld::Step(float dt)
@ -367,6 +377,9 @@ namespace SHADE
void SHPhysicsWorld::runNarrowphase() noexcept void SHPhysicsWorld::runNarrowphase() noexcept
{ {
if (narrowphaseBatch.empty())
return;
for (auto& [id, narrowphasePair] : narrowphaseBatch) for (auto& [id, narrowphasePair] : narrowphaseBatch)
{ {
const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger(); const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger();
@ -378,6 +391,9 @@ namespace SHADE
else else
collideManifolds(id, narrowphasePair); collideManifolds(id, narrowphasePair);
} }
// Clear every frame
narrowphaseBatch.clear();
} }
void SHPhysicsWorld::collideTriggers(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept void SHPhysicsWorld::collideTriggers(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept
@ -432,10 +448,18 @@ namespace SHADE
void SHPhysicsWorld::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept void SHPhysicsWorld::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept
{ {
if (isColliding) if (isColliding)
{
// New states start at invalid. In the first frame of collision, move to enter.
// If it already in enter, move to stay
state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY; state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY;
}
else else
state = SHCollisionState::EXIT; {
// New states start at invalid. In false positive, remain unchanged.
// If previously colliding, move to exit.
state = state == SHCollisionState::INVALID ? SHCollisionState::INVALID : SHCollisionState::EXIT;
}
} }
void SHPhysicsWorld::updateEvents() noexcept void SHPhysicsWorld::updateEvents() noexcept

View File

@ -71,8 +71,10 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
const TriggerEvents& GetTriggerEvents () const noexcept; const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept;
const CollisionEvents& GetCollisionEvents () const noexcept;
const TriggerEvents& GetTriggerEvents () const noexcept;
const CollisionEvents& GetCollisionEvents () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Member Functions */ /* Member Functions */
@ -84,6 +86,14 @@ namespace SHADE
void AddCollider (SHCollider* collider) noexcept; void AddCollider (SHCollider* collider) noexcept;
void RemoveCollider (SHCollider* collider) noexcept; void RemoveCollider (SHCollider* collider) noexcept;
/**
* @brief
* Invoke this method to update the broadphase of a collider while the simulation
* is not running.
* @param collider
* The collider to update.
*/
void UpdateBroadphase (SHCollider* collider) noexcept;
void Step (float dt); void Step (float dt);
private: private:

View File

@ -18,6 +18,7 @@
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics/System/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE namespace SHADE
{ {
@ -40,7 +41,6 @@ namespace SHADE
if (!physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::ACTIVE)) if (!physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::ACTIVE))
return; return;
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>(); auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS); const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS);
@ -68,6 +68,10 @@ namespace SHADE
} }
} }
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
return;
if (DRAW_CONTACTS) if (DRAW_CONTACTS)
{ {
// TODO // TODO
@ -81,7 +85,16 @@ namespace SHADE
if (DRAW_BROADPHASE) if (DRAW_BROADPHASE)
{ {
// TODO const SHColour& AABB_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::BROADPHASE)];
auto& broadphaseAABBs = physicsSystem->GetWorld()->GetBroadphaseAABBs();
for (auto& aabb : broadphaseAABBs)
{
// Compute AABB Transform
const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f);
debugDrawSystem->DrawWireCube(TRS, AABB_COLOUR);
}
} }
} }

View File

@ -65,6 +65,8 @@ namespace SHADE
physicsObject.collider->SetScale(WORLD_SCL); physicsObject.collider->SetScale(WORLD_SCL);
physicsObject.collider->RecomputeShapes(); physicsObject.collider->RecomputeShapes();
physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider);
} }
} }
} }

View File

@ -41,9 +41,9 @@ namespace SHADE
eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST }; eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST };
eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST }; eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST };
#ifdef SHEDITOR //#ifdef SHEDITOR
eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT }; // eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT };
#endif //#endif
} }
SHPhysicsSystem::~SHPhysicsSystem() noexcept SHPhysicsSystem::~SHPhysicsSystem() noexcept
@ -55,6 +55,11 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
const SHPhysicsWorld* SHPhysicsSystem::GetWorld() const noexcept
{
return physicsWorld;
}
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
{ {
return 1.0 / fixedDT; return 1.0 / fixedDT;
@ -173,15 +178,6 @@ namespace SHADE
// Create the physics world // Create the physics world
physicsWorld = new SHPhysicsWorld; physicsWorld = new SHPhysicsWorld;
#ifdef SHEDITOR
// Link all entities with the world if editor is already playing.
// This is for handling scene changes while the editor is active.
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (!EDITOR || EDITOR->editorState != SHEditor::State::PLAY)
return onSceneInitEvent.get()->handle;
for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values)
{ {
if (PHYSICS_OBJECT.rigidBody) if (PHYSICS_OBJECT.rigidBody)
@ -191,7 +187,25 @@ namespace SHADE
physicsWorld->AddCollider(PHYSICS_OBJECT.collider); physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
} }
#endif //#ifdef SHEDITOR
// // Link all entities with the world if editor is already playing.
// // This is for handling scene changes while the editor is active.
//
// const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
// if (!EDITOR || EDITOR->editorState != SHEditor::State::PLAY)
// return onSceneInitEvent.get()->handle;
// for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values)
// {
// if (PHYSICS_OBJECT.rigidBody)
// physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody);
// if (PHYSICS_OBJECT.collider)
// physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
// }
//#endif
return onSceneInitEvent.get()->handle; return onSceneInitEvent.get()->handle;
} }

View File

@ -45,8 +45,9 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedUpdateRate() const noexcept; [[nodiscard]] const SHPhysicsWorld* GetWorld () const noexcept;
[[nodiscard]] double GetFixedDT() const noexcept; [[nodiscard]] double GetFixedUpdateRate() const noexcept;
[[nodiscard]] double GetFixedDT () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
@ -123,11 +124,11 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
#ifdef SHEDITOR //#ifdef SHEDITOR
static constexpr int NUM_EVENT_FUNCTIONS = 5; // static constexpr int NUM_EVENT_FUNCTIONS = 5;
#else //#else
static constexpr int NUM_EVENT_FUNCTIONS = 4; static constexpr int NUM_EVENT_FUNCTIONS = 4;
#endif //#endif
// Event function container for cleanly registering to events // Event function container for cleanly registering to events
EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS]; EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS];