Implemented a custom physics engine #316
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace SHADE
|
|||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
const SHVec3& SHSphereCollisionShape::GetCenter() const noexcept
|
||||
SHVec3 SHSphereCollisionShape::GetCenter() const noexcept
|
||||
{
|
||||
return Center;
|
||||
}
|
||||
|
|
|
@ -72,9 +72,9 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] const SHVec3& GetCenter () const noexcept;
|
||||
[[nodiscard]] float GetWorldRadius () const noexcept;
|
||||
[[nodiscard]] float GetRelativeRadius () const noexcept;
|
||||
[[nodiscard]] SHVec3 GetCenter () const noexcept;
|
||||
[[nodiscard]] float GetWorldRadius () const noexcept;
|
||||
[[nodiscard]] float GetRelativeRadius () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Setter Functions */
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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,10 +34,10 @@ 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 SHVec3 A_TO_B = SPHERE_B.GetCenter() - SPHERE_A.GetCenter();
|
||||
const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared();
|
||||
|
||||
const float COMBINED_RADIUS = (SPHERE_A.GetWorldRadius() + SPHERE_B.GetWorldRadius());
|
||||
|
|
|
@ -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
|
||||
|
@ -432,10 +448,18 @@ namespace SHADE
|
|||
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -71,8 +71,10 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
const TriggerEvents& GetTriggerEvents () const noexcept;
|
||||
const CollisionEvents& GetCollisionEvents () const noexcept;
|
||||
const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept;
|
||||
|
||||
const TriggerEvents& GetTriggerEvents () const noexcept;
|
||||
const CollisionEvents& GetCollisionEvents () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ namespace SHADE
|
|||
physicsObject.collider->SetScale(WORLD_SCL);
|
||||
|
||||
physicsObject.collider->RecomputeShapes();
|
||||
|
||||
physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -45,8 +45,9 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] double GetFixedUpdateRate() const noexcept;
|
||||
[[nodiscard]] double GetFixedDT() const noexcept;
|
||||
[[nodiscard]] const SHPhysicsWorld* GetWorld () const noexcept;
|
||||
[[nodiscard]] double GetFixedUpdateRate() const noexcept;
|
||||
[[nodiscard]] double GetFixedDT () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Setter Functions */
|
||||
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue