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

View File

@ -185,6 +185,13 @@ namespace Sandbox
#endif
SHSceneManager::SceneUpdate(0.016f);
#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());
editor->PollPicking();
#else

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,12 +35,13 @@ namespace SHADE
SHCollisionShape* A = nullptr;
SHCollisionShape* B = nullptr;
uint32_t numContacts = 0;
SHCollisionState state = SHCollisionState::INVALID;
SHVec3 normal;
SHVec3 tangents[SHContact::NUM_TANGENTS];
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
{
const SHSphereCollisionShape& SPHERE_A = dynamic_cast<const SHSphereCollisionShape&>(A);
const SHSphereCollisionShape& SPHERE_B = dynamic_cast<const SHSphereCollisionShape&>(B);
const SHSphereCollisionShape& SPHERE_A = reinterpret_cast<const SHSphereCollisionShape&>(A);
const SHSphereCollisionShape& SPHERE_B = reinterpret_cast<const SHSphereCollisionShape&>(B);
return SHSphere::Intersect(SPHERE_A, SPHERE_B);
}
@ -34,8 +34,8 @@ namespace SHADE
bool SHCollision::SphereVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept
{
// Convert to spheres
const SHSphereCollisionShape& SPHERE_A = dynamic_cast<const SHSphereCollisionShape&>(A);
const SHSphereCollisionShape& SPHERE_B = dynamic_cast<const SHSphereCollisionShape&>(B);
const SHSphereCollisionShape& SPHERE_A = reinterpret_cast<const SHSphereCollisionShape&>(A);
const SHSphereCollisionShape& SPHERE_B = reinterpret_cast<const SHSphereCollisionShape&>(B);
const SHVec3 A_TO_B = SPHERE_B.GetCenter() - SPHERE_A.GetCenter();
const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared();

View File

@ -39,6 +39,11 @@ namespace SHADE
/* Getter Functions Definitions */
/*-----------------------------------------------------------------------------------*/
const SHAABBTree::AABBs& SHPhysicsWorld::GetBroadphaseAABBs() const noexcept
{
return broadphase.GetAABBs();
}
const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept
{
static TriggerEvents triggerEvents;
@ -153,8 +158,13 @@ namespace SHADE
* Get collider's rigid body
* 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)
@ -367,6 +377,9 @@ namespace SHADE
void SHPhysicsWorld::runNarrowphase() noexcept
{
if (narrowphaseBatch.empty())
return;
for (auto& [id, narrowphasePair] : narrowphaseBatch)
{
const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger();
@ -378,6 +391,9 @@ namespace SHADE
else
collideManifolds(id, narrowphasePair);
}
// Clear every frame
narrowphaseBatch.clear();
}
void SHPhysicsWorld::collideTriggers(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept
@ -433,9 +449,17 @@ namespace SHADE
void SHPhysicsWorld::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept
{
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;
}
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

View File

@ -71,6 +71,8 @@ namespace SHADE
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept;
const TriggerEvents& GetTriggerEvents () const noexcept;
const CollisionEvents& GetCollisionEvents () const noexcept;
@ -84,6 +86,14 @@ namespace SHADE
void AddCollider (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);
private:

View File

@ -18,6 +18,7 @@
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
@ -40,7 +41,6 @@ namespace SHADE
if (!physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::ACTIVE))
return;
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
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)
{
// TODO
@ -81,7 +85,16 @@ namespace SHADE
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->RecomputeShapes();
physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider);
}
}
}

View File

@ -41,9 +41,9 @@ namespace SHADE
eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST };
eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST };
#ifdef SHEDITOR
eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT };
#endif
//#ifdef SHEDITOR
// eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT };
//#endif
}
SHPhysicsSystem::~SHPhysicsSystem() noexcept
@ -55,6 +55,11 @@ namespace SHADE
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsWorld* SHPhysicsSystem::GetWorld() const noexcept
{
return physicsWorld;
}
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
{
return 1.0 / fixedDT;
@ -173,15 +178,6 @@ namespace SHADE
// Create the physics world
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)
{
if (PHYSICS_OBJECT.rigidBody)
@ -191,7 +187,25 @@ namespace SHADE
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;
}

View File

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