From 52dc993941676f93f0af4985c197b63e38072016 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 2 Dec 2022 17:44:44 +0800 Subject: [PATCH 01/84] goodbye react --- .../src/Application/SBApplication.cpp | 29 -- SHADE_Application/src/Scenes/SBMainScene.cpp | 10 - SHADE_Engine/src/Camera/SHCameraSystem.cpp | 28 +- .../Inspector/SHEditorComponentView.hpp | 4 +- .../Physics/Collision/SHCollisionListener.cpp | 254 ----------- .../Physics/Collision/SHCollisionListener.h | 80 ---- .../Physics/Collision/SHPhysicsRaycaster.cpp | 350 -------------- .../Physics/Collision/SHPhysicsRaycaster.h | 134 ------ .../Physics/Interface/SHColliderComponent.cpp | 131 +----- .../Physics/Interface/SHColliderComponent.h | 9 - .../Physics/Interface/SHCollisionShape.cpp | 82 ++-- .../Interface/SHRigidBodyComponent.cpp | 310 ++----------- .../Physics/Interface/SHRigidBodyComponent.h | 28 +- .../Physics/PhysicsObject/SHPhysicsObject.cpp | 431 ------------------ .../Physics/PhysicsObject/SHPhysicsObject.h | 111 ----- .../PhysicsObject/SHPhysicsObjectManager.cpp | 309 ------------- .../PhysicsObject/SHPhysicsObjectManager.h | 181 -------- .../System/SHPhysicsDebugDrawSystem.cpp | 334 -------------- .../Physics/System/SHPhysicsDebugDrawSystem.h | 138 ------ .../src/Physics/System/SHPhysicsSystem.cpp | 394 ---------------- .../src/Physics/System/SHPhysicsSystem.h | 151 +----- .../System/SHPhysicsSystemInterface.cpp | 96 +--- .../Physics/System/SHPhysicsSystemInterface.h | 9 +- .../System/SHPhysicsSystemRoutines.cpp | 307 +------------ SHADE_Managed/src/Components/Collider.cxx | 2 +- SHADE_Managed/src/Physics/Physics.cxx | 18 +- SHADE_Managed/src/Utility/Convert.cxx | 32 -- SHADE_Managed/src/Utility/Convert.hxx | 14 - 28 files changed, 131 insertions(+), 3845 deletions(-) delete mode 100644 SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp delete mode 100644 SHADE_Engine/src/Physics/Collision/SHCollisionListener.h delete mode 100644 SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp delete mode 100644 SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h delete mode 100644 SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp delete mode 100644 SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h delete mode 100644 SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp delete mode 100644 SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h delete mode 100644 SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp delete mode 100644 SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 5aa1eb00..ce0a939c 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -31,7 +31,6 @@ #include "Input/SHInputManager.h" #include "Math/Transform/SHTransformSystem.h" #include "Physics/System/SHPhysicsSystem.h" -#include "Physics/System/SHPhysicsDebugDrawSystem.h" #include "Scripting/SHScriptEngine.h" #include "UI/SHUISystem.h" @@ -74,9 +73,6 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); -#ifndef _PUBLISH - SHSystemManager::CreateSystem(); -#endif SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); @@ -116,10 +112,6 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); -#ifndef _PUBLISH - SHSystemManager::RegisterRoutine(); -#endif - SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); @@ -192,27 +184,6 @@ namespace Sandbox #else SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime()); #endif - // TODO: Move into an Editor menu - static bool drawContacts = false; - if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9)) - { - drawContacts = !drawContacts; - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts); - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts); - } - static bool drawColliders = false; - if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) - { - drawColliders = !drawColliders; - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders); - } - static bool drawRays = false; - if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F11)) - { - drawRays = !drawRays; - SHSystemManager::GetSystem()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); - } - } // Finish all graphics jobs first graphicsSystem->AwaitGraphicsExecution(); diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp index 73926115..55ce32b0 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -51,16 +51,6 @@ namespace Sandbox return; } - #ifdef SHEDITOR - - physicsSystem->ForceBuild(SHSceneManager::GetCurrentSceneGraph()); - - #else - - physicsSystem->BuildScene(SHSceneManager::GetCurrentSceneGraph()); - - #endif - /*-----------------------------------------------------------------------*/ /* TESTING CODE */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 8ef7ff64..d94bd3f8 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -186,20 +186,20 @@ namespace SHADE //SHLOG_INFO("Ray position: {},{},{} direction:{},{},{}",pivot.ray.position.x, pivot.ray.position.y, pivot.ray.position.z,pivot.ray.direction.x, pivot.ray.direction.y, pivot.ray.direction.z) - auto result = physicsSystem->Raycast(pivot.ray ); - if (result && result.distance < pivot.GetArmLength()) - { - - SHVec3 newOffset = SHVec3{ 0.0f,0.0f, result.distance * 0.8f }; - newOffset = SHVec3::RotateX(newOffset, -(SHMath::DegreesToRadians(pivot.GetPitch()))); - newOffset = SHVec3::RotateY(newOffset, (SHMath::DegreesToRadians(pivot.GetYaw()))); - pivot.offset = newOffset; - //SHLOG_INFO("CAMERA COLLISION HIT, {}", result.distance); - } - else - { - //SHLOG_INFO("CAMERA COLLISION CANT HIT CAMERA"); - } + //auto result = physicsSystem->Raycast(pivot.ray ); + //if (result && result.distance < pivot.GetArmLength()) + //{ + // + // SHVec3 newOffset = SHVec3{ 0.0f,0.0f, result.distance * 0.8f }; + // newOffset = SHVec3::RotateX(newOffset, -(SHMath::DegreesToRadians(pivot.GetPitch()))); + // newOffset = SHVec3::RotateY(newOffset, (SHMath::DegreesToRadians(pivot.GetYaw()))); + // pivot.offset = newOffset; + // //SHLOG_INFO("CAMERA COLLISION HIT, {}", result.distance); + //} + //else + //{ + // //SHLOG_INFO("CAMERA COLLISION CANT HIT CAMERA"); + //} diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 0f3dce3e..f70ab889 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -285,8 +285,8 @@ namespace SHADE if(ImGui::CollapsingHeader("Debug Information", ImGuiTreeNodeFlags_DefaultOpen))//Dynamic or Kinematic only fields { SHEditorWidgets::DragFloat("Mass", [component] { return component->GetMass(); }, [](float value){}, "Mass", 0.1f, 0.0f, std::numeric_limits::infinity(), "%.3f", ImGuiSliderFlags_ReadOnly); - SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component] {return component->GetPosition(); }, [](SHVec3 const& value) {}, false, "Position", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); - SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, [component] {return component->GetRotation(); }, [](SHVec3 const& value) {}, false, "Rotation", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); + //SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component] {return component->GetPosition(); }, [](SHVec3 const& value) {}, false, "Position", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); + //SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, [component] {return component->GetRotation(); }, [](SHVec3 const& value) {}, false, "Rotation", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { SHEditorWidgets::DragVec3("Velocity", { "X", "Y", "Z" }, [component] {return component->GetLinearVelocity(); }, [](SHVec3 const& value) {}, false, "Linear Velocity", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp deleted file mode 100644 index 3e485153..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionListener.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Collision Listener. - * - * \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 - -// Primary Header -#include "SHCollisionListener.h" - -// Project Headers -#include "ECS_Base/Managers/SHEntityManager.h" -#include "Physics/PhysicsObject/SHPhysicsObject.h" -#include "Physics/System/SHPhysicsSystem.h" -#include "Scene/SHSceneManager.h" - -/*-------------------------------------------------------------------------------------*/ -/* Local Helper Functions */ -/*-------------------------------------------------------------------------------------*/ - -uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID) -{ - for (uint32_t i = 0; i < physicsObject.GetCollisionBody()->getNbColliders(); ++i) - { - const auto* collider = physicsObject.GetCollisionBody()->getCollider(i); - if (collider->getEntity() == colliderID) - return i; - } - - return std::numeric_limits::max(); -} - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionListener::SHCollisionListener() noexcept - : system { nullptr } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const std::vector& SHCollisionListener::GetCollisionInfoContainer() const noexcept - { - return collisionInfoContainer; - } - - const std::vector& SHCollisionListener::GetTriggerInfoContainer() const noexcept - { - return triggerInfoContainer; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionListener::BindToSystem(SHPhysicsSystem* physicsSystem) noexcept - { - system = physicsSystem; - } - - void SHCollisionListener::BindToWorld(rp3d::PhysicsWorld* world) noexcept - { - if (!world) - return; - - world->setEventListener(this); - } - - void SHCollisionListener::CleanContainers() noexcept - { - static const auto CLEAR = [](std::vector& container) - { - for (auto eventIter = container.begin(); eventIter != container.end();) - { - const SHCollisionInfo& C_INFO = *eventIter; - - const bool INVALID_ENTITY = !SHEntityManager::IsValidEID(C_INFO.GetEntityA()) || !SHEntityManager::IsValidEID(C_INFO.GetEntityB()); - if (INVALID_ENTITY) - { - eventIter = container.erase(eventIter); - continue; - } - else - { - const bool CLEAR_EVENT = C_INFO.GetCollisionState() == SHCollisionInfo::State::EXIT || C_INFO.GetCollisionState() == SHCollisionInfo::State::INVALID; - - const bool INACTIVE_OBJECT = !SHSceneManager::CheckNodeAndComponentsActive(C_INFO.GetEntityA()) - || !SHSceneManager::CheckNodeAndComponentsActive(C_INFO.GetEntityB()); - - if (CLEAR_EVENT || INACTIVE_OBJECT) - { - eventIter = container.erase(eventIter); - continue; - } - } - - ++eventIter; - } - }; - - CLEAR(collisionInfoContainer); - CLEAR(triggerInfoContainer); - } - - void SHCollisionListener::ClearContainers() noexcept - { - collisionInfoContainer.clear(); - triggerInfoContainer.clear(); - } - - void SHCollisionListener::onContact(const rp3d::CollisionCallback::CallbackData& callbackData) - { - for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i) - { - const auto CONTACT_PAIR = callbackData.getContactPair(i); - const SHCollisionInfo NEW_INFO = generateCollisionInfo(CONTACT_PAIR); - - updateInfoContainers(NEW_INFO, collisionInfoContainer); - } - } - - void SHCollisionListener::onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData) - { - for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i) - { - const auto OVERLAP_PAIR = callbackData.getOverlappingPair(i); - const SHCollisionInfo NEW_INFO = generateTriggerInfo(OVERLAP_PAIR); - - updateInfoContainers(NEW_INFO, triggerInfoContainer); - } - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionListener::updateInfoContainers(const SHCollisionInfo& collisionEvent, std::vector& container) noexcept - { - const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionInfo& info) - { - const bool ENTITY_MATCH = (info.ids[0] == collisionEvent.ids[0] && info.ids[1] == collisionEvent.ids[1]) - || (info.ids[0] == collisionEvent.ids[1] && info.ids[1] == collisionEvent.ids[0]); - const bool COLLIDERS_MATCH = (info.ids[2] == collisionEvent.ids[2] && info.ids[3] == collisionEvent.ids[3]) - || (info.ids[2] == collisionEvent.ids[3] && info.ids[3] == collisionEvent.ids[2]); - return ENTITY_MATCH && COLLIDERS_MATCH; - }); - - if (IT == container.end()) - container.emplace_back(collisionEvent); - else - IT->collisionState = collisionEvent.collisionState; - } - - SHCollisionInfo SHCollisionListener::generateCollisionInfo(const rp3d::CollisionCallback::ContactPair& cp) const noexcept - { - SHCollisionInfo cInfo; - - // Update collision state - cInfo.collisionState = static_cast(cp.getEventType()); - - // Match body and collider for collision event - const rp3d::Entity body1 = cp.getBody1()->getEntity(); - const rp3d::Entity body2 = cp.getBody2()->getEntity(); - const rp3d::Entity collider1 = cp.getCollider1()->getEntity(); - const rp3d::Entity collider2 = cp.getCollider2()->getEntity(); - - // Find and match both ids - bool matched[2] = { false, false }; - - - for (auto& [entityID, physicsObject] : system->GetPhysicsObjects()) - { - // Match body 1 - if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1) - { - cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID; - cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1); - - matched[SHCollisionInfo::ENTITY_A] = true; - } - - // Match body 2 - if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2) - { - cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID; - cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2); - - matched[SHCollisionInfo::ENTITY_B] = true; - } - - if (matched[SHCollisionInfo::ENTITY_A] == true && matched[SHCollisionInfo::ENTITY_B] == true) - return cInfo; - } - - return cInfo; - } - - SHCollisionInfo SHCollisionListener::generateTriggerInfo(const rp3d::OverlapCallback::OverlapPair& cp) const noexcept - { - SHCollisionInfo cInfo; - - // Update collision state - cInfo.collisionState = static_cast(cp.getEventType()); - - // Match body and collider for collision event - const rp3d::Entity body1 = cp.getBody1()->getEntity(); - const rp3d::Entity body2 = cp.getBody2()->getEntity(); - const rp3d::Entity collider1 = cp.getCollider1()->getEntity(); - const rp3d::Entity collider2 = cp.getCollider2()->getEntity(); - - // Find and match both ids - bool matched[2] = { false, false }; - - - for (auto& [entityID, physicsObject] : system->GetPhysicsObjects()) - { - // Match body 1 - if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1) - { - cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID; - cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1); - - matched[SHCollisionInfo::ENTITY_A] = true; - } - - // Match body 2 - if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2) - { - cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID; - cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2); - - matched[SHCollisionInfo::ENTITY_B] = true; - } - - if (matched[SHCollisionInfo::ENTITY_A] == true && matched[SHCollisionInfo::ENTITY_B] == true) - return cInfo; - } - - return cInfo; - } - - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h deleted file mode 100644 index 62882556..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionListener.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Collision Listener. - * - * \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 - -// External Dependencies -#include - -// Project Headers -#include "SH_API.h" -#include "SHCollisionInfo.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - class SHPhysicsSystem; - - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHCollisionListener final : public rp3d::EventListener - { - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionListener() noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] const std::vector& GetCollisionInfoContainer () const noexcept; - [[nodiscard]] const std::vector& GetTriggerInfoContainer () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept; - void BindToWorld (rp3d::PhysicsWorld* world) noexcept; - void CleanContainers () noexcept; - void ClearContainers () noexcept; - - void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override; - void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override; - - private: - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsSystem* system; - std::vector collisionInfoContainer; - std::vector triggerInfoContainer; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - static void updateInfoContainers (const SHCollisionInfo& collisionEvent, std::vector& container) noexcept; - - SHCollisionInfo generateCollisionInfo (const rp3d::CollisionCallback::ContactPair& cp) const noexcept; - SHCollisionInfo generateTriggerInfo (const rp3d::OverlapCallback::OverlapPair& cp) const noexcept; - }; - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp deleted file mode 100644 index cab5c93b..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsRaycaster.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Physics Raycaster. - * - * \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 - -// Primary Header -#include "SHPhysicsRaycaster.h" - -/* - * TODO(DIREN): - * Once the physics engine has been rebuilt, this whole implementation should change - * and just call PhysicsWorld.Raycast etc. - * - * SHRaycastResult can be converted to a bool when necessary. - */ - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsRaycaster::SHPhysicsRaycaster() noexcept - : world { nullptr } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHPhysicsRaycaster::RaycastPairs& SHPhysicsRaycaster::GetRaycasts() const noexcept - { - return raycasts; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsRaycaster::SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept - { - objectManager = physicsObjectManager; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept - { - world = physicsWorld; - } - - void SHPhysicsRaycaster::ClearFrame() noexcept - { - raycasts.clear(); - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept - { - // Reset temp - temp = SHPhysicsRaycastResult{}; - temp.distance = distance; - - if (!world) - { - SHLOG_ERROR("Physics world missing for raycasting!") - return temp; - } - - // If distance in infinity, cast to the default max distance of 2 km. - if (distance == std::numeric_limits::infinity()) - { - world->raycast(ray, this, collisionTag); - } - else - { - const SHVec3 END_POINT = ray.position + ray.direction * distance; - const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; - world->raycast(RP3D_RAY, this, collisionTag); - } - - // If a hit was found, populate temp info for return. - if (temp.hit) - { - temp.distance = SHVec3::Distance(ray.position, temp.position); - temp.angle = SHVec3::Angle(ray.position, temp.position); - } - - raycasts.emplace_back(ray, temp); - return temp; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept - { - temp = SHPhysicsRaycastResult{}; - temp.distance = SHVec3::Distance(start, end); - - if (!world) - { - SHLOG_ERROR("Physics world missing for raycasting!") - return temp; - } - - const rp3d::Ray RP3D_RAY{ start, end }; - world->raycast(RP3D_RAY, this, collisionTag); - - if (temp.hit) - { - temp.distance = SHVec3::Distance(start, temp.position); - temp.angle = SHVec3::Angle(start, temp.position); - } - - raycasts.emplace_back(RP3D_RAY, temp); - return temp; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept - { - SHPhysicsRaycastResult result; - result.distance = distance; - - // Get a valid physics object with at least 1 collider. - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody(); - - // Data to populate - rp3d::RaycastInfo rp3dRaycastInfo; - bool hit = false; - - if (distance == std::numeric_limits::infinity()) - { - hit = rp3dBody->raycast(ray, rp3dRaycastInfo); - } - else - { - const SHVec3 END_POINT = ray.position + ray.direction * distance; - const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; - hit = rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo); - } - - if (hit) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(ray.position, result.position); - result.angle = SHVec3::Angle(ray.position, result.position); - result.entityHit = eid; - result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity()); - } - - raycasts.emplace_back(ray, result); - return result; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept - { - SHPhysicsRaycastResult result; - result.distance = distance; - - // Get a valid physics object with at least 1 collider. - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - // Boundary check for shape index - if (shapeIndex < 0 || shapeIndex >= static_cast(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders())) - { - SHLOGV_WARNING("Invalid collision shape index passed in") - return result; - } - - auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex); - - rp3d::RaycastInfo rp3dRaycastInfo; - bool hit = false; - if (distance == std::numeric_limits::infinity()) - { - hit = rp3dCollider->raycast(ray, rp3dRaycastInfo); - } - else - { - const SHVec3 END_POINT = ray.position + ray.direction * distance; - const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; - hit = rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo); - } - - if (hit) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(ray.position, result.position); - result.angle = SHVec3::Angle(ray.position, result.position); - result.entityHit = eid; - result.shapeIndex = shapeIndex; - } - - raycasts.emplace_back(ray, result); - return result; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept - { - SHPhysicsRaycastResult result; - result.distance = SHVec3::Distance(start, end); - - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody(); - - rp3d::RaycastInfo rp3dRaycastInfo; - - const rp3d::Ray RP3D_RAY{ start, end }; - if (rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo)) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(start, result.position); - result.angle = SHVec3::Angle(end, result.position); - result.entityHit = eid; - result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity()); - } - - raycasts.emplace_back(RP3D_RAY, result); - return result; - } - - SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept - { - SHPhysicsRaycastResult result; - result.distance = SHVec3::Distance(start, end); - - const auto* PHYSICS_OBJECT = validateColliderRaycast(eid); - if (!PHYSICS_OBJECT) - return result; - - if (shapeIndex < 0 || shapeIndex >= static_cast(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders())) - { - SHLOGV_WARNING("Invalid collision shape index passed in") - return result; - } - - auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex); - - rp3d::RaycastInfo rp3dRaycastInfo; - - const rp3d::Ray RP3D_RAY{ start, end }; - if (rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo)) - { - result.hit = true; - result.position = rp3dRaycastInfo.worldPoint; - result.normal = rp3dRaycastInfo.worldPoint; - result.distance = SHVec3::Distance(start, result.position); - result.angle = SHVec3::Angle(end, result.position); - result.entityHit = eid; - result.shapeIndex = shapeIndex; - } - - raycasts.emplace_back(RP3D_RAY, result); - return result; - } - - rp3d::decimal SHPhysicsRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) - { - temp.hit = true; - temp.position = raycastInfo.worldPoint; - temp.normal = raycastInfo.worldNormal; - - if (!objectManager) - { - SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies") - return 0.0f; - } - - // Compare body IDs to find the matching physics object - const auto HIT_BODY_EID = raycastInfo.body->getEntity(); - - for (const auto& [entityID, physicsObject] : objectManager->GetPhysicsObjects()) - { - const auto RP3D_BODY = physicsObject.GetCollisionBody(); - - // Match rp3d bodies - if (RP3D_BODY->getEntity() != HIT_BODY_EID) - continue; - - temp.entityHit = entityID; - - // Find collider index - if (const int INDEX = findColliderIndex(RP3D_BODY, raycastInfo.collider->getEntity()); INDEX > -1) - { - temp.shapeIndex = INDEX; - break; - } - } - - return 0.0f; - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject* SHPhysicsRaycaster::validateColliderRaycast(EntityID eid) noexcept - { - if (!objectManager) - { - SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies") - return nullptr; - } - - auto* physicsObject = objectManager->GetPhysicsObject(eid); - if (!physicsObject || physicsObject->GetCollisionBody()->getNbColliders() == 0) - { - SHLOGV_WARNING("Cannot cast ray at an entity without colliders!") - return nullptr; - } - - return physicsObject; - } - - int SHPhysicsRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept - { - const int NUM_COLLISION_SHAPES = static_cast(rp3dBody->getNbColliders()); - for (int i = 0; i < NUM_COLLISION_SHAPES; ++i) - { - const auto COLLIDER_EID = rp3dBody->getCollider(i)->getEntity(); - if (COLLIDER_EID == rp3dColliderEID) - return i; - } - - return -1; - } - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h deleted file mode 100644 index 447207c7..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsRaycaster.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Physics Raycaster. - * - * \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 - -#include - -// Project Headers -#include "Math/SHRay.h" -#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" -#include "Physics/SHPhysicsWorld.h" -#include "SH_API.h" -#include "SHCollisionTags.h" -#include "SHPhysicsRaycastResult.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHPhysicsRaycaster : public reactphysics3d::RaycastCallback - { - private: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using RaycastPair = std::pair; - using RaycastPairs = std::vector; - - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsRaycaster() noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] const RaycastPairs& GetRaycasts() const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept; - void ClearFrame () noexcept; - - // TODO(Diren): Filtering, return all shades ray hits - - SHPhysicsRaycastResult Raycast - ( - const SHRay& ray - , float distance = std::numeric_limits::infinity() - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - SHPhysicsRaycastResult Linecast - ( - const SHVec3& start - , const SHVec3& end - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , int shapeIndex - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , int shapeIndex - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - rp3d::PhysicsWorld* world; - SHPhysicsObjectManager* objectManager; // For - SHPhysicsRaycastResult temp; // Holds the temporary result after casting into the world - RaycastPairs raycasts; // Used for debug drawing - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject* validateColliderRaycast (EntityID eid) noexcept; - static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept; - }; - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index d7db2c64..eef92493 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -25,34 +25,12 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHColliderComponent::SHColliderComponent() noexcept - : system { nullptr } {} /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - - const SHVec3& SHColliderComponent::GetPosition() const noexcept - { - return position; - } - - const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept - { - return orientation; - } - - SHVec3 SHColliderComponent::GetRotation() const noexcept - { - return orientation.ToEuler(); - } - - const SHVec3& SHColliderComponent::GetScale() const noexcept - { - return scale; - } - const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept { return collisionShapes; @@ -72,22 +50,7 @@ namespace SHADE void SHColliderComponent::OnCreate() { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOG_ERROR("Physics System does not exist to link with Physics Components!") - return; - } - system = physicsSystem; - - // Sync with transform if one already exists - if (auto* transformComponent = SHComponentManager::GetComponent_s(GetEID()); transformComponent) - { - position = transformComponent->GetWorldPosition(); - orientation = transformComponent->GetWorldOrientation(); - scale = transformComponent->GetWorldScale(); - } } void SHColliderComponent::OnDestroy() @@ -97,112 +60,22 @@ namespace SHADE void SHColliderComponent::RecomputeCollisionShapes() noexcept { - for (auto& collisionShape : collisionShapes) - { - switch (collisionShape.GetType()) - { - case SHCollisionShape::Type::BOX: - { - auto* box = reinterpret_cast(collisionShape.shape); - const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents(); - // Recompute world extents based on new scale and fixed relative extents - - const SHVec3 WORLD_EXTENTS = RELATIVE_EXTENTS * (scale * 0.5f); - box->SetWorldExtents(WORLD_EXTENTS); - - continue; - } - case SHCollisionShape::Type::SPHERE: - { - auto* sphere = reinterpret_cast(collisionShape.shape); - const float RELATIVE_RADIUS = sphere->GetRelativeRadius(); - - // Recompute world radius based on new scale and fixed radius - - const float MAX_SCALE = SHMath::Max({ scale.x, scale.y, scale.z }); - const float WORLD_RADIUS = RELATIVE_RADIUS * MAX_SCALE * 0.5f; - sphere->SetWorldRadius(WORLD_RADIUS); - - continue; - } - default: continue; - } - } } int SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset, const SHVec3& rotOffset) noexcept { - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!") - return -1; - } - - static constexpr auto TYPE = SHCollisionShape::Type::BOX; - - auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE }); - - collider.entityID = GetEID(); - collider.SetPositionOffset(posOffset); - collider.SetRotationOffset(rotOffset); - collider.SetBoundingBox(halfExtents); - - // Notify Physics System - const int NEW_SHAPE_INDEX = static_cast(collisionShapes.size()) - 1; - - system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX); - return NEW_SHAPE_INDEX; + return 0; } int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept { - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!") - return -1; - } - - static constexpr auto TYPE = SHCollisionShape::Type::SPHERE; - - auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE }); - - collider.entityID = GetEID(); - collider.SetPositionOffset(posOffset); - collider.SetBoundingSphere(radius); - - // Notify Physics System - const int NEW_SHAPE_INDEX = static_cast(collisionShapes.size()) - 1; - - system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX); - return NEW_SHAPE_INDEX; + return 0; } void SHColliderComponent::RemoveCollider(int index) { - if (index < 0 || static_cast(index) >= collisionShapes.size()) - throw std::invalid_argument("Out-of-range access!"); - int idx = 0; - auto it = collisionShapes.begin(); - for (; it != collisionShapes.end(); ++it) - { - if (idx == index) - break; - - ++idx; - } - - it = collisionShapes.erase(it); - - // Notify Physics System - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to remove Collider!") - return; - } - - system->RemoveCollisionShape(GetEID(), index); } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index 0781f3cf..15a02173 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -69,11 +69,6 @@ namespace SHADE [[nodiscard]] bool HasChanged () const noexcept; - [[nodiscard]] const SHVec3& GetPosition () const noexcept; - [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; - [[nodiscard]] SHVec3 GetRotation () const noexcept; - [[nodiscard]] const SHVec3& GetScale () const noexcept; - [[nodiscard]] const CollisionShapes& GetCollisionShapes() const noexcept; [[nodiscard]] SHCollisionShape& GetCollisionShape (int index); @@ -97,10 +92,6 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHPhysicsSystem* system; - - SHVec3 position; - SHQuaternion orientation; SHVec3 scale; CollisionShapes collisionShapes; diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp index f597077f..4dd506f9 100644 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp @@ -190,63 +190,63 @@ namespace SHADE void SHCollisionShape::SetBoundingBox(const SHVec3& halfExtents) { - dirty = true; + //dirty = true; - const auto* COLLIDER = SHComponentManager::GetComponent(entityID); - auto* box = reinterpret_cast(shape); + //const auto* COLLIDER = SHComponentManager::GetComponent(entityID); + //auto* box = reinterpret_cast(shape); - SHVec3 correctedHalfExtents = halfExtents; + //SHVec3 correctedHalfExtents = halfExtents; - // Get current relative halfExtents for error checking. 0 is ignored - const SHVec3& CURRENT_RELATIVE_EXTENTS = box->GetRelativeExtents(); - for (size_t i = 0; i < SHVec3::SIZE; ++i) - { - if (SHMath::CompareFloat(halfExtents[i], 0.0f)) - correctedHalfExtents[i] = CURRENT_RELATIVE_EXTENTS[i]; - } - - // Set the half extents relative to world scale - const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale() * 0.5f; + //// Get current relative halfExtents for error checking. 0 is ignored + //const SHVec3& CURRENT_RELATIVE_EXTENTS = box->GetRelativeExtents(); + //for (size_t i = 0; i < SHVec3::SIZE; ++i) + //{ + // if (SHMath::CompareFloat(halfExtents[i], 0.0f)) + // correctedHalfExtents[i] = CURRENT_RELATIVE_EXTENTS[i]; + //} + // + //// Set the half extents relative to world scale + //const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale() * 0.5f; - if (type != Type::BOX) - { - type = Type::BOX; + //if (type != Type::BOX) + //{ + // type = Type::BOX; - delete shape; - shape = new SHBox{ positionOffset, WORLD_EXTENTS }; - } + // delete shape; + // shape = new SHBox{ positionOffset, WORLD_EXTENTS }; + //} - box->SetWorldExtents(WORLD_EXTENTS); - box->SetRelativeExtents(correctedHalfExtents); + //box->SetWorldExtents(WORLD_EXTENTS); + //box->SetRelativeExtents(correctedHalfExtents); } void SHCollisionShape::SetBoundingSphere(float radius) { - dirty = true; + //dirty = true; - auto* sphere = reinterpret_cast(shape); - const auto* COLLIDER = SHComponentManager::GetComponent(entityID); + //auto* sphere = reinterpret_cast(shape); + //const auto* COLLIDER = SHComponentManager::GetComponent(entityID); - // Get current relative halfExtents for error checking. 0 is ignored - const float CURRENT_RELATIVE_RADIUS = sphere->GetRelativeRadius(); - if (SHMath::CompareFloat(radius, 0.0f)) - radius = CURRENT_RELATIVE_RADIUS; + //// Get current relative halfExtents for error checking. 0 is ignored + //const float CURRENT_RELATIVE_RADIUS = sphere->GetRelativeRadius(); + //if (SHMath::CompareFloat(radius, 0.0f)) + // radius = CURRENT_RELATIVE_RADIUS; - // Set the radius relative to world scale - const SHVec3 WORLD_SCALE = COLLIDER->GetScale(); - const float MAX_SCALE = SHMath::Max({ WORLD_SCALE.x, WORLD_SCALE.y, WORLD_SCALE.z }); - const float WORLD_RADIUS = radius * MAX_SCALE * 0.5f; + //// Set the radius relative to world scale + //const SHVec3 WORLD_SCALE = COLLIDER->GetScale(); + //const float MAX_SCALE = SHMath::Max({ WORLD_SCALE.x, WORLD_SCALE.y, WORLD_SCALE.z }); + //const float WORLD_RADIUS = radius * MAX_SCALE * 0.5f; - if (type != Type::SPHERE) - { - type = Type::SPHERE; + //if (type != Type::SPHERE) + //{ + // type = Type::SPHERE; - delete shape; - shape = new SHSphere{ positionOffset, WORLD_RADIUS }; - } + // delete shape; + // shape = new SHSphere{ positionOffset, WORLD_RADIUS }; + //} - sphere->SetWorldRadius(WORLD_RADIUS); - sphere->SetRelativeRadius(radius); + //sphere->SetWorldRadius(WORLD_RADIUS); + //sphere->SetRelativeRadius(radius); } void SHCollisionShape::SetIsTrigger(bool trigger) noexcept diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index 330c3abe..6dad9020 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -28,18 +28,8 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHRigidBodyComponent::SHRigidBodyComponent() noexcept - : type { Type::DYNAMIC } - , flags { 0 } - , dirtyFlags { std::numeric_limits::max() } - , mass { 1.0f } - , drag { 0.01f } - , angularDrag { 0.01f } - , system { nullptr } { - // Initialise default flags - flags |= 1U << 0; // Gravity set to true - flags |= 1U << 1; // Sleeping allowed - flags |= 1U << 8; // Interpolate by default + } /*-----------------------------------------------------------------------------------*/ @@ -48,363 +38,166 @@ namespace SHADE bool SHRigidBodyComponent::IsGravityEnabled() const noexcept { - static constexpr int FLAG_POS = 0; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept { - static constexpr int FLAG_POS = 1; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::IsInterpolating() const noexcept { - static constexpr int FLAG_POS = 8; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::GetIsSleeping() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->isSleeping(); - return false; } SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept { - return type; + return Type::STATIC; } bool SHRigidBodyComponent::GetFreezePositionX() const noexcept { - static constexpr int FLAG_POS = 2; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::GetFreezePositionY() const noexcept { - static constexpr int FLAG_POS = 3; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept { - static constexpr int FLAG_POS = 4; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept { - static constexpr int FLAG_POS = 5; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept { - static constexpr int FLAG_POS = 6; - return flags & (1U << FLAG_POS); + return false; } bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept { - static constexpr int FLAG_POS = 7; - return flags & (1U << FLAG_POS); + return false; } - //bool SHRigidBodyComponent::GetAutoMass() const noexcept - //{ - // static constexpr int FLAG_POS = 9; - // return flags & (1U << FLAG_POS); - //} - float SHRigidBodyComponent::GetMass() const noexcept { - return mass; + return 0.0f; } float SHRigidBodyComponent::GetDrag() const noexcept { - return drag; + return 0.0f; } float SHRigidBodyComponent::GetAngularDrag() const noexcept { - return angularDrag; + return 0.0f; } SHVec3 SHRigidBodyComponent::GetForce() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getForce(); - return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetTorque() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getTorque(); - return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getLinearVelocity(); - return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - return physicsObject->GetRigidBody()->getAngularVelocity(); - return SHVec3::Zero; } - const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept - { - return position; - } - - const SHQuaternion& SHRigidBodyComponent::GetOrientation() const noexcept - { - return orientation; - } - - SHVec3 SHRigidBodyComponent::GetRotation() const noexcept - { - return orientation.ToEuler(); - } - /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ void SHRigidBodyComponent::SetType(Type newType) noexcept { - static constexpr int FLAG_POS = 8; - - if (type == newType) - return; - - type = newType; - dirtyFlags |= 1U << FLAG_POS; + } void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept { - static constexpr int FLAG_POS = 0; - - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - enableGravity ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept { - static constexpr int FLAG_POS = 1; - - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - isAllowedToSleep ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept { - static constexpr int FLAG_POS = 2; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - freezePositionX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept { - static constexpr int FLAG_POS = 3; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - freezePositionY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept { - static constexpr int FLAG_POS = 4; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - freezePositionZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept { - static constexpr int FLAG_POS = 5; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - freezeRotationX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept { - static constexpr int FLAG_POS = 6; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - freezeRotationY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept { - static constexpr int FLAG_POS = 7; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept { - static constexpr int FLAG_POS = 8; - allowInterpolation ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); + } - //void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept - //{ - // static constexpr int FLAG_POS = 9; - // autoMass ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); - - // dirtyFlags |= 1U << FLAG_POS; - //} - - //void SHRigidBodyComponent::SetMass(float newMass) noexcept - //{ - // static constexpr int FLAG_POS = 9; - - // if (newMass < 0.0f) - // return; - - // if (type != Type::DYNAMIC) - // { - // SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) - // return; - // } - - // dirtyFlags |= 1U << FLAG_POS; - // mass = newMass; - - // // Turn off automass - // flags &= ~(1U << FLAG_POS); - //} - void SHRigidBodyComponent::SetDrag(float newDrag) noexcept { - static constexpr int FLAG_POS = 10; - - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - drag = newDrag; + } void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept { - static constexpr int FLAG_POS = 11; - - if (type != Type::DYNAMIC) - { - SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID()) - return; - } - - dirtyFlags |= 1U << FLAG_POS; - angularDrag = newAngularDrag; + } void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID()) - return; - } - - auto* physicsObject = system->GetPhysicsObject(GetEID()); - if (!physicsObject) - { - SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID()) - return; - } - physicsObject->GetRigidBody()->setLinearVelocity(newLinearVelocity); + } void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept { - static constexpr int FLAG_POS = 13; - - if (type == Type::STATIC) - { - SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID()) - return; - } - - auto* physicsObject = system->GetPhysicsObject(GetEID()); - if (!physicsObject) - { - SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID()) - return; - } - physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity); + } /*-----------------------------------------------------------------------------------*/ @@ -413,81 +206,57 @@ namespace SHADE void SHRigidBodyComponent::OnCreate() { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOG_ERROR("Physics System does not exist to link with Physics Components!") - return; - } - - system = physicsSystem; - - // Sync with transform if one already exists - if (auto* transformComponent = SHComponentManager::GetComponent_s(GetEID()); transformComponent) - { - position = transformComponent->GetWorldPosition(); - orientation = transformComponent->GetWorldOrientation(); - } + } void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldForceAtCenterOfMass(force); + } void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldForceAtLocalPosition(force, localPos); + } void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldForceAtWorldPosition(force, worldPos); + } void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalForceAtCenterOfMass(relativeForce); + } void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalForceAtLocalPosition(relativeForce, localPos); + } void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalForceAtWorldPosition(relativeForce, worldPos); + } void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyWorldTorque(torque); + } void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->applyLocalTorque(relativeTorque); + } void SHRigidBodyComponent::ClearForces() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->resetForce(); + } void SHRigidBodyComponent::ClearTorque() const noexcept { - if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) - physicsObject->GetRigidBody()->resetTorque(); + } } // namespace SHADE @@ -512,7 +281,6 @@ RTTR_REGISTRATION .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled ) .property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate ) .property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep) - //.property("Auto Mass" , &SHRigidBodyComponent::GetAutoMass , &SHRigidBodyComponent::SetAutoMass ) .property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX ) .property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY ) .property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ ) diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index 532b3312..021743da 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -82,8 +82,6 @@ namespace SHADE [[nodiscard]] bool GetFreezeRotationY () const noexcept; [[nodiscard]] bool GetFreezeRotationZ () const noexcept; - //[[nodiscard]] bool GetAutoMass () const noexcept; - [[nodiscard]] float GetMass () const noexcept; [[nodiscard]] float GetDrag () const noexcept; [[nodiscard]] float GetAngularDrag () const noexcept; @@ -93,9 +91,9 @@ namespace SHADE [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; - [[nodiscard]] const SHVec3& GetPosition () const noexcept; - [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; - [[nodiscard]] SHVec3 GetRotation () const noexcept; + //[[nodiscard]] const SHVec3& GetPosition () const noexcept; + //[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + //[[nodiscard]] SHVec3 GetRotation () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ @@ -144,26 +142,6 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr size_t NUM_FLAGS = 8; - static constexpr size_t NUM_DIRTY_FLAGS = 12; - - Type type; - - uint16_t flags; // 0 0 0 0 0 0 am ip aZ aY aX lZ lY lX slp g - uint16_t dirtyFlags; // 0 0 0 0 aD d m t aZ aY aX lZ lY lX slp g - - float mass; - float drag; - float angularDrag; - - SHVec3 linearVelocity; - SHVec3 angularVelocity; - - SHPhysicsSystem* system; - - SHVec3 position; - SHQuaternion orientation; - RTTR_ENABLE() }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp deleted file mode 100644 index 71b08831..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsObject.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Physics Object. - * - * \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 - -// Primary Header -#include "SHPhysicsObject.h" - -// Project Headers -#include "ECS_Base/Managers/SHSystemManager.h" -#include "ECS_Base/Managers/SHComponentManager.h" -#include "Scene/SHSceneManager.h" - - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept - : entityID { eid } - , collidersActive { true } - , factory { physicsFactory } - , world { physicsWorld } - , rp3dBody { nullptr } - { - // Implicitly create a static body. - - const auto* TRANSFORM = SHComponentManager::GetComponent(eid); - - const rp3d::Transform RP3D_TRANSFORM { TRANSFORM->GetWorldPosition(), TRANSFORM->GetWorldOrientation() }; - - rp3dBody = world->createRigidBody(RP3D_TRANSFORM); - rp3dBody->setType(rp3d::BodyType::STATIC); - } - - SHPhysicsObject::~SHPhysicsObject() noexcept - { - factory = nullptr; - world = nullptr; - rp3dBody = nullptr; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHVec3 SHPhysicsObject::GetPosition() const noexcept - { - return rp3dBody->getTransform().getPosition(); - } - - SHQuaternion SHPhysicsObject::GetOrientation() const noexcept - { - return rp3dBody->getTransform().getOrientation(); - } - - SHVec3 SHPhysicsObject::GetRotation() const noexcept - { - return SHQuaternion{ rp3dBody->getTransform().getOrientation() }.ToEuler(); - } - - rp3d::CollisionBody* SHPhysicsObject::GetCollisionBody() const noexcept - { - return rp3dBody; - } - - rp3d::RigidBody* SHPhysicsObject::GetRigidBody() const noexcept - { - return rp3dBody; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsObject::SetStaticBody() const noexcept - { - if (!rp3dBody) - return; - - rp3dBody->setType(rp3d::BodyType::STATIC); - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - int SHPhysicsObject::AddCollisionShape(int index) - { - // Get collider component - auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); - if (!colliderComponent) - { - SHLOGV_ERROR("Unable to add Collision Shape to Entity {} due to Missing Collider Component!", entityID) - return -1; - } - - auto& collisionShape = colliderComponent->GetCollisionShape(index); - switch (collisionShape.GetType()) - { - // TODO(Diren): Add more collider shapes - - case SHCollisionShape::Type::BOX: - { - addBoxShape(collisionShape); - break; - } - - case SHCollisionShape::Type::SPHERE: - { - addSphereShape(collisionShape); - break; - } - default: break; - } - - auto* rp3dCollider = rp3dBody->getCollider(rp3dBody->getNbColliders() - 1); - syncColliderProperties(collisionShape, rp3dCollider); - - if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC) - { - rp3dBody->updateMassPropertiesFromColliders(); - - if (auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); rigidBodyComponent) - rigidBodyComponent->mass = rp3dBody->getMass(); - } - - return index; - } - - void SHPhysicsObject::RemoveCollisionShape(int index) - { - const int NUM_COLLIDERS = static_cast(rp3dBody->getNbColliders()); - if (NUM_COLLIDERS == 0) - return; - - if (index < 0 || index >= NUM_COLLIDERS) - throw std::invalid_argument("Index out of range!"); - - auto* collider = rp3dBody->getCollider(index); - rp3dBody->removeCollider(collider); - - if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC) - { - rp3dBody->updateMassPropertiesFromColliders(); - - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - if (rigidBodyComponent) - rigidBodyComponent->mass = rp3dBody->getMass(); - } - } - - void SHPhysicsObject::RemoveAllCollisionShapes() const noexcept - { - int numColliders = static_cast(rp3dBody->getNbColliders()); - if (numColliders == 0) - return; - - while (numColliders - 1 >= 0) - { - auto* collider = rp3dBody->getCollider(numColliders - 1); - rp3dBody->removeCollider(collider); - - --numColliders; - } - } - - void SHPhysicsObject::SyncRigidBody(SHRigidBodyComponent& component) const noexcept - { - // This state is synced in the pre-update routine - if (!rp3dBody->isActive()) - return; - - if (component.dirtyFlags == 0) - return; - - for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i) - { - if (const bool IS_DIRTY = component.dirtyFlags & (1U << i); IS_DIRTY) - { - switch (i) - { - case 0: // Gravity - { - const bool IS_ENABLED = component.flags & (1U << i); - rp3dBody->enableGravity(IS_ENABLED); - - break; - } - case 1: // Sleeping - { - const bool IS_ENABLED = component.flags & (1U << i); - rp3dBody->setIsAllowedToSleep(IS_ENABLED); - - break; - } - case 2: // Lock Position X - { - const bool IS_ENABLED = component.flags & (1U << i); - - auto positionLock = rp3dBody->getLinearLockAxisFactor(); - positionLock.x = IS_ENABLED ? 0.0f : 1.0f; - rp3dBody->setLinearLockAxisFactor(positionLock); - - break; - } - case 3: // Lock Position Y - { - const bool IS_ENABLED = component.flags & (1U << i); - - auto positionLock = rp3dBody->getLinearLockAxisFactor(); - positionLock.y = IS_ENABLED ? 0.0f : 1.0f; - rp3dBody->setLinearLockAxisFactor(positionLock); - - break; - } - case 4: // Lock Position Z - { - const bool IS_ENABLED = component.flags & (1U << i); - - auto positionLock = rp3dBody->getLinearLockAxisFactor(); - positionLock.z = IS_ENABLED ? 0.0f : 1.0f; - rp3dBody->setLinearLockAxisFactor(positionLock); - - break; - } - case 5: // Lock Rotation X - { - const bool IS_ENABLED = component.flags & (1U << i); - - auto rotationLock = rp3dBody->getAngularLockAxisFactor(); - rotationLock.x = IS_ENABLED ? 0.0f : 1.0f; - rp3dBody->setAngularLockAxisFactor(rotationLock); - - break; - } - case 6: // Lock Rotation Y - { - const bool IS_ENABLED = component.flags & (1U << i); - - auto rotationLock = rp3dBody->getAngularLockAxisFactor(); - rotationLock.y = IS_ENABLED ? 0.0f : 1.0f; - rp3dBody->setAngularLockAxisFactor(rotationLock); - - break; - } - case 7: // Lock Rotation Z - { - const bool IS_ENABLED = component.flags & (1U << i); - - auto rotationLock = rp3dBody->getAngularLockAxisFactor(); - rotationLock.z = IS_ENABLED ? 0.0f : 1.0f; - rp3dBody->setAngularLockAxisFactor(rotationLock); - - break; - } - case 8: // Type - { - rp3dBody->setType(static_cast(component.type)); - - break; - } - case 9: // Mass - { - //rp3dBody->setMass(component.mass); - - //if (component.GetAutoMass()) - //{ - // rp3dBody->updateMassPropertiesFromColliders(); - // component.mass = rp3dBody->getMass(); - //} - //else - //{ - // rp3dBody->setMass(component.mass); - // rp3dBody->updateLocalCenterOfMassFromColliders(); - // rp3dBody->updateLocalInertiaTensorFromColliders(); - //} - - break; - } - case 10: // Drag - { - rp3dBody->setLinearDamping(component.drag); - - break; - } - case 11: // Angular Drag - { - rp3dBody->setAngularDamping(component.angularDrag); - - break; - } - default: break; - } - } - } - - component.dirtyFlags = 0; - } - - void SHPhysicsObject::SyncColliders(SHColliderComponent& component) const noexcept - { - // This state is synced in the pre-update routine - if (!rp3dBody->isActive()) - return; - - const int NUM_SHAPES = static_cast(rp3dBody->getNbColliders()); - for (int i = 0; i < NUM_SHAPES; ++i) - { - auto& collisionShape = component.collisionShapes[i]; - - if (!collisionShape.dirty) - continue; - - switch (collisionShape.GetType()) - { - case SHCollisionShape::Type::BOX: syncBoxShape(i, collisionShape); break; - case SHCollisionShape::Type::SPHERE: syncSphereShape(i, collisionShape); break; - default: break; - } - - auto* rp3dCollider = rp3dBody->getCollider(i); - syncColliderProperties(collisionShape, rp3dCollider); - - collisionShape.dirty = false; - } - - // Set rigidbody mass if dynamic - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - if (rigidBodyComponent) - { - // This is generally expensive, will be optimised in the future with my own engine. - rp3dBody->updateMassPropertiesFromColliders(); - rigidBodyComponent->mass = rp3dBody->getMass(); - } - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsObject::syncColliderProperties(const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept - { - rp3dCollider->setIsTrigger(collisionShape.IsTrigger()); - - auto& rp3dMaterial = rp3dCollider->getMaterial(); - - rp3dMaterial.setFrictionCoefficient(collisionShape.GetFriction()); - rp3dMaterial.setBounciness(collisionShape.GetBounciness()); - rp3dMaterial.setMassDensity(collisionShape.GetDensity()); - - const unsigned short MASK_BITS = collisionShape.GetCollisionTag(); - rp3dCollider->setCollisionCategoryBits(MASK_BITS); - rp3dCollider->setCollideWithMaskBits(MASK_BITS); - } - - void SHPhysicsObject::addBoxShape(const SHCollisionShape& boxShape) const noexcept - { - const rp3d::Transform OFFSETS - { - boxShape.GetPositionOffset() - , boxShape.GetRotationOffset() - }; - - const auto* BOX = reinterpret_cast(boxShape.GetShape()); - rp3d::BoxShape* newBox = factory->createBoxShape(BOX->GetWorldExtents()); - - rp3dBody->addCollider(newBox, OFFSETS); - } - - void SHPhysicsObject::syncBoxShape(int index, const SHCollisionShape& boxShape) const noexcept - { - const auto* BOX = reinterpret_cast(boxShape.GetShape()); - - auto* rp3dCollider = rp3dBody->getCollider(index); - auto* rp3dBox = reinterpret_cast(rp3dCollider->getCollisionShape()); - - const rp3d::Transform OFFSETS - { - boxShape.GetPositionOffset() - , boxShape.GetRotationOffset() - }; - - rp3dCollider->setIsTrigger(boxShape.IsTrigger()); - rp3dCollider->setLocalToBodyTransform(OFFSETS); - - rp3dBox->setHalfExtents(BOX->GetWorldExtents()); - } - - void SHPhysicsObject::addSphereShape(const SHCollisionShape& sphereShape) const noexcept - { - const rp3d::Transform OFFSETS - { - sphereShape.GetPositionOffset() - , sphereShape.GetRotationOffset() - }; - - const auto* SPHERE = reinterpret_cast(sphereShape.GetShape()); - rp3d::SphereShape* newSphere = factory->createSphereShape(SPHERE->GetWorldRadius()); - - rp3dBody->addCollider(newSphere, OFFSETS); - } - - void SHPhysicsObject::syncSphereShape(int index, const SHCollisionShape& sphereShape) const noexcept - { - const auto* SPHERE = reinterpret_cast(sphereShape.GetShape()); - - auto* rp3dCollider = rp3dBody->getCollider(index); - auto* rp3dSphere = reinterpret_cast(rp3dCollider->getCollisionShape()); - - const rp3d::Transform OFFSETS - { - sphereShape.GetPositionOffset() - , sphereShape.GetRotationOffset() - }; - - rp3dCollider->setIsTrigger(sphereShape.IsTrigger()); - rp3dCollider->setLocalToBodyTransform(OFFSETS); - - rp3dSphere->setRadius(SPHERE->GetWorldRadius()); - } -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h deleted file mode 100644 index c572ca2e..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsObject.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Physics Object. - * - * \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 - -// Project Headers -#include "Math/Transform/SHTransformComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" -#include "Physics/Interface/SHColliderComponent.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHPhysicsObject - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHPhysicsSystem; - friend class SHPhysicsObjectManager; - - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject (EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept; - SHPhysicsObject (const SHPhysicsObject& rhs) noexcept = default; - SHPhysicsObject (SHPhysicsObject&& rhs) noexcept = default; - virtual ~SHPhysicsObject () noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept = default; - SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept = default; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] SHVec3 GetPosition () const noexcept; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept; - [[nodiscard]] SHVec3 GetRotation () const noexcept; - - [[nodiscard]] rp3d::CollisionBody* GetCollisionBody () const noexcept; - [[nodiscard]] rp3d::RigidBody* GetRigidBody () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetStaticBody () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - int AddCollisionShape (int index); - void RemoveCollisionShape (int index); - void RemoveAllCollisionShapes () const noexcept; - - void SyncRigidBody (SHRigidBodyComponent& component) const noexcept; - void SyncColliders (SHColliderComponent& component) const noexcept; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - EntityID entityID; - bool collidersActive; // Only used to sync with SHADE components - - rp3d::PhysicsCommon* factory; - rp3d::PhysicsWorld* world; - - rp3d::RigidBody* rp3dBody; - rp3d::Transform prevTransform; // Cached transform for interpolation - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void syncColliderProperties (const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept; - - // Box Shapes - - void addBoxShape (const SHCollisionShape& boxShape) const noexcept; - void syncBoxShape (int index, const SHCollisionShape& boxShape) const noexcept; - - // Sphere Shapes - - void addSphereShape (const SHCollisionShape& sphereShape) const noexcept; - void syncSphereShape (int index, const SHCollisionShape& sphereShape) const noexcept; - }; -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp deleted file mode 100644 index 7c111a2d..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsObjectManager.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Physics Object Manager. - * - * \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 - -// Primary Header -#include "SHPhysicsObjectManager.h" - -// Project Headers -#include "ECS_Base/Managers/SHEntityManager.h" -#include "Tools/Utilities/SHUtilities.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Static Data Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[3][2] - { - addRigidBody , addCollider , addCollisionShape - , removeRigidBody , removeCollider , removeCollisionShape - }; - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsObjectManager::SetFactory(rp3d::PhysicsCommon& physicsFactory) noexcept - { - factory = &physicsFactory; - } - - void SHPhysicsObjectManager::SetWorld(rp3d::PhysicsWorld* physicsWorld) noexcept - { - world = physicsWorld; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID eid) noexcept - { - const auto it = physicsObjects.find(eid); - if (it == physicsObjects.end()) - return nullptr; - - return &it->second; - } - - const SHPhysicsObjectManager::PhysicsObjectEntityMap SHPhysicsObjectManager::GetPhysicsObjects() const noexcept - { - return physicsObjects; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsObjectManager::AddRigidBody(EntityID eid) noexcept - { - const QueueCommand NEW_QUEUE_COMMAND - { - .eid = eid - , .command = QueueCommand::Command::ADD - , .component = PhysicsComponents::RIGID_BODY - }; - - commandQueue.push(NEW_QUEUE_COMMAND); - } - - void SHPhysicsObjectManager::AddCollider(EntityID eid) noexcept - { - const QueueCommand NEW_QUEUE_COMMAND - { - .eid = eid - , .command = QueueCommand::Command::ADD - , .component = PhysicsComponents::COLLIDER - }; - - commandQueue.push(NEW_QUEUE_COMMAND); - } - - void SHPhysicsObjectManager::AddCollisionShape(EntityID eid, int shapeIndex) noexcept - { - const QueueCommand NEW_QUEUE_COMMAND - { - .eid = eid - , .command = QueueCommand::Command::ADD - , .component = PhysicsComponents::COLLISION_SHAPE - , .shapeIndex = shapeIndex - }; - - commandQueue.push(NEW_QUEUE_COMMAND); - } - - void SHPhysicsObjectManager::RemoveRigidBody(EntityID eid) noexcept - { - const QueueCommand NEW_QUEUE_COMMAND - { - .eid = eid - , .command = QueueCommand::Command::REMOVE - , .component = PhysicsComponents::RIGID_BODY - }; - - commandQueue.push(NEW_QUEUE_COMMAND); - } - - void SHPhysicsObjectManager::RemoveCollider(EntityID eid) noexcept - { - const QueueCommand NEW_QUEUE_COMMAND - { - .eid = eid - , .command = QueueCommand::Command::REMOVE - , .component = PhysicsComponents::COLLIDER - }; - - commandQueue.push(NEW_QUEUE_COMMAND); - } - - void SHPhysicsObjectManager::RemoveCollisionShape(EntityID eid, int shapeIndex) noexcept - { - const QueueCommand NEW_QUEUE_COMMAND - { - .eid = eid - , .command = QueueCommand::Command::REMOVE - , .component = PhysicsComponents::COLLISION_SHAPE - , .shapeIndex = shapeIndex - }; - - commandQueue.push(NEW_QUEUE_COMMAND); - } - - void SHPhysicsObjectManager::UpdateCommands() - { - if (commandQueue.empty()) - return; - - while (!commandQueue.empty()) - { - const QueueCommand COMMAND = commandQueue.front(); - commandQueue.pop(); - - // Check validity of command - if (COMMAND.command == QueueCommand::Command::INVALID || COMMAND.component == PhysicsComponents::INVALID) - continue; - - // Get physics components - const PhysicsComponentGroup COMPONENT_GROUP - { - .eid = COMMAND.eid - , .rigidBodyComponent = SHComponentManager::GetComponent_s(COMMAND.eid) - , .colliderComponent = SHComponentManager::GetComponent_s(COMMAND.eid) - }; - - // Delete any object that is missing both components - // We infer that a remove command has been pushed for these, but we will ignore those if both components have already been removed. - if (!COMPONENT_GROUP.rigidBodyComponent && !COMPONENT_GROUP.colliderComponent) - { - destroyPhysicsObject(COMMAND.eid); - wakeAllObjects(); - continue; - } - - // Find the physics Object. If none found and attempting to add, create an object. - SHPhysicsObject* physicsObject = GetPhysicsObject(COMMAND.eid); - if (!physicsObject && COMMAND.command == QueueCommand::Command::ADD) - physicsObject = createPhysicsObject(COMMAND.eid); - - componentFunc[SHUtilities::ConvertEnum(COMMAND.command)][SHUtilities::ConvertEnum(COMMAND.component)](COMMAND, physicsObject, COMPONENT_GROUP); - - // If any removal was done, wake all objects - if (COMMAND.command == QueueCommand::Command::REMOVE) - wakeAllObjects(); - } - } - - void SHPhysicsObjectManager::RemoveAllObjects() - { - // Destroy all objects and clear - for (auto& physicsObject : physicsObjects | std::views::values) - { - world->destroyRigidBody(physicsObject.GetRigidBody()); - physicsObject.rp3dBody = nullptr; - } - - physicsObjects.clear(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID eid) noexcept - { - // Force transforms to sync - SHVec3 worldPos = SHVec3::Zero; - SHQuaternion worldRot = SHQuaternion::Identity; - - const SHTransformComponent* TRANSFORM = nullptr; - if (SHEntityManager::IsValidEID(eid)) - TRANSFORM = SHComponentManager::GetComponent_s(eid); - - if (TRANSFORM) - { - worldPos = TRANSFORM->GetWorldPosition(); - worldRot = TRANSFORM->GetWorldOrientation(); - } - - const rp3d::Transform RP3D_TRANSFORM{ worldPos, worldRot }; - - auto& newPhysicsObject = physicsObjects.emplace(eid, SHPhysicsObject{ eid, factory, world }).first->second; - newPhysicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM); - newPhysicsObject.prevTransform = RP3D_TRANSFORM; - - return &newPhysicsObject; - } - - void SHPhysicsObjectManager::destroyPhysicsObject(EntityID eid) noexcept - { - const auto ITER = physicsObjects.find(eid); - if (ITER == physicsObjects.end()) - { - // Assume the object has already been successfully destroyed - return; - } - - world->destroyRigidBody(ITER->second.GetRigidBody()); - ITER->second.rp3dBody = nullptr; - - physicsObjects.erase(eid); - } - - void SHPhysicsObjectManager::addRigidBody(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup) - { - SHASSERT(physicsObject != nullptr, "Valid physics object required to add body!") - - if (!componentGroup.rigidBodyComponent) - { - SHLOG_ERROR("Entity {} is missing a Rigidbody Component. Unable to update physics object!", componentGroup.eid) - return; - } - - // A static rigid body is implicitly created on creation of a physics object. - // Nothing is needed here. - } - - void SHPhysicsObjectManager::addCollider(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup) - { - SHASSERT(physicsObject != nullptr, "Valid physics object required to add collider!") - - if (!componentGroup.colliderComponent) - { - SHLOG_ERROR("Entity {} is missing a Rigidbody Component. Unable to update physics object!", componentGroup.eid) - return; - } - - //const int NUM_SHAPES = static_cast(componentGroup.colliderComponent->GetCollisionShapes().size()); - //for (int i = 0; i < NUM_SHAPES; ++i) - // physicsObject->AddCollisionShape(i); - - physicsObject->SyncColliders(*componentGroup.colliderComponent); - } - - void SHPhysicsObjectManager::removeRigidBody(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup) - { - SHASSERT(physicsObject != nullptr, "Valid physics object required to remove body!") - - if (componentGroup.colliderComponent) - physicsObject->SetStaticBody(); - } - - void SHPhysicsObjectManager::removeCollider(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&) - { - SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collider!") - - physicsObject->RemoveAllCollisionShapes(); - } - - void SHPhysicsObjectManager::addCollisionShape(const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&) - { - SHASSERT(physicsObject != nullptr, "Valid physics object required to add collision shape!") - - physicsObject->AddCollisionShape(command.shapeIndex); - } - - void SHPhysicsObjectManager::removeCollisionShape(const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&) - { - SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collision shape!") - - physicsObject->RemoveCollisionShape(command.shapeIndex); - } - - void SHPhysicsObjectManager::wakeAllObjects() noexcept - { - for (auto& physicsObject : physicsObjects | std::views::values) - physicsObject.GetRigidBody()->setIsSleeping(false); - } - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h deleted file mode 100644 index f41c62ad..00000000 --- a/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsObjectManager.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Physics Object Manager. - * - * \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 -#include - -#include - -// Project Headers -#include "SHPhysicsObject.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHPhysicsObjectManager - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHPhysicsSystem; - - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using PhysicsObjectEntityMap = std::unordered_map; - - public: - - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class PhysicsComponents - { - RIGID_BODY - , COLLIDER - , COLLISION_SHAPE - - , TOTAL - , INVALID = -1 - }; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObjectManager () = default; - ~SHPhysicsObjectManager () = default; - - SHPhysicsObjectManager (const SHPhysicsObjectManager&) = delete; - SHPhysicsObjectManager (SHPhysicsObjectManager&&) = delete; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObjectManager& operator=(const SHPhysicsObjectManager&) = delete; - SHPhysicsObjectManager& operator=(SHPhysicsObjectManager&&) = delete; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept; - [[nodiscard]] const PhysicsObjectEntityMap GetPhysicsObjects () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetFactory (rp3d::PhysicsCommon& physicsFactory) noexcept; - void SetWorld (rp3d::PhysicsWorld* physicsWorld) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void AddRigidBody (EntityID eid) noexcept; - void AddCollider (EntityID eid) noexcept; - void AddCollisionShape (EntityID eid, int shapeIndex) noexcept; - - void RemoveRigidBody (EntityID eid) noexcept; - void RemoveCollider (EntityID eid) noexcept; - void RemoveCollisionShape (EntityID eid, int shapeIndex) noexcept; - - void UpdateCommands (); - void RemoveAllObjects (); - - private: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - struct QueueCommand - { - /*-------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-------------------------------------------------------------------------------*/ - - enum class Command - { - ADD - , REMOVE - - , INVALID = -1 - }; - - /*-------------------------------------------------------------------------------*/ - /* Data Members */ - /*-------------------------------------------------------------------------------*/ - - EntityID eid = MAX_EID; - Command command = Command::INVALID; - PhysicsComponents component = PhysicsComponents::INVALID; - int shapeIndex = -1; // Only used when adding & removing collision shapes - }; - - struct PhysicsComponentGroup - { - public: - - /*-------------------------------------------------------------------------------*/ - /* Data Members */ - /*-------------------------------------------------------------------------------*/ - - - EntityID eid = MAX_EID; - SHRigidBodyComponent* rigidBodyComponent = nullptr; - SHColliderComponent* colliderComponent = nullptr; - }; - - using CommandFunctionPtr = void(*)(const QueueCommand&, SHPhysicsObject*, const PhysicsComponentGroup&); - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - static CommandFunctionPtr componentFunc[3][2]; // 3 components, 2 commands - - rp3d::PhysicsCommon* factory = nullptr; - rp3d::PhysicsWorld* world = nullptr; - - PhysicsObjectEntityMap physicsObjects; - std::queue commandQueue; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsObject* createPhysicsObject (EntityID eid) noexcept; - void destroyPhysicsObject (EntityID eid) noexcept; - - void wakeAllObjects () noexcept; - - static void addRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup); - static void addCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup); - static void removeRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup); - static void removeCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup); - - static void addCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup); - static void removeCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup); - - - }; - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp deleted file mode 100644 index 1ca7ae39..00000000 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsDebugDrawSystem.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for the Physics Debug Draw System - * - * \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 - -// Primary Header -#include "SHPhysicsDebugDrawSystem.h" - -// Project Headers -#include "ECS_Base/Managers/SHSystemManager.h" -#include "Editor/SHEditor.h" -#include "Scene/SHSceneManager.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Static Data Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[NUM_FLAGS] = - { - drawColliders - , drawColliderAABBs - , drawBroadPhaseAABBs - , drawContactPoints - , drawContactNormals - , drawRaycasts - }; - - SHVec3 SHPhysicsDebugDrawSystem::boxVertices[NUM_BOX_VERTICES]; - - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept - : debugDrawFlags { 0 } - , physicsSystem { nullptr } - { - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER)] = SHColour::GREEN; - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB)] = SHColour::YELLOW; - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB)] = SHColour::CYAN; - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS)] = SHColour::RED; - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS)] = SHColour::RED; - debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::RAYCASTS)] = SHColour::ORANGE; - } - - SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine() - : SHSystemRoutine { "Physics Debug Draw", true } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept - { - const auto INT_FLAG = SHUtilities::ConvertEnum(flag); - if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS) - { - SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to get debug draw state!", INT_FLAG) - return false; - } - - return debugDrawFlags & 1U << SHUtilities::ConvertEnum(flag); - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept - { - const auto INT_FLAG = SHUtilities::ConvertEnum(flag); - if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS) - { - SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to set debug draw state!", INT_FLAG) - return; - } - - value ? (debugDrawFlags |= 1U << INT_FLAG) : (debugDrawFlags &= ~(1U << INT_FLAG)); - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsDebugDrawSystem::Init() - { - SystemFamily::GetID(); - - SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!") - physicsSystem = SHSystemManager::GetSystem(); - - // Generate shapes - generateBox(); - } - - void SHPhysicsDebugDrawSystem::Exit() - { - physicsSystem = nullptr; - } - - void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept - { - auto* system = reinterpret_cast(GetSystem()); - - auto* debugDrawSystem = SHSystemManager::GetSystem(); - if (debugDrawSystem == nullptr) - { - SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!") - return; - } - - rp3d::DebugRenderer* rp3dRenderer = nullptr; - if (system->physicsSystem->worldState.world) - rp3dRenderer = &system->physicsSystem->worldState.world->getDebugRenderer(); - - for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i) - { - const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0; - if (DRAW) - { - drawFunctions[i](debugDrawSystem, rp3dRenderer); - } - else - { - if (rp3dRenderer && (i == 3 || i == 4)) - { - rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_POINT, false); - rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_NORMAL, false); - } - } - - } - - // Automatically clear the container of raycasts despite debug drawing state - // TODO(Diren): Move this somewhere else - system->physicsSystem->raycaster.ClearFrame(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsDebugDrawSystem::drawColliders(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - const auto& COLLIDER_SET = SHComponentManager::GetDense(); - for (const auto& COLLIDER : COLLIDER_SET) - { - // Skip inactive colliders - if (!SHSceneManager::CheckNodeAndComponentsActive(COLLIDER.GetEID())) - continue; - - for (auto& collisionShape : COLLIDER.GetCollisionShapes()) - { - switch (collisionShape.GetType()) - { - case SHCollisionShape::Type::BOX: debugDrawBox(debugRenderer, COLLIDER, collisionShape); break; - case SHCollisionShape::Type::SPHERE: debugDrawSphere(debugRenderer, COLLIDER, collisionShape); break; - default: break; - } - } - } - } - - void SHPhysicsDebugDrawSystem::drawColliderAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - - } - - void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - - } - - void SHPhysicsDebugDrawSystem::drawContactPoints(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - #ifdef SHEDITOR - - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - { - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true); - const int NUM_TRIS = static_cast(rp3dRenderer->getNbTriangles()); - if (NUM_TRIS == 0) - return; - - const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray(); - for (int i = 0; i < NUM_TRIS; ++i) - debugRenderer->DrawTri(SHColour::RED, TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3); - } - - #else - - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true); - const int NUM_TRIS = static_cast(rp3dRenderer->getNbTriangles()); - if (NUM_TRIS == 0) - return; - - const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray(); - for (int i = 0; i < NUM_TRIS; ++i) - debugRenderer->DrawTri(SHColour::RED, TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3); - - #endif - } - - void SHPhysicsDebugDrawSystem::drawContactNormals(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - #ifdef SHEDITOR - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - { - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true); - const int NUM_LINES = static_cast(rp3dRenderer->getNbLines()); - if (NUM_LINES == 0) - return; - - const auto& LINE_ARRAY = rp3dRenderer->getLinesArray(); - for (int i = 0; i < NUM_LINES; ++i) - debugRenderer->DrawLine(SHColour::RED, LINE_ARRAY[i].point1, LINE_ARRAY[i].point2); - } - - #else - - rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true); - const int NUM_LINES = static_cast(rp3dRenderer->getNbLines()); - if (NUM_LINES == 0) - return; - - const auto& LINE_ARRAY = rp3dRenderer->getLinesArray(); - for (int i = 0; i < NUM_LINES; ++i) - debugRenderer->DrawLine(SHColour::RED, LINE_ARRAY[i].point1, LINE_ARRAY[i].point2); - - #endif - } - - void SHPhysicsDebugDrawSystem::drawRaycasts(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOG_ERROR("Unable to retrieve physics system for debug drawing raycasts!") - return; - } - - const SHColour& RAY_COLOUR = SHColour::ORANGE; - - // Draw all raycast pairs - for (const auto& [ray, raycastResult] : physicsSystem->raycaster.GetRaycasts()) - { - // If infinity, it is an infinite raycast. If not, render the distance in raycastResult. - // Ignore the hit variable as it will always correspond to the length of the raycast, hit or miss. - const float RENDER_DIST = raycastResult.distance == std::numeric_limits::infinity() ? SHRay::MAX_RAYCAST_DIST : raycastResult.distance; - const SHVec3 END_POS = ray.position + (ray.direction * RENDER_DIST); - - debugRenderer->DrawLine(RAY_COLOUR, ray.position, END_POS); - } - } - - - void SHPhysicsDebugDrawSystem::generateBox() noexcept - { - boxVertices[0] = { 0.5f, 0.5f, -0.5f }; // TOP_RIGHT_BACK - boxVertices[1] = { -0.5f, 0.5f, -0.5f }; // TOP_LEFT_BACK - boxVertices[2] = { 0.5f, -0.5f, -0.5f }; // BTM_RIGHT_BACK - boxVertices[3] = { -0.5f, -0.5f, -0.5f }; // BTM_LEFT_BACK - boxVertices[4] = { 0.5f, 0.5f, 0.5f }; // TOP_RIGHT_FRONT - boxVertices[5] = { -0.5f, 0.5f, 0.5f }; // TOP_LEFT_FRONT - boxVertices[6] = { 0.5f, -0.5f, 0.5f }; // BTM_RIGHT_FRONT - boxVertices[7] = { -0.5f, -0.5f, 0.5f }; // BTM_LEFT_FRONT - } - - void SHPhysicsDebugDrawSystem::debugDrawBox(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept - { - auto* BOX = reinterpret_cast(collisionShape.GetShape()); - - // Calculate final position & orientation - const SHVec3 COLLIDER_POS = colliderComponent.GetPosition(); - const SHVec3 BOX_POS = collisionShape.GetPositionOffset(); - const SHQuaternion COLLIDER_ROT = colliderComponent.GetOrientation(); - const SHQuaternion BOX_ROT = SHQuaternion::FromEuler(collisionShape.GetRotationOffset()); - - - const SHMatrix COLLIDER_TR = SHMatrix::Rotate(COLLIDER_ROT) * SHMatrix::Translate(COLLIDER_POS); - const SHMatrix BOX_TRS = SHMatrix::Scale(BOX->GetWorldExtents() * 2.0f) * SHMatrix::Rotate(BOX_ROT) * SHMatrix::Translate(BOX_POS); - - const SHMatrix FINAL_TRS = BOX_TRS * COLLIDER_TR; - - const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN; - - std::array transformedVertices; - for (uint32_t i = 0; i < NUM_BOX_VERTICES / 2; ++i) - { - const uint32_t IDX1 = i; - const uint32_t IDX2 = i + NUM_BOX_VERTICES / 2; - - transformedVertices[IDX1] = SHVec3::Transform(boxVertices[IDX1], FINAL_TRS); - transformedVertices[IDX2] = SHVec3::Transform(boxVertices[IDX2], FINAL_TRS); - - // Draw 4 line to connect the quads - debugRenderer->DrawLine(COLLIDER_COLOUR, transformedVertices[IDX1], transformedVertices[IDX2]); - } - - // A, B, C, D - std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] }; - debugRenderer->DrawPoly(COLLIDER_COLOUR, backQuad.begin(), backQuad.end()); - - // E, F, G, H - std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] }; - debugRenderer->DrawPoly(COLLIDER_COLOUR, frontQuad.begin(), frontQuad.end()); - } - - void SHPhysicsDebugDrawSystem::debugDrawSphere(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept - { - auto* SPHERE = reinterpret_cast(collisionShape.GetShape()); - - const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN; - - // Calculate final position & orientation - const SHQuaternion FINAL_ROT = colliderComponent.GetOrientation() * SHQuaternion::FromEuler(collisionShape.GetRotationOffset()); - const SHMatrix TR = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(colliderComponent.GetPosition()); - - debugRenderer->DrawSphere(COLLIDER_COLOUR, SHVec3::Transform(collisionShape.GetPositionOffset(), TR), SPHERE->GetWorldRadius()); - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h deleted file mode 100644 index dc703092..00000000 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsDebugDrawSystem.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for the Physics Debug Draw System - * - * \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 - -// Project Headers -#include "ECS_Base/System/SHSystemRoutine.h" -#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" -#include "Math/SHColour.h" -#include "SHPhysicsSystem.h" -#include "Tools/Utilities/SHUtilities.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHPhysicsDebugDrawSystem final : public SHSystem - { - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class DebugDrawFlags - { - COLLIDER - , COLLIDER_AABB - , BROAD_PHASE_AABB - , CONTACT_POINTS - , CONTACT_NORMALS - , RAYCASTS - - , NUM_FLAGS - }; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHPhysicsDebugDrawSystem() noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void Init() override; - void Exit() override; - - /*---------------------------------------------------------------------------------*/ - /* System Routines */ - /*---------------------------------------------------------------------------------*/ - - class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine - { - public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - - PhysicsDebugDrawRoutine(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - void Execute(double dt) noexcept override; - }; - - private: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using DebugDrawFunction = void(*)(SHDebugDrawSystem*, rp3d::DebugRenderer*) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); - static const DebugDrawFunction drawFunctions[NUM_FLAGS]; - - // SHAPES INFO - - static constexpr size_t NUM_BOX_VERTICES = 8; - static SHVec3 boxVertices[NUM_BOX_VERTICES]; - - - uint8_t debugDrawFlags; - SHPhysicsSystem* physicsSystem; - SHColour debugColours[NUM_FLAGS]; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - // Generic Draw Functions - - static void drawColliders (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawColliderAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawBroadPhaseAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawContactPoints (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawContactNormals (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - static void drawRaycasts (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; - - // Shape Generation Functions - - static void generateBox () noexcept; - - // Shape Draw Functions - - static void debugDrawBox (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; - static void debugDrawSphere (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept; - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 768c9b77..eacd6ac9 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -45,32 +45,6 @@ namespace SHADE return 1.0 / fixedDT; } - const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept - { - return worldState.settings; - } - - const std::vector& SHPhysicsSystem::GetAllCollisionInfo() const noexcept - { - return collisionListener.GetCollisionInfoContainer(); - } - - const std::vector& SHPhysicsSystem::GetAllTriggerInfo() const noexcept - { - return collisionListener.GetTriggerInfoContainer(); - } - - const SHPhysicsObject* SHPhysicsSystem::GetPhysicsObject(EntityID eid) noexcept - { - return objectManager.GetPhysicsObject(eid); - } - - - const SHPhysicsObjectManager::PhysicsObjectEntityMap& SHPhysicsSystem::GetPhysicsObjects() const noexcept - { - return objectManager.physicsObjects; - } - /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -80,12 +54,6 @@ namespace SHADE fixedDT = 1.0 / fixedUpdateRate; } - void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept - { - worldState.settings = settings; - worldState.UpdateSettings(); - } - /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -96,41 +64,10 @@ namespace SHADE std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath); - - // Link Physics Object Manager with System & Raycaster - objectManager.SetFactory(factory); - raycaster.SetObjectManager(&objectManager); - - // Link Collision Listener with System - collisionListener.BindToSystem(this); - - // Subscribe to component events - const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::addPhysicsComponent) }; - const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(ADD_COMPONENT_RECEIVER); - SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR); - - const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::removePhysicsComponent) }; - const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(REMOVE_COMPONENT_RECEIVER); - SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR); - - #ifdef SHEDITOR - - // Subscribe to Editor State Change Events - const std::shared_ptr ON_PLAY_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::onPlay) }; - const ReceiverPtr ON_PLAY_RECEIVER_PTR = std::dynamic_pointer_cast(ON_PLAY_RECEIVER); - SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, ON_PLAY_RECEIVER_PTR); - - const std::shared_ptr ON_STOP_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::onStop) }; - const ReceiverPtr ON_STOP_RECEIVER_PTR = std::dynamic_pointer_cast(ON_STOP_RECEIVER); - SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, ON_STOP_RECEIVER_PTR); - - #endif - } void SHPhysicsSystem::Exit() { - worldState.DestroyWorld(factory); // Write collision tag names to file std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; @@ -138,344 +75,13 @@ namespace SHADE SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath); } - void SHPhysicsSystem::BuildScene(SHSceneGraph& sceneGraph) - { - static const auto BUILD_NEW_SCENE_PHYSICS_OBJECT = [&](SHSceneNode* node) - { - const EntityID EID = node->GetEntityID(); - - if (SHComponentManager::HasComponent(EID)) - objectManager.AddRigidBody(EID); - - if (SHComponentManager::HasComponent(EID)) - { - objectManager.AddCollider(EID); - - auto* COLLIDER = SHComponentManager::GetComponent(EID); - for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i) - objectManager.AddCollisionShape(EID, i); - } - - }; - - //////////////////////////////// - - // Destroy an existing world - if (worldState.world != nullptr) - { - objectManager.RemoveAllObjects(); - objectManager.SetWorld(nullptr); - - collisionListener.ClearContainers(); - raycaster.ClearFrame(); - - worldState.DestroyWorld(factory); - } - - worldState.CreateWorld(factory); -#ifdef _PUBLISH - worldState.world->setIsDebugRenderingEnabled(false); -#else - worldState.world->setIsDebugRenderingEnabled(true); -#endif - - // Link Collision Listener & Raycaster - collisionListener.BindToWorld(worldState.world); - raycaster.BindToWorld(worldState.world); - - // Link with object manager & create all physics objects - objectManager.SetWorld(worldState.world); - - // When building a scene, clear the object manager command queue and build scene objects again. - // This is done to avoid duplicate adds. - while (!objectManager.commandQueue.empty()) - objectManager.commandQueue.pop(); - - sceneGraph.Traverse(BUILD_NEW_SCENE_PHYSICS_OBJECT); - objectManager.UpdateCommands(); - } - - void SHPhysicsSystem::ForceBuild(SHSceneGraph& sceneGraph) - { - // HACK: Band-aid fix. To be removed. - objectManager.UpdateCommands(); - } - - void SHPhysicsSystem::ForceUpdate() { - if (!worldState.world) - { - SHLOGV_ERROR("Unable to force update without a Physics world!") - return; - } - auto* scriptingSystem = SHSystemManager::GetSystem(); - if (scriptingSystem == nullptr) - { - SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); - } - - // Force the physics world to update once - if (scriptingSystem != nullptr) - scriptingSystem->ExecuteFixedUpdates(); - - worldState.world->update(static_cast(fixedDT)); - - // Sync transforms. No interpolation applied here - for (auto& [entityID, physicsObject] : objectManager.physicsObjects) - { - auto* transformComponent = SHComponentManager::GetComponent_s(entityID); - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); - - const auto& CURRENT_TF = physicsObject.GetRigidBody()->getTransform(); - const auto& RENDER_POS = CURRENT_TF.getPosition(); - const auto& RENDER_ROT = CURRENT_TF.getOrientation(); - - // Cache transform - physicsObject.prevTransform = CURRENT_TF; - - // Sync with physics components - if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive(entityID)) - { - rigidBodyComponent->position = RENDER_POS; - rigidBodyComponent->orientation = RENDER_ROT; - } - - if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive(entityID)) - { - colliderComponent->position = RENDER_POS; - colliderComponent->orientation = RENDER_ROT; - } - - // Set transform for rendering - if (transformComponent) - { - transformComponent->SetWorldPosition(RENDER_POS); - transformComponent->SetWorldOrientation(RENDER_ROT); - } - } - } - - SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept - { - return raycaster.Raycast(ray, distance, collisionTag); - } - - SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept - { - return raycaster.Linecast(start, end, collisionTag); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept - { - return raycaster.ColliderRaycast(eid, ray, distance); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept - { - return raycaster.ColliderRaycast(eid, shapeIndex, ray, distance); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept - { - return raycaster.ColliderLinecast(eid, start, end); - } - - SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept - { - return raycaster.ColliderLinecast(eid, shapeIndex, start, end); - } - - void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex) - { - static const auto ADD_SHAPE = [&](EntityID entityID, int index) - { - objectManager.AddCollisionShape(entityID, index); - - auto* colliderComponent = SHComponentManager::GetComponent(entityID); - auto& collisionShape = colliderComponent->GetCollisionShape(index); - - const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA - { - .entityID = entityID - , .colliderType = collisionShape.GetType() - , .colliderIndex = index - }; - - SHEventManager::BroadcastEvent(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); - }; - - #ifdef SHEDITOR - - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - ADD_SHAPE(eid, shapeIndex); - - #else - - ADD_SHAPE(eid, shapeIndex); - - #endif - } - - void SHPhysicsSystem::RemoveCollisionShape(EntityID eid, int shapeIndex) - { - static const auto REMOVE_SHAPE = [&](EntityID entityID, int index) - { - objectManager.RemoveCollisionShape(entityID, index); - - const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA - { - .entityID = entityID - , .colliderIndex = index - }; - - SHEventManager::BroadcastEvent(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); - }; - - #ifdef SHEDITOR - - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - REMOVE_SHAPE(eid, shapeIndex); - - #else - - REMOVE_SHAPE(eid, shapeIndex); - - #endif } /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept - { - const auto& EVENT_DATA = reinterpret_cast*>(addComponentEvent.get()); - - static const auto RIGID_BODY_ID = ComponentFamily::GetID(); - static const auto COLLIDER_ID = ComponentFamily::GetID(); - - const auto ADDED_ID = EVENT_DATA->data->addedComponentType; - const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID; - if (IS_PHYSICS_COMPONENT) - { - const EntityID EID = EVENT_DATA->data->eid; - - // We only add tell the physics object manager to add a component if the scene is played - - #ifdef SHEDITOR - - const auto* EDITOR = SHSystemManager::GetSystem(); - - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID); - - #else - - ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID); - - #endif - } - - return EVENT_DATA->handle; - } - - SHEventHandle SHPhysicsSystem::removePhysicsComponent(SHEventPtr removeComponentEvent) noexcept - { - const auto& EVENT_DATA = reinterpret_cast*>(removeComponentEvent.get()); - - static const auto RIGID_BODY_ID = ComponentFamily::GetID(); - static const auto COLLIDER_ID = ComponentFamily::GetID(); - - const auto REMOVED_ID = EVENT_DATA->data->removedComponentType; - const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID; - if (IS_PHYSICS_COMPONENT) - { - const EntityID EID = EVENT_DATA->data->eid; - - // We only add tell the physics object manager to remove a component if the scene is played - - #ifdef SHEDITOR - - const auto* EDITOR = SHSystemManager::GetSystem(); - - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID); - - #else - - REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID); - - #endif - } - - return EVENT_DATA->handle; - } - - SHEventHandle SHPhysicsSystem::onPlay(SHEventPtr onPlayEvent) - { - static const auto BUILD_PHYSICS_OBJECT = [&](SHSceneNode* node) - { - const EntityID EID = node->GetEntityID(); - - if (SHComponentManager::HasComponent(EID)) - objectManager.AddRigidBody(EID); - - if (SHComponentManager::HasComponent(EID)) - { - objectManager.AddCollider(EID); - - auto* COLLIDER = SHComponentManager::GetComponent(EID); - for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i) - objectManager.AddCollisionShape(EID, i); - } - }; - - //////////////////////////////// - - // Create physics world - if (worldState.world != nullptr) - return onPlayEvent->handle; - - worldState.CreateWorld(factory); -#ifdef _PUBLISH - worldState.world->setIsDebugRenderingEnabled(false); -#else - worldState.world->setIsDebugRenderingEnabled(true); -#endif - - // Link Collision Listener & Raycaster - collisionListener.BindToWorld(worldState.world); - raycaster.BindToWorld(worldState.world); - - // Link with object manager & create all physics objects - objectManager.SetWorld(worldState.world); - - // Build scene - SHSceneManager::GetCurrentSceneGraph().Traverse(BUILD_PHYSICS_OBJECT); - objectManager.UpdateCommands(); - - return onPlayEvent->handle; - } - - SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent) - { - // Remove all physics objects - objectManager.RemoveAllObjects(); - objectManager.SetWorld(nullptr); - - // Clear all collision info - // Collision listener is automatically unbound when world is destroyed - collisionListener.ClearContainers(); - raycaster.ClearFrame(); - - // Destroy the world - worldState.DestroyWorld(factory); - - return onStopEvent->handle; - } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index 99db493e..3fe05c09 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -10,22 +10,13 @@ #pragma once -#include -#include - -// External Dependencies -#include - // Project Headers #include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHFixedSystemRoutine.h" #include "Math/Transform/SHTransformComponent.h" -#include "Physics/Collision/SHCollisionListener.h" -#include "Physics/Collision/SHPhysicsRaycaster.h" #include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" #include "Physics/SHPhysicsWorld.h" #include "Scene/SHSceneGraph.h" @@ -55,14 +46,9 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] double GetFixedUpdateRate () const noexcept; - [[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept; + [[nodiscard]] double GetFixedUpdateRate () const noexcept; + [[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept; - [[nodiscard]] const std::vector& GetAllCollisionInfo () const noexcept; - [[nodiscard]] const std::vector& GetAllTriggerInfo () const noexcept; - - [[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept; - [[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ @@ -77,105 +63,8 @@ namespace SHADE void Init () override; void Exit () override; - void BuildScene (SHSceneGraph& sceneGraph); - void ForceBuild (SHSceneGraph& sceneGraph); void ForceUpdate (); - /** - * @brief Casts a ray into the world. - * @param ray The ray to cast. - * @param distance The distance to cast the ray. Defaults to infinity. - * @param collisionTag The collision tag to use for filtering the raycast. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult Raycast - ( - const SHRay& ray - , float distance = std::numeric_limits::infinity() - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - /** - * @brief Casts a bounded ray into the world. - * @param start The starting point of the ray. - * @param end The end point of the ray. - * @param collisionTag The collision tag to use for filtering the bounded raycast. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult Linecast - ( - const SHVec3& start - , const SHVec3& end - , const SHCollisionTag& collisionTag = SHCollisionTag{} - ) noexcept; - - /** - * @brief Casts a ray at a body with colliders. - * @param eid The entity to cast to. - * @param ray The ray to cast. - * @param distance The distance to cast the ray. Defaults to infinity. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - /** - * @brief Casts a ray at a collider. - * @param eid The entity to cast to. - * @param shapeIndex The index of the collision shape. - * @param ray The ray to cast. - * @param distance The distance to cast the ray. Defaults to infinity. - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderRaycast - ( - EntityID eid - , int shapeIndex - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - ) noexcept; - - /** - * @brief Casts a bounded ray at a body with colliders. - * @param eid - * @param start - * @param end - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - /** - * @brief - * @param eid - * @param shapeIndex - * @param start - * @param end - * @return The result of the raycast. - */ - SHPhysicsRaycastResult ColliderLinecast - ( - EntityID eid - , int shapeIndex - , const SHVec3& start - , const SHVec3& end - ) noexcept; - - // Specific Handling for Collision Shapes as they are not under the Component System. - // This is done as events need to be sent out. - // TODO(Diren): Consider using a static method through the ColliderComponent. - - void AddCollisionShape (EntityID eid, int shapeIndex); - void RemoveCollisionShape (EntityID eid, int shapeIndex); - /*---------------------------------------------------------------------------------*/ /* System Routines */ /*---------------------------------------------------------------------------------*/ @@ -200,17 +89,6 @@ namespace SHADE /* Function Members */ /*-------------------------------------------------------------------------------*/ - void syncRigidBodyActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept; - void syncColliderActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept; - static void syncOnPlay (EntityID eid, SHPhysicsObject& physicsObject) noexcept; - - static void preUpdateSyncTransform - ( - SHPhysicsObject& physicsObject - , SHTransformComponent* transformComponent - , SHRigidBodyComponent* rigidBodyComponent - , SHColliderComponent* colliderComponent - ) noexcept; }; class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine @@ -250,14 +128,6 @@ namespace SHADE /* Function Members */ /*-------------------------------------------------------------------------------*/ - static void postUpdateSyncTransforms - ( - SHPhysicsObject& physicsObject - , SHTransformComponent* transformComponent - , SHRigidBodyComponent* rigidBodyComponent - , SHColliderComponent* colliderComponent - , double interpolationFactor - ) noexcept; }; private: @@ -271,26 +141,9 @@ namespace SHADE double interpolationFactor; double fixedDT; - // rp3d - - rp3d::PhysicsCommon factory; - - // Interface objects - - SHPhysicsWorldState worldState; - SHPhysicsObjectManager objectManager; - SHCollisionListener collisionListener; - SHPhysicsRaycaster raycaster; - /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept; - SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept; - - SHEventHandle onPlay (SHEventPtr onPlayEvent); - SHEventHandle onStop (SHEventPtr onStopEvent); - SHEventHandle buildScene (SHEventPtr onSceneChangeEvent); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index 1fb11274..06f1b464 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -27,26 +27,26 @@ namespace SHADE { static std::vector emptyVec; - auto phySystem = SHSystemManager::GetSystem(); - if (phySystem) - { - return phySystem->GetAllCollisionInfo(); - } + //auto phySystem = SHSystemManager::GetSystem(); + //if (phySystem) + //{ + // return phySystem->GetAllCollisionInfo(); + //} - SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); + //SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); return emptyVec; } const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept { static std::vector emptyVec; - auto phySystem = SHSystemManager::GetSystem(); - if (phySystem) - { - return phySystem->GetAllTriggerInfo(); - } + //auto phySystem = SHSystemManager::GetSystem(); + //if (phySystem) + //{ + // return phySystem->GetAllTriggerInfo(); + //} - SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); + //SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); return emptyVec; } @@ -61,76 +61,4 @@ namespace SHADE SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); return 0.0; } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::Raycast(const SHRay& ray, float distance) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->Raycast(ray, distance); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::Linecast(const SHVec3& start, const SHVec3& end) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->Linecast(start, end); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderRaycast(eid, ray, distance); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderRaycast(eid, shapeIndex, ray, distance); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderLinecast(eid, start, end); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } - - SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept - { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - { - return physicsSystem->ColliderLinecast(eid, shapeIndex, start, end); - } - - SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); - return SHPhysicsRaycastResult{}; - } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index 0065aee3..0664f367 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited. // Project Headers #include "ECS_Base/Entity/SHEntity.h" +#include "Physics/Collision/SHCollisionInfo.h" namespace SHADE @@ -24,7 +25,6 @@ namespace SHADE /* Forward Declarations */ /*-----------------------------------------------------------------------------------*/ - class SHCollisionInfo; class SHVec3; struct SHRay; struct SHPhysicsRaycastResult; @@ -52,12 +52,5 @@ namespace SHADE [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; [[nodiscard]] static double GetFixedDT () noexcept; - - [[nodiscard]] static SHPhysicsRaycastResult Raycast (const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult Linecast (const SHVec3& start, const SHVec3& end) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, int shapeIndex, const SHRay& ray, float distance = std::numeric_limits::infinity()) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, const SHVec3& start, const SHVec3& end) noexcept; - [[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept; }; } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp index a5ca957a..0029a8e7 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp @@ -55,85 +55,12 @@ namespace SHADE void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept { auto* physicsSystem = reinterpret_cast(GetSystem()); - - #ifdef SHEDITOR - - // Only Sync on Play. - // Otherwise, Components are only holding data until the world is built on play. - const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) - { - physicsSystem->objectManager.UpdateCommands(); - - for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects) - { - // Ensure a valid physics Object - if (physicsObject.rp3dBody == nullptr) - continue; - - // Sync active states between SHADE & RP3D - syncRigidBodyActive(entityID, physicsObject); - syncColliderActive(entityID, physicsObject); - - syncOnPlay(entityID, physicsObject); - } - } - else - { - auto& rigidBodyDense = SHComponentManager::GetDense(); - auto& colliderDense = SHComponentManager::GetDense(); - - for (auto& rigidBodyComponent : rigidBodyDense) - { - const auto* TRANSFORM = SHComponentManager::GetComponent_s(rigidBodyComponent.GetEID()); - - if (TRANSFORM && TRANSFORM->HasChanged()) - { - rigidBodyComponent.position = TRANSFORM->GetWorldPosition(); - rigidBodyComponent.orientation = TRANSFORM->GetWorldOrientation(); - } - } - - for (auto& colliderComponent : colliderDense) - { - const auto* TRANSFORM = SHComponentManager::GetComponent_s(colliderComponent.GetEID()); - - if (TRANSFORM && TRANSFORM->HasChanged()) - { - colliderComponent.position = TRANSFORM->GetWorldPosition(); - colliderComponent.orientation = TRANSFORM->GetWorldOrientation(); - colliderComponent.scale = TRANSFORM->GetWorldScale(); - - colliderComponent.RecomputeCollisionShapes(); - } - } - } - - #else - - // Always sync Rigid Body & Collider Components with Physics Objects - // Do not check for an editor here - - physicsSystem->objectManager.UpdateCommands(); - - for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects) - { - // Ensure a valid physics Object - if (physicsObject.rp3dBody == nullptr) - continue; - - syncRigidBodyActive(entityID, physicsObject); - syncColliderActive(entityID, physicsObject); - - syncOnPlay(entityID, physicsObject); - } - - #endif } void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept { auto* physicsSystem = reinterpret_cast(GetSystem()); + auto* scriptingSystem = SHSystemManager::GetSystem(); if (scriptingSystem == nullptr) { @@ -141,20 +68,16 @@ namespace SHADE } const double FIXED_DT = physicsSystem->fixedDT; - // HACK: Clamp DT here to prevent a ridiculous amount of updates. This limits updates from large dt to 2. - // HACK: This should be done by the FRC and not here for predictable behaviour. accumulatedTime += dt; - //testFunction(); - int count = 0; while (accumulatedTime > FIXED_DT) { if (scriptingSystem != nullptr) scriptingSystem->ExecuteFixedUpdates(); - physicsSystem->worldState.world->update(static_cast(FIXED_DT)); + // TODO: Update World accumulatedTime -= FIXED_DT; ++count; @@ -177,236 +100,16 @@ namespace SHADE } // Interpolate transforms for rendering - if (physicsSystem->worldUpdated) - { - for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects) - { - auto* transformComponent = SHComponentManager::GetComponent_s(entityID); - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); - postUpdateSyncTransforms - ( - physicsObject - , transformComponent - , rigidBodyComponent - , colliderComponent - , physicsSystem->interpolationFactor - ); - } + // Collision & Trigger messages + if (scriptingSystem != nullptr) + scriptingSystem->ExecuteCollisionFunctions(); - // Collision & Trigger messages - if (scriptingSystem != nullptr) - scriptingSystem->ExecuteCollisionFunctions(); - - // Since this function never runs when editor in not in play, execute the function anyway - physicsSystem->collisionListener.CleanContainers(); - } } /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsSystem::PhysicsPreUpdate::syncRigidBodyActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept - { - if (!SHComponentManager::HasComponent(eid)) - return; - - const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive(eid); - const bool IS_RP3D_BODY_ACTIVE = physicsObject.GetRigidBody()->isActive(); - - if (IS_ACTIVE_IN_SCENE != IS_RP3D_BODY_ACTIVE) - physicsObject.GetRigidBody()->setIsActive(IS_ACTIVE_IN_SCENE); - } - - void SHPhysicsSystem::PhysicsPreUpdate::syncColliderActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept - { - const auto* COLLIDER = SHComponentManager::GetComponent_s(eid); - if (!COLLIDER) - return; - - const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive(eid); - const bool IS_RP3D_COLLIDER_ACTIVE = physicsObject.collidersActive; - - if (IS_ACTIVE_IN_SCENE != IS_RP3D_COLLIDER_ACTIVE) - { - // HACK: If active state turned off, remove all collision shapes. If turned on, add them back. - auto* physicsSystem = reinterpret_cast(GetSystem()); - - const int NUM_SHAPES = static_cast(COLLIDER->GetCollisionShapes().size()); - if (IS_ACTIVE_IN_SCENE) - { - for (int i = 0; i < NUM_SHAPES; ++i) - physicsSystem->objectManager.AddCollisionShape(eid, i); - } - else - { - for (int i = NUM_SHAPES - 1; i >= 0; --i) - physicsSystem->objectManager.RemoveCollisionShape(eid, i); - } - - physicsObject.collidersActive = IS_ACTIVE_IN_SCENE; - } - } - - void SHPhysicsSystem::PhysicsPreUpdate::syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept - { - auto* transformComponent = SHComponentManager::GetComponent_s(eid); - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(eid); - auto* colliderComponent = SHComponentManager::GetComponent_s(eid); - - // Sync transforms & physics components transforms - if (transformComponent && transformComponent->HasChanged()) - { - physicsObject.GetRigidBody()->setIsSleeping(false); - - preUpdateSyncTransform - ( - physicsObject - , transformComponent - , rigidBodyComponent - , colliderComponent - ); - } - - // Sync Rigid Bodies - if (rigidBodyComponent) - physicsObject.SyncRigidBody(*rigidBodyComponent); - - // Sync Colliders - if (colliderComponent) - physicsObject.SyncColliders(*colliderComponent); - } - - void SHPhysicsSystem::PhysicsPreUpdate::preUpdateSyncTransform - ( - SHPhysicsObject& physicsObject - , SHTransformComponent* transformComponent - , SHRigidBodyComponent* rigidBodyComponent - , SHColliderComponent* colliderComponent - ) noexcept - { - if (!transformComponent) - return; - - const SHVec3& WORLD_POS = transformComponent->GetWorldPosition(); - const SHQuaternion& WORLD_ROT = transformComponent->GetWorldOrientation(); - const SHVec3& WORLD_SCL = transformComponent->GetWorldScale(); - - const rp3d::Transform RP3D_TRANSFORM { WORLD_POS, WORLD_ROT }; - physicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM); - physicsObject.prevTransform = RP3D_TRANSFORM; - - if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - rigidBodyComponent->position = WORLD_POS; - rigidBodyComponent->orientation = WORLD_ROT; - } - - if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - colliderComponent->position = WORLD_POS; - colliderComponent->orientation = WORLD_ROT; - colliderComponent->scale = WORLD_SCL; - - colliderComponent->RecomputeCollisionShapes(); - } - } - - void SHPhysicsSystem::PhysicsPostUpdate::postUpdateSyncTransforms - ( - SHPhysicsObject& physicsObject - , SHTransformComponent* transformComponent - , SHRigidBodyComponent* rigidBodyComponent - , SHColliderComponent* colliderComponent - , double interpolationFactor - ) noexcept - { - const rp3d::Transform& CURRENT_TF = physicsObject.GetRigidBody()->getTransform(); - auto renderPos = CURRENT_TF.getPosition(); - auto renderRot = CURRENT_TF.getOrientation(); - - // Cache transforms - if (physicsObject.GetRigidBody()->isActive()) - physicsObject.prevTransform = CURRENT_TF; - - // Sync with rigid bodies - if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - // Skip static bodies - if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC) - return; - - // Check if transform should be interpolated - if (rigidBodyComponent->IsInterpolating()) - { - // Interpolate transforms between current and predicted next transform - - const rp3d::Transform PREV_TF = physicsObject.prevTransform; - const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast(interpolationFactor)); - - renderPos = INTERPOLATED_TF.getPosition(); - renderRot = INTERPOLATED_TF.getOrientation(); - } - - rigidBodyComponent->position = CURRENT_TF.getPosition(); - rigidBodyComponent->orientation = CURRENT_TF.getOrientation(); - - // Sync with colliders - if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive(physicsObject.entityID)) - { - // Skip colliders without rigidbody components. If any transform was updated, it was done in pre-update. - - colliderComponent->position = CURRENT_TF.getPosition(); - colliderComponent->orientation = CURRENT_TF.getOrientation(); - } - - // Set transform for rendering - if (transformComponent) - { - transformComponent->SetWorldPosition(renderPos); - transformComponent->SetWorldOrientation(renderRot); - } - } - } } // namespace SHADE -///////////////////////////////////////////////////////////////////////////////////////// -void testFunction() -{ - using namespace SHADE; - - // Test movement - const float forceModifier = 25.0f; - EntityID eid = 65538; - - if (SHEntityManager::IsValidEID(eid)) - { - auto* rb = SHComponentManager::GetComponent_s(eid); - if (rb) - { - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W)) - rb->AddForce(SHVec3::UnitZ * forceModifier); - - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) - rb->AddForce(-SHVec3::UnitX * forceModifier); - - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S)) - rb->AddForce(-SHVec3::UnitZ * forceModifier); - - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D)) - rb->AddForce(SHVec3::UnitX * forceModifier); - } - } - - // Cast rays - auto* tag = SHCollisionTagMatrix::GetTag(1); - tag->SetLayerState(SHCollisionTag::Layer::_1, false); - tag->SetLayerState(SHCollisionTag::Layer::_2, true); - - SHRay ray { SHVec3{3.0f, 3.5f, 0.0f}, -SHVec3::UnitX }; - auto* physicsSystem = SHSystemManager::GetSystem(); - physicsSystem->Raycast(ray, std::numeric_limits::infinity(), *tag); -} diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index b5f1444f..414e79b7 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -19,7 +19,7 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /*---------------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ /* CollisionShape - Constructors */ /*---------------------------------------------------------------------------------*/ CollisionShape::CollisionShape(int arrayIdx, Entity attachedEntity) diff --git a/SHADE_Managed/src/Physics/Physics.cxx b/SHADE_Managed/src/Physics/Physics.cxx index 9e2c1413..fc54f527 100644 --- a/SHADE_Managed/src/Physics/Physics.cxx +++ b/SHADE_Managed/src/Physics/Physics.cxx @@ -43,47 +43,47 @@ namespace SHADE RaycastHit Physics::Raycast(Ray ray) { - return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray))); + return RaycastHit{}; } RaycastHit Physics::Raycast(Ray ray, float distance) { - return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray), distance)); + return RaycastHit{}; } RaycastHit Physics::Linecast(Vector3 start, Vector3 end) { - return Convert::ToCLI(SHPhysicsSystemInterface::Linecast(Convert::ToNative(start), Convert::ToNative(end))); + return RaycastHit{}; } RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray))); + return RaycastHit{}; } RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray), distance)); + return RaycastHit{}; } RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray))); + return RaycastHit{}; } RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray), distance)); + return RaycastHit{}; } RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, Convert::ToNative(start), Convert::ToNative(end))); + return RaycastHit{}; } RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end) { - return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, shapeIndex, Convert::ToNative(start), Convert::ToNative(end))); + return RaycastHit{}; } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index 590a3cf0..1d277274 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -103,38 +103,6 @@ namespace SHADE /* Physics Conversions */ /*---------------------------------------------------------------------------------*/ - SHPhysicsRaycastResult Convert::ToNative(RaycastHit cli) - { - // This function shouldn't be used anyway, so we leave the entityHit empty. - - SHPhysicsRaycastResult native; - - native.hit = cli.Hit; - native.position = ToNative(cli.Position); - native.normal = ToNative(cli.Normal); - native.distance = cli.Distance; - native.shapeIndex = cli.CollisionShapeIndex; - - return native; - } - - RaycastHit Convert::ToCLI(const SHPhysicsRaycastResult& native) - { - RaycastHit cli; - - cli.Hit = native.hit; - cli.Position = ToCLI(native.position); - cli.Normal = ToCLI(native.normal); - cli.Distance = native.distance; - cli.CollisionShapeIndex = native.shapeIndex; - - cli.Other = SHEntityManager::IsValidEID(native.entityHit) - ? GameObject(native.entityHit) - : System::Nullable(); - - return cli; - } - /*---------------------------------------------------------------------------------*/ /* Handle Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index fb373c51..6fa4d935 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -141,20 +141,6 @@ namespace SHADE /* Physics Conversions */ /*-----------------------------------------------------------------------------*/ - /// - /// Converts from a managed RaycastHit to a native SHPhysicsRaycastResult - /// - /// The managed RaycastHit to convert from. - /// Native copy of a managed RaycastHit. - static SHPhysicsRaycastResult ToNative(RaycastHit cli); - - /// - /// Converts from native SHPhysicsRaycastResult to a managed RaycastHit. - /// - /// The native SHPhysicsRaycastResult to convert from. - /// Managed copy of a native SHPhysicsRaycastResult. - static RaycastHit ToCLI(const SHPhysicsRaycastResult& native); - /*-----------------------------------------------------------------------------*/ /* Handle Conversions */ /*-----------------------------------------------------------------------------*/ -- 2.40.1 From 6cd203179a6bb7d6951ce4b06993a6b0489e7fd6 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 2 Dec 2022 19:01:08 +0800 Subject: [PATCH 02/84] Added Rigid Body --- Assets/Application.SHConfig | 2 +- Assets/Scenes/PhysicsSandbox.shade | 1 + Assets/Scenes/PhysicsSandbox.shade.shmeta | 3 + .../src/Physics/Dynamics/SHRigidBody.cpp | 96 +++++ .../src/Physics/Dynamics/SHRigidBody.h | 189 +++++++++ .../src/Physics/Dynamics/SHRigidBody.inl | 375 ++++++++++++++++++ 6 files changed, 665 insertions(+), 1 deletion(-) create mode 100644 Assets/Scenes/PhysicsSandbox.shade create mode 100644 Assets/Scenes/PhysicsSandbox.shade.shmeta create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 5673556d..d0fa83df 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97158628 +Starting Scene ID: 97402985 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Assets/Scenes/PhysicsSandbox.shade.shmeta b/Assets/Scenes/PhysicsSandbox.shade.shmeta new file mode 100644 index 00000000..97c00ca6 --- /dev/null +++ b/Assets/Scenes/PhysicsSandbox.shade.shmeta @@ -0,0 +1,3 @@ +Name: PhysicsSandbox +ID: 97402985 +Type: 5 diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp new file mode 100644 index 00000000..ad739847 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -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 + +// 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h new file mode 100644 index 00000000..598ed3aa --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -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" diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl new file mode 100644 index 00000000..28f98d12 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl @@ -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 -- 2.40.1 From ca45a12186f97621bfa4c91e1e76313bd7eda6ae Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 4 Dec 2022 17:31:22 +0800 Subject: [PATCH 03/84] Restructured Physics Systems & Interfaces --- Assets/Scenes/PhysicsSandbox.shade | 29 +- .../src/Application/SBApplication.cpp | 2 +- SHADE_Application/src/Scenes/SBMainScene.cpp | 9 +- SHADE_Application/src/Scenes/SBTestScene.cpp | 2 +- .../Inspector/SHEditorComponentView.hpp | 4 +- .../Inspector/SHEditorInspector.cpp | 2 +- SHADE_Engine/src/Events/SHEventDefines.h | 12 +- .../src/Physics/Collision/SHCollisionInfo.h | 2 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 356 +++++++++++++++++ .../src/Physics/Dynamics/SHRigidBody.h | 16 +- .../src/Physics/Dynamics/SHRigidBody.inl | 375 ------------------ .../PhysicsObject/SHPhysicsObject.cpp | 74 ++++ .../Interface/PhysicsObject/SHPhysicsObject.h | 52 +++ .../PhysicsObject/SHPhysicsObjectManager.cpp | 138 +++++++ .../PhysicsObject/SHPhysicsObjectManager.h | 125 ++++++ .../SHRigidBodyComponent.cpp | 210 +++++++--- .../SHRigidBodyComponent.h | 35 +- SHADE_Engine/src/Physics/SHPhysicsWorld.cpp | 44 -- SHADE_Engine/src/Physics/SHPhysicsWorld.h | 11 - .../SHPhysicsPostUpdateRoutine.cpp} | 73 +--- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 62 +++ .../Routines/SHPhysicsUpdateRoutine.cpp | 62 +++ .../src/Physics/System/SHPhysicsSystem.cpp | 160 +++++++- .../src/Physics/System/SHPhysicsSystem.h | 125 +++--- .../src/Serialization/SHSerialization.cpp | 2 +- SHADE_Managed/src/Components/RigidBody.cxx | 2 +- SHADE_Managed/src/Components/RigidBody.hxx | 2 +- SHADE_Managed/src/Engine/ECS.cxx | 2 +- 28 files changed, 1333 insertions(+), 655 deletions(-) delete mode 100644 SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl create mode 100644 SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp create mode 100644 SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h create mode 100644 SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp create mode 100644 SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h rename SHADE_Engine/src/Physics/Interface/{ => RigidBodyComponent}/SHRigidBodyComponent.cpp (59%) rename SHADE_Engine/src/Physics/Interface/{ => RigidBodyComponent}/SHRigidBodyComponent.h (88%) rename SHADE_Engine/src/Physics/System/{SHPhysicsSystemRoutines.cpp => Routines/SHPhysicsPostUpdateRoutine.cpp} (50%) create mode 100644 SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp create mode 100644 SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 0637a088..a0b3c0c2 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -1 +1,28 @@ -[] \ No newline at end of file +- EID: 0 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 1.77475965, z: 0} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: 1 + Drag: 0 + Angular Drag: 0 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Scripts: ~ \ No newline at end of file diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index ce0a939c..a58839c5 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -109,7 +109,7 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp index 55ce32b0..6c875518 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -11,7 +11,7 @@ #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" @@ -44,13 +44,6 @@ namespace Sandbox { sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID); - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - { - SHLOGV_CRITICAL("Failed to get the physics system for building the scene!") - return; - } - /*-----------------------------------------------------------------------*/ /* TESTING CODE */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index bcc7f09d..9e3fa8ab 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -10,7 +10,7 @@ #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index f70ab889..02614631 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -251,7 +251,7 @@ namespace SHADE if(rbType == SHRigidBodyComponent::Type::DYNAMIC) //Dynamic only fields { - SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetGravityEnabled(value);}, "Gravity"); + SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetIsGravityEnabled(value);}, "Gravity"); //SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); } if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields @@ -296,7 +296,7 @@ namespace SHADE { SHEditorWidgets::DragVec3("Force", { "X", "Y", "Z" }, [component] {return component->GetForce(); }, [](SHVec3 const& value) {}, false, "Force", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); SHEditorWidgets::DragVec3("Torque", { "X", "Y", "Z" }, [component] {return component->GetTorque(); }, [](SHVec3 const& value) {}, false, "Torque", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); - SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->GetIsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); + SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->IsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 83647da7..f0d3e3e5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -14,7 +14,7 @@ #include "Scripting/SHScriptEngine.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Camera/SHCameraComponent.h" #include "Camera/SHCameraArmComponent.h" diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index d7bbf5f0..7bf82cd5 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -13,9 +13,11 @@ constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 }; constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 }; constexpr SHEventIdentifier SH_SCENEGRAPH_ADD_CHILD_EVENT { 6 }; constexpr SHEventIdentifier SH_SCENEGRAPH_REMOVE_CHILD_EVENT { 7 }; -constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 8 }; -constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 9 }; -constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 10 }; -constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 11 }; -constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 12 }; +constexpr SHEventIdentifier SH_SCENE_ON_INIT_EVENT { 8 }; +constexpr SHEventIdentifier SH_SCENE_ON_EXIT_EVENT { 9 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 10 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 11 }; +constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 12 }; +constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 13 }; +constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 14 }; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h index d2dad647..dfcf4f22 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h @@ -12,7 +12,7 @@ // Project Headers #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index ad739847..1867636c 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -13,6 +13,9 @@ // Primary Header #include "SHRigidBody.h" +// Project Headers +#include "Tools/Logger/SHLogger.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -93,4 +96,357 @@ namespace SHADE return *this; } + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHRigidBody::Type SHRigidBody::GetType() const noexcept + { + return bodyType; + } + + float SHRigidBody::GetMass() const noexcept + { + return 1.0f/ invMass; + } + + float SHRigidBody::GetLinearDrag() const noexcept + { + return linearDrag; + } + + float SHRigidBody::GetGravityScale() const noexcept + { + return gravityScale; + } + + const SHVec3& SHRigidBody::GetAccumulatedForce() const noexcept + { + return accumulatedForce; + } + + const SHVec3& SHRigidBody::GetLinearVelocity() const noexcept + { + return linearVelocity; + } + + const SHVec3& SHRigidBody::GetAngularVelocity() const noexcept + { + return angularVelocity; + } + + // Flags + + bool SHRigidBody::IsActive() const noexcept + { + static constexpr unsigned int FLAG_POS = 0; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::IsSleeping() const noexcept + { + static constexpr unsigned int FLAG_POS = 1; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::IsSleepingEnabled() const noexcept + { + static constexpr unsigned int FLAG_POS = 2; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::IsGravityEnabled() const noexcept + { + static constexpr unsigned int FLAG_POS = 3; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::IsAutoMassEnabled() const noexcept + { + static constexpr unsigned int FLAG_POS = 4; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::GetFreezePositionX() const noexcept + { + static constexpr unsigned int FLAG_POS = 10; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::GetFreezePositionY() const noexcept + { + static constexpr unsigned int FLAG_POS = 11; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::GetFreezePositionZ() const noexcept + { + static constexpr unsigned int FLAG_POS = 12; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::GetFreezeRotationX() const noexcept + { + static constexpr unsigned int FLAG_POS = 13; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::GetFreezeRotationY() const noexcept + { + static constexpr unsigned int FLAG_POS = 14; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBody::GetFreezeRotationZ() const noexcept + { + static constexpr unsigned int FLAG_POS = 15; + return flags & (1U << FLAG_POS); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHRigidBody::SetType(Type newType) noexcept + { + if (newType == bodyType) + return; + + bodyType = newType; + invMass = newType == Type::DYNAMIC ? 1.0f : 0.0f; + } + + 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 + } + + 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; + } + + void SHRigidBody::SetGravityScale(float newGravityScale) noexcept + { + gravityScale = newGravityScale; + } + + void SHRigidBody::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept + { + linearVelocity = newLinearVelocity; + } + + 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; + } + + 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; + } + + 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); + } + } + + 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; + } + + 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; + } + } + + 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; + } + } + + 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; + } + } + + 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; + } + } + + 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; + } + } + + 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; + } + } + + 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 */ + /*-----------------------------------------------------------------------------------*/ + + void SHRigidBody::AddForce(const SHVec3& force, const SHVec3& pos) noexcept + { + if (bodyType != Type::DYNAMIC) + return; + + accumulatedForce += force; + // Compute torque when force is offset + } + + void SHRigidBody::AddImpulse(const SHVec3& impulse, const SHVec3& pos) noexcept + { + if (bodyType != Type::DYNAMIC) + return; + + linearVelocity += impulse * invMass; + } + + void SHRigidBody::ClearForces() noexcept + { + accumulatedForce = SHVec3::Zero; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 598ed3aa..77b29292 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -13,22 +13,20 @@ // Project Headers #include "ECS_Base/SHECSMacros.h" #include "Math/Vector/SHVec3.h" +#include "SH_API.h" namespace SHADE { + /*-------------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------------------*/ + /** * @brief * Encapsulates a Rigid Body used in Physics Simulations */ - class SHRigidBody + class SH_API SHRigidBody { - private: - /*-----------------------------------------------------------------------------------*/ - /* Friends */ - /*-----------------------------------------------------------------------------------*/ - - friend class SHRigidBodyComponent; - public: /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -185,5 +183,3 @@ namespace SHADE }; } // namespace SHADE - -#include "SHRigidBody.inl" diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl deleted file mode 100644 index 28f98d12..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.inl +++ /dev/null @@ -1,375 +0,0 @@ -/**************************************************************************************** - * \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 diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp new file mode 100644 index 00000000..44452868 --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -0,0 +1,74 @@ +/**************************************************************************************** + * \file SHPhysicsObject.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Object. + * + * \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 + +// Primary Header +#include "SHPhysicsObject.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructor & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject::SHPhysicsObject(EntityID eid) noexcept + : entityID { eid } + {} + + SHPhysicsObject::SHPhysicsObject(const SHPhysicsObject& rhs) noexcept + : entityID { rhs.entityID } + { + // Perform a deep copy of the components + *rigidBody = *rhs.rigidBody; + } + + SHPhysicsObject::SHPhysicsObject(SHPhysicsObject&& rhs) noexcept + : entityID { rhs.entityID } + { + // Perform a deep copy of the components + *rigidBody = *rhs.rigidBody; + } + + SHPhysicsObject::~SHPhysicsObject() noexcept + { + entityID = MAX_EID; + + delete rigidBody; + } + + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject& SHPhysicsObject::operator=(const SHPhysicsObject& rhs) noexcept + { + if (this == &rhs) + return *this; + + entityID = rhs.entityID; + + // Perform a deep copy of the components + *rigidBody = *rhs.rigidBody; + + return *this; + } + + SHPhysicsObject& SHPhysicsObject::operator=(SHPhysicsObject&& rhs) noexcept + { + entityID = rhs.entityID; + + // Perform a deep copy of the components + *rigidBody = *rhs.rigidBody; + + return *this; + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h new file mode 100644 index 00000000..2be5844d --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h @@ -0,0 +1,52 @@ +/**************************************************************************************** + * \file SHPhysicsObject.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Object. + * + * \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 "Physics/Dynamics/SHRigidBody.h" + +namespace SHADE +{ + /*-------------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a rigid body and a collider tied to an Entity. + */ + struct SH_API SHPhysicsObject + { + public: + /*-----------------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------------*/ + + EntityID entityID = MAX_EID; + SHRigidBody* rigidBody = nullptr; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject (EntityID eid) noexcept; + SHPhysicsObject (const SHPhysicsObject& rhs) noexcept; + SHPhysicsObject (SHPhysicsObject&& rhs) noexcept; + ~SHPhysicsObject () noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept; + SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept; + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp new file mode 100644 index 00000000..dccca97b --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp @@ -0,0 +1,138 @@ +/**************************************************************************************** + * \file SHPhysicsObjectManager.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Object Manager. + * + * \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 + +// Primary Header +#include "SHPhysicsObjectManager.h" + +// Project Headers +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Interface/SHCollisionShape.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObjectManager::EntityObjectMap& SHPhysicsObjectManager::GetPhysicsObjects() noexcept + { + return physicsObjects; + } + + const SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID entityID) noexcept + { + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) + { + SHLOG_ERROR("Cannot find physics object for entity {}!", entityID) + return nullptr; + } + + return &PHYSICS_OBJECT_ITERATOR->second; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsObjectManager::AddRigidBody(EntityID entityID) noexcept + { + SHPhysicsObject* physicsObject = nullptr; + + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) + physicsObject = createPhysicsObject(entityID); + else + physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + + // Get the component + auto* rigidBodyComponent = SHComponentManager::GetComponent(entityID); + + // Create a new rigidbody in the physics object + // We assume none has already been made + + physicsObject->rigidBody = new SHRigidBody + { + entityID + , static_cast(rigidBodyComponent->GetType()) + }; + + // Link with the component + rigidBodyComponent->SetRigidBody(physicsObject->rigidBody); + + // TODO: Broadcast event + } + + void SHPhysicsObjectManager::RemoveRigidBody(EntityID entityID) noexcept + { + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR != physicsObjects.end()) + { + SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + + delete physicsObject->rigidBody; + physicsObject->rigidBody = nullptr; + + // Destroy empty physics objects + if (physicsObject->rigidBody == nullptr) + destroyPhysicsObject(entityID); + } + + // TODO: Broadcast event + } + + void SHPhysicsObjectManager::AddCollider(EntityID entityID) noexcept + { + // Link with the component + + // TODO: Broadcast event + } + + void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept + { + // Unlink with the component + + // TODO: Broadcast event + } + + void SHPhysicsObjectManager::AddCollisionShape(EntityID entityID, uint8_t shapeID) noexcept + { + // Link with the component + + // TODO: Broadcast event + } + + void SHPhysicsObjectManager::RemoveCollisionShape(EntityID entityID, uint8_t shapeID) noexcept + { + // Unlink with the component + + // TODO: Broadcast event + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID entityID) + { + const auto& NEW_OBJECT = physicsObjects.emplace(entityID, SHPhysicsObject{entityID}).first; + return &NEW_OBJECT->second; + } + + void SHPhysicsObjectManager::destroyPhysicsObject(EntityID entityID) + { + physicsObjects.erase(entityID); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h new file mode 100644 index 00000000..17a1d3a1 --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h @@ -0,0 +1,125 @@ +/**************************************************************************************** + * \file SHPhysicsObjectManager.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Object Manager. + * + * \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 + +// Project Headers +#include "SHPhysicsObject.h" + +namespace SHADE +{ + /*-------------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a manager for physics objects that links raw physics components with the + * engine's components. + */ + class SHPhysicsObjectManager + { + private: + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + using EntityObjectMap = std::unordered_map; + + public: + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObjectManager() noexcept = default; + + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*-----------------------------------------------------------------------------------*/ + + [[nodiscard]] EntityObjectMap& GetPhysicsObjects () noexcept; + [[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Creates a rigid body and links it with the rigid body component. + * @param entityID + * The entity to link the new rigid body to. + */ + void AddRigidBody (EntityID entityID) noexcept; + + /** + * @brief + * Destroys a rigid body and removes the link with the rigid body component. + * @param entityID + * The entity to destroy the rigid body of. + */ + void RemoveRigidBody (EntityID entityID) noexcept; + + /** + * @brief + * Creates a collider and links it with the collider component. + * @param entityID + * The entity to link the new collider to. + */ + void AddCollider (EntityID entityID) noexcept; + + /** + * @brief + * Destroys a collider and removes the link with the collider component. + * @param entityID + * The entity to destroy the collider of. + */ + void RemoveCollider (EntityID entityID) noexcept; + + /** + * @brief + * Creates a collision shape for composite colliders and links it with the + * collider component. + * @param eientityIDd + * The entity to create a collision shape for. + * @param shapeID + * The id of the shape being created. + */ + void AddCollisionShape (EntityID entityID, uint8_t shapeID) noexcept; + + /** + * @brief + * Destroys a collision shape for composite colliders and removes the link with the + * collider component. + * @param entityID + * The entity to destroy the collision shape of. + * @param shapeID + * The id of the shape being destroyed. + */ + void RemoveCollisionShape (EntityID entityID, uint8_t shapeID) noexcept; + + private: + /*-----------------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------------*/ + + EntityObjectMap physicsObjects; + + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject* createPhysicsObject (EntityID entityID); + void destroyPhysicsObject (EntityID entityID); + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp similarity index 59% rename from SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp rename to SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp index 6dad9020..5924c612 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp @@ -18,7 +18,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" -#include "Math/SHMathHelpers.h" +#include "Physics/Dynamics/SHRigidBody.h" #include "Physics/System/SHPhysicsSystem.h" namespace SHADE @@ -28,77 +28,127 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHRigidBodyComponent::SHRigidBodyComponent() noexcept + : type { Type::STATIC } + , interpolate { true } + , rigidBody { nullptr } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept { - + return type; } - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - bool SHRigidBodyComponent::IsGravityEnabled() const noexcept { + if (rigidBody) + return rigidBody->IsGravityEnabled(); + return false; } bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept { + if (rigidBody) + return rigidBody->IsSleepingEnabled(); + return false; } bool SHRigidBodyComponent::IsInterpolating() const noexcept { + return interpolate; + } + + bool SHRigidBodyComponent::IsSleeping() const noexcept + { + if (rigidBody) + return rigidBody->IsSleeping(); + return false; } - bool SHRigidBodyComponent::GetIsSleeping() const noexcept + bool SHRigidBodyComponent::GetAutoMass() const noexcept { - return false; - } + if (rigidBody) + return rigidBody->IsAutoMassEnabled(); - SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept - { - return Type::STATIC; + return false; } bool SHRigidBodyComponent::GetFreezePositionX() const noexcept { + if (rigidBody) + return rigidBody->GetFreezePositionX(); + return false; } bool SHRigidBodyComponent::GetFreezePositionY() const noexcept { + if (rigidBody) + return rigidBody->GetFreezePositionY(); + return false; } bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept { + if (rigidBody) + return rigidBody->GetFreezePositionZ(); + return false; } bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept { + if (rigidBody) + return rigidBody->GetFreezeRotationX(); + return false; } bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept { + if (rigidBody) + return rigidBody->GetFreezeRotationY(); + return false; } bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept { + if (rigidBody) + return rigidBody->GetFreezeRotationZ(); + return false; } - float SHRigidBodyComponent::GetMass() const noexcept + float SHRigidBodyComponent::GetGravityScale() const noexcept { + if (rigidBody) + return rigidBody->GetGravityScale(); + return 0.0f; } + float SHRigidBodyComponent::GetMass() const noexcept + { + if (rigidBody) + return rigidBody->GetMass(); + + return -1.0f; + } + float SHRigidBodyComponent::GetDrag() const noexcept { - return 0.0f; + if (rigidBody) + return rigidBody->GetLinearDrag(); + + return -1.0f; } float SHRigidBodyComponent::GetAngularDrag() const noexcept @@ -108,6 +158,9 @@ namespace SHADE SHVec3 SHRigidBodyComponent::GetForce() const noexcept { + if (rigidBody) + return rigidBody->GetAccumulatedForce(); + return SHVec3::Zero; } @@ -118,6 +171,9 @@ namespace SHADE SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept { + if (rigidBody) + return rigidBody->GetLinearVelocity(); + return SHVec3::Zero; } @@ -127,91 +183,126 @@ namespace SHADE } /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ + /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ void SHRigidBodyComponent::SetType(Type newType) noexcept { - + if (newType == type) + return; + + type = newType; + + if (rigidBody) + rigidBody->SetType(static_cast(newType)); } - void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept + void SHRigidBodyComponent::SetRigidBody(SHRigidBody* rb) noexcept { - + rigidBody = rb; + } + + void SHRigidBodyComponent::SetIsGravityEnabled(bool enableGravity) noexcept + { + if (rigidBody) + rigidBody->SetGravityEnabled(enableGravity); } void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept { - + if (rigidBody) + rigidBody->SetSleepingEnabled(isAllowedToSleep); + } + + void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept + { + if (rigidBody) + rigidBody->SetAutoMassEnabled(autoMass); } void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept { - + if (rigidBody) + rigidBody->SetFreezePositionX(freezePositionX); } void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept { - + if (rigidBody) + rigidBody->SetFreezePositionY(freezePositionY); } void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept { - + if (rigidBody) + rigidBody->SetFreezePositionZ(freezePositionZ); } void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept { - + if (rigidBody) + rigidBody->SetFreezeRotationX(freezeRotationX); } void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept { - + if (rigidBody) + rigidBody->SetFreezeRotationY(freezeRotationY); } void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept { - + if (rigidBody) + rigidBody->SetFreezeRotationZ(freezeRotationZ); } void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept { - + interpolate = allowInterpolation; + } + + void SHRigidBodyComponent::SetGravityScale(float gravityScale) noexcept + { + if (rigidBody) + rigidBody->SetGravityScale(gravityScale); + } + + void SHRigidBodyComponent::SetMass(float newMass) noexcept + { + if (rigidBody) + rigidBody->SetMass(newMass); } void SHRigidBodyComponent::SetDrag(float newDrag) noexcept { - + if (rigidBody) + rigidBody->SetLinearDrag(newDrag); } void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept { - + } void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { - + if (rigidBody) + rigidBody->SetLinearVelocity(newLinearVelocity); } void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept { - + } /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ + /* Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBodyComponent::OnCreate() - { - - } - void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept { - + if (rigidBody) + rigidBody->AddForce(force); } void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept @@ -221,12 +312,13 @@ namespace SHADE void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept { - + if (rigidBody) + rigidBody->AddForce(force, worldPos); } void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept { - + } void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept @@ -251,7 +343,8 @@ namespace SHADE void SHRigidBodyComponent::ClearForces() const noexcept { - + if (rigidBody) + rigidBody->ClearForces(); } void SHRigidBodyComponent::ClearTorque() const noexcept @@ -259,6 +352,15 @@ namespace SHADE } + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHRigidBodyComponent::OnCreate() + { + + } + } // namespace SHADE RTTR_REGISTRATION @@ -274,17 +376,19 @@ RTTR_REGISTRATION ); registration::class_("RigidBody Component") - .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) - //.property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) - .property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag ) - .property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag ) - .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled ) - .property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate ) - .property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep) - .property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX ) - .property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY ) - .property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ ) - .property("Freeze Rotation X" , &SHRigidBodyComponent::GetFreezeRotationX , &SHRigidBodyComponent::SetFreezeRotationX ) - .property("Freeze Rotation Y" , &SHRigidBodyComponent::GetFreezeRotationY , &SHRigidBodyComponent::SetFreezeRotationY ) - .property("Freeze Rotation Z" , &SHRigidBodyComponent::GetFreezeRotationZ , &SHRigidBodyComponent::SetFreezeRotationZ ); + .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) + .property("Auto Mass" , &SHRigidBodyComponent::GetAutoMass , &SHRigidBodyComponent::SetAutoMass ) + .property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) + .property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag ) + .property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag ) + .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetIsGravityEnabled ) + .property("Gravity Scale" , &SHRigidBodyComponent::GetGravityScale , &SHRigidBodyComponent::SetGravityScale ) + .property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate ) + .property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep ) + .property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX ) + .property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY ) + .property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ ) + .property("Freeze Rotation X" , &SHRigidBodyComponent::GetFreezeRotationX , &SHRigidBodyComponent::SetFreezeRotationX ) + .property("Freeze Rotation Y" , &SHRigidBodyComponent::GetFreezeRotationY , &SHRigidBodyComponent::SetFreezeRotationY ) + .property("Freeze Rotation Z" , &SHRigidBodyComponent::GetFreezeRotationZ , &SHRigidBodyComponent::SetFreezeRotationZ ); } \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h similarity index 88% rename from SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h rename to SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h index 021743da..ae0bd3ec 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h @@ -15,10 +15,15 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" #include "Math/Vector/SHVec3.h" -#include "Math/SHQuaternion.h" namespace SHADE { + /*-------------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-------------------------------------------------------------------------------------*/ + + class SHRigidBody; + /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -67,13 +72,13 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] bool IsGravityEnabled () const noexcept; [[nodiscard]] bool IsAllowedToSleep () const noexcept; [[nodiscard]] bool IsInterpolating () const noexcept; - - [[nodiscard]] bool GetIsSleeping () const noexcept; - - [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] bool IsSleeping () const noexcept; + [[nodiscard]] bool GetAutoMass () const noexcept; [[nodiscard]] bool GetFreezePositionX () const noexcept; [[nodiscard]] bool GetFreezePositionY () const noexcept; @@ -82,6 +87,7 @@ namespace SHADE [[nodiscard]] bool GetFreezeRotationY () const noexcept; [[nodiscard]] bool GetFreezeRotationZ () const noexcept; + [[nodiscard]] float GetGravityScale () const noexcept; [[nodiscard]] float GetMass () const noexcept; [[nodiscard]] float GetDrag () const noexcept; [[nodiscard]] float GetAngularDrag () const noexcept; @@ -91,18 +97,18 @@ namespace SHADE [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; - //[[nodiscard]] const SHVec3& GetPosition () const noexcept; - //[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; - //[[nodiscard]] SHVec3 GetRotation () const noexcept; - /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ void SetType (Type newType) noexcept; - void SetGravityEnabled (bool enableGravity) noexcept; + void SetRigidBody (SHRigidBody* rb) noexcept; + + void SetIsGravityEnabled (bool enableGravity) noexcept; void SetIsAllowedToSleep (bool isAllowedToSleep) noexcept; + void SetAutoMass (bool autoMass) noexcept; + void SetFreezePositionX (bool freezePositionX) noexcept; void SetFreezePositionY (bool freezePositionY) noexcept; void SetFreezePositionZ (bool freezePositionZ) noexcept; @@ -110,9 +116,9 @@ namespace SHADE void SetFreezeRotationY (bool freezeRotationY) noexcept; void SetFreezeRotationZ (bool freezeRotationZ) noexcept; void SetInterpolate (bool allowInterpolation) noexcept; - //void SetAutoMass (bool autoMass) noexcept; - //void SetMass (float newMass) noexcept; + void SetGravityScale (float gravityScale) noexcept; + void SetMass (float newMass) noexcept; void SetDrag (float newDrag) noexcept; void SetAngularDrag (float newAngularDrag) noexcept; @@ -142,6 +148,11 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ + Type type; + bool interpolate; + SHRigidBody* rigidBody; + RTTR_ENABLE() }; + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp index 85e76702..d54d3f86 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp @@ -19,53 +19,9 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsWorldState::SHPhysicsWorldState() noexcept - : world { nullptr } - {} /*-----------------------------------------------------------------------------------*/ /* Public Function Members Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsWorldState::CreateWorld(rp3d::PhysicsCommon& factory) - { - rp3d::PhysicsWorld::WorldSettings rp3dWorldSettings; - rp3dWorldSettings.gravity = settings.gravity; - rp3dWorldSettings.defaultVelocitySolverNbIterations = settings.numVelocitySolverIterations; - rp3dWorldSettings.defaultPositionSolverNbIterations = settings.numPositionSolverIterations; - rp3dWorldSettings.isSleepingEnabled = settings.sleepingEnabled; - - // These are my preferred default values. QoL for modifying these. - rp3dWorldSettings.defaultBounciness = 0.0f; - rp3dWorldSettings.defaultFrictionCoefficient = 0.4f; - - world = factory.createPhysicsWorld(rp3dWorldSettings); - world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES); - } - - void SHPhysicsWorldState::DestroyWorld(rp3d::PhysicsCommon& factory) - { - if (!world) - return; - - factory.destroyPhysicsWorld(world); - world = nullptr; - } - - void SHPhysicsWorldState::UpdateSettings() const noexcept - { - if (!world) - { - SHLOGV_ERROR("Unable to update Physics World settings without creating a world!") - return; - } - - world->setGravity(settings.gravity); - world->setNbIterationsVelocitySolver(settings.numVelocitySolverIterations); - world->setNbIterationsPositionSolver(settings.numPositionSolverIterations); - world->enableSleeping(settings.sleepingEnabled); - } - - - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/SHPhysicsWorld.h index c5152c44..e872cd3c 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/SHPhysicsWorld.h @@ -10,8 +10,6 @@ #pragma once -#include - // Project Headers #include "Math/SHMath.h" #include "SH_API.h" @@ -47,7 +45,6 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - rp3d::PhysicsWorld* world; WorldSettings settings; /*---------------------------------------------------------------------------------*/ @@ -60,14 +57,6 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void CreateWorld (rp3d::PhysicsCommon& factory); - void DestroyWorld (rp3d::PhysicsCommon& factory); - - /** - * @brief Applies the current settings to the physics world. The world must be created - * before this is called. - */ - void UpdateSettings () const noexcept; }; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp similarity index 50% rename from SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp rename to SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 0029a8e7..9b1c0015 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHPhysicsSystemRoutines.h + * \file SHPhysicsPostUpdateRoutine.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for the Physics System Routines + * \brief Implementation for the Physics Post-Update Routine * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -11,24 +11,12 @@ #include // Primary Header -#include "SHPhysicsSystem.h" +#include "Physics/System/SHPhysicsSystem.h" + // Project Headers -#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Editor/SHEditor.h" -#include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" -#include "Input/SHInputManager.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" - -/*-------------------------------------------------------------------------------------*/ -/* Local Functions */ -/*-------------------------------------------------------------------------------------*/ - -void testFunction(); - -///////////////////////////////////////////////////////////////////////////////////////// namespace SHADE { @@ -36,59 +24,14 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate() - : SHSystemRoutine { "Physics PreUpdate", true } - {} - - SHPhysicsSystem::PhysicsFixedUpdate::PhysicsFixedUpdate() - : SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics FixedUpdate", false } - {} - SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate() - : SHSystemRoutine { "Physics PostUpdate", false } + : SHSystemRoutine { "Physics Post-Update", false } {} /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept - { - auto* physicsSystem = reinterpret_cast(GetSystem()); - } - - void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept - { - auto* physicsSystem = reinterpret_cast(GetSystem()); - - auto* scriptingSystem = SHSystemManager::GetSystem(); - if (scriptingSystem == nullptr) - { - SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); - } - - const double FIXED_DT = physicsSystem->fixedDT; - - accumulatedTime += dt; - - int count = 0; - while (accumulatedTime > FIXED_DT) - { - if (scriptingSystem != nullptr) - scriptingSystem->ExecuteFixedUpdates(); - - // TODO: Update World - - accumulatedTime -= FIXED_DT; - ++count; - } - - stats.numSteps = count; - physicsSystem->worldUpdated = count > 0; - - physicsSystem->interpolationFactor = accumulatedTime / fixedTimeStep; - } - void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept { auto* physicsSystem = reinterpret_cast(GetSystem()); @@ -110,6 +53,10 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ -} // namespace SHADE + void SHPhysicsSystem::PhysicsPostUpdate::syncTransforms(SHRigidBodyComponent* rbComponent) const noexcept + { + + } +} diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp new file mode 100644 index 00000000..a0f348f4 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -0,0 +1,62 @@ +/**************************************************************************************** + * \file SHPhysicsPreUpdateRoutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Pre-Update Routine + * + * \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 + +// Primary Header +#include "Physics/System/SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate() + : SHSystemRoutine { "Physics Pre-Update", true } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept + { + auto* physicsSystem = reinterpret_cast(GetSystem()); + + // Get all physics objects & sync transforms + for (auto& physicsObject : physicsSystem->physicsObjectManager.GetPhysicsObjects() | std::views::values) + syncTransforms(&physicsObject); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::PhysicsPreUpdate::syncTransforms(SHPhysicsObject* physicsObject) const noexcept + { + const EntityID EID = physicsObject->entityID; + + // Get relevant components: Transform, Rigidbody & Collider + const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(EID); + + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(EID); + auto* colliderComponent = SHComponentManager::GetComponent_s(EID); + + if (TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged()) + { + // Sync the objects transforms + } + } +} diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp new file mode 100644 index 00000000..77da8706 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp @@ -0,0 +1,62 @@ +/**************************************************************************************** + * \file SHPhysicsUpdateRoutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Update Routine + * + * \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 + +// Primary Header +#include "Physics/System/SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Scripting/SHScriptEngine.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::PhysicsUpdate::PhysicsUpdate() + : SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics Update", false } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::PhysicsUpdate::Execute(double dt) noexcept + { + auto* physicsSystem = reinterpret_cast(GetSystem()); + + auto* scriptEngine = SHSystemManager::GetSystem(); + if (!scriptEngine) + { + SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing ScriptEngine!") + } + + const double FIXED_DT = physicsSystem->fixedDT; + accumulatedTime += dt; + + int count = 0; + while (accumulatedTime > FIXED_DT) + { + + + accumulatedTime -= FIXED_DT; + ++count; + } + + stats.numSteps = count; + physicsSystem->worldUpdated = count > 0; + + physicsSystem->interpolationFactor = physicsSystem->worldUpdated ? accumulatedTime / FIXED_DT : 0.0; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index eacd6ac9..98a69087 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -20,9 +20,7 @@ #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" #include "Physics/Collision/SHCollisionTagMatrix.h" -#include "Physics/SHPhysicsEvents.h" -#include "Scene/SHSceneManager.h" -#include "Scripting/SHScriptEngine.h" +#include "Physics/Interface/SHColliderComponent.h" namespace SHADE { @@ -34,7 +32,18 @@ namespace SHADE : worldUpdated { false } , interpolationFactor { 0.0 } , fixedDT { DEFAULT_FIXED_STEP } - {} + { + // Add more events here to register them + + eventFunctions[0] = { &SHPhysicsSystem::onComponentAdded , SH_COMPONENT_ADDED_EVENT }; + eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT }; + eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_ON_INIT_EVENT }; + eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_ON_EXIT_EVENT }; + + #ifdef SHEDITOR + eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT }; + #endif + } /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ @@ -45,13 +54,48 @@ namespace SHADE return 1.0 / fixedDT; } + double SHPhysicsSystem::GetFixedDT() const noexcept + { + return fixedDT; + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept + void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept { + // Handle invalid input + if (fixedUpdateRate <= 0.0) + { + SHLOGV_WARNING("Invalid value for setting fixed update rate! Fixed update rate unchanged.") + return; + } + fixedDT = 1.0 / fixedUpdateRate; + + // Handle potential incorrect / unintended input + if (fixedDT > 1.0) + { + SHLOGV_WARNING("Fixed Update Rate Time is set below 1. This may result in undesirable behaviour.") + } + } + + void SHPhysicsSystem::SetFixedDT(double fixedDt) noexcept + { + if (fixedDt <= 0.0) + { + SHLOGV_WARNING("Invalid value for setting fixed delta time! Fixed delta time unchanged.") + return; + } + + fixedDT = fixedDt; + + // Handle potential incorrect / unintended input + if (fixedDT > 1.0) + { + SHLOGV_WARNING("Fixed Delta Time is set above 1. This may result in undesirable behaviour.") + } } /*-----------------------------------------------------------------------------------*/ @@ -64,11 +108,21 @@ namespace SHADE std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath); + + // Link Managers to system + + // Register Events + for (int i = 0; i < NUM_EVENT_FUNCTIONS; ++i) + { + const std::shared_ptr EVENT_RECEIVER = std::make_shared>(this, eventFunctions[i].first); + const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast(EVENT_RECEIVER); + + SHEventManager::SubscribeTo(eventFunctions[i].second, EVENT_RECEIVER_PTR); + } } void SHPhysicsSystem::Exit() { - // Write collision tag names to file std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); @@ -84,4 +138,98 @@ namespace SHADE /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ + SHEventHandle SHPhysicsSystem::onSceneInit(SHEventPtr onSceneInitEvent) + { + /* + * TODO: + * If a world already exists, destroy it + * Recreate the world + * + * If there is an editor and editor mode is already playing, link all entities with the world immediately. + */ + + return onSceneInitEvent.get()->handle; + } + + SHEventHandle SHPhysicsSystem::onSceneExit(SHEventPtr onSceneExitEvent) + { + /* + * TODO: + * Destroy the physics world. + * Destroy all physics objects. + */ + + return onSceneExitEvent.get()->handle; + } + + SHEventHandle SHPhysicsSystem::onComponentAdded(SHEventPtr onComponentAddedEvent) + { + static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID(); + static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID(); + + const auto& EVENT_DATA = reinterpret_cast*>(onComponentAddedEvent.get())->data; + + const auto ADDED_ID = EVENT_DATA->addedComponentType; + + const bool IS_RIGID_BODY = ADDED_ID == RIGID_BODY_COMPONENT_ID; + const bool IS_COLLIDER = ADDED_ID == COLLIDER_COMPONENT_ID; + + // Check if its a physics component + if (IS_RIGID_BODY || IS_COLLIDER) + { + const EntityID EID = EVENT_DATA->eid; + + // Link engine components with physics object component + if (IS_RIGID_BODY) + physicsObjectManager.AddRigidBody(EID); + + if (IS_COLLIDER) + physicsObjectManager.AddCollider(EID); + } + + return onComponentAddedEvent.get()->handle; + } + + SHEventHandle SHPhysicsSystem::onComponentRemoved(SHEventPtr onComponentRemovedEvent) + { + static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID(); + static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID(); + + const auto& EVENT_DATA = reinterpret_cast*>(onComponentRemovedEvent.get())->data; + + const auto REMOVED_DATA = EVENT_DATA->removedComponentType; + + const bool IS_RIGID_BODY = REMOVED_DATA == RIGID_BODY_COMPONENT_ID; + const bool IS_COLLIDER = REMOVED_DATA == COLLIDER_COMPONENT_ID; + + // Check if its a physics component + if (IS_RIGID_BODY || IS_COLLIDER) + { + const EntityID EID = EVENT_DATA->eid; + + // Link engine components with physics object component + if (IS_RIGID_BODY) + physicsObjectManager.RemoveRigidBody(EID); + + if (IS_COLLIDER) + physicsObjectManager.RemoveCollider(EID); + } + + return onComponentRemovedEvent.get()->handle; + } + +#ifdef SHEDITOR + + SHEventHandle SHPhysicsSystem::onEditorPlay(SHEventPtr onEditorPlayEvent) + { + /* + * TODO: + * Link all entities with the world. + */ + + return onEditorPlayEvent.get()->handle; + } + +#endif + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index 3fe05c09..1562241f 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -11,14 +11,15 @@ #pragma once // Project Headers +#include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHFixedSystemRoutine.h" +#include "Events/SHEvent.h" -#include "Math/Transform/SHTransformComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/SHPhysicsWorld.h" -#include "Scene/SHSceneGraph.h" + namespace SHADE { @@ -28,13 +29,6 @@ namespace SHADE class SH_API SHPhysicsSystem final : public SHSystem { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHPhysicsDebugDrawSystem; - public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -46,104 +40,121 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] double GetFixedUpdateRate () const noexcept; - [[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept; + [[nodiscard]] double GetFixedUpdateRate() const noexcept; + [[nodiscard]] double GetFixedDT() const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetFixedUpdateRate (double fixedUpdateRate) noexcept; - void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept; + void SetFixedUpdateRate(double fixedUpdateRate) noexcept; + void SetFixedDT(double fixedDt) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - void Init () override; - void Exit () override; + void Init() override; + void Exit() override; - void ForceUpdate (); + void ForceUpdate(); /*---------------------------------------------------------------------------------*/ /* System Routines */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * The physics update routine that runs before the simulation is updated. + * This is always running, regardless of the editor state. + *
+ * This update game logic is applied before the simulation runs. + */ class SH_API PhysicsPreUpdate final : public SHSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - PhysicsPreUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - void Execute(double dt) noexcept override; private: - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - + void syncTransforms(SHPhysicsObject* physicsObject) const noexcept; }; - class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine + /** + * @brief + * The physics update routine that runs at a fixed rate. This is where the main + * simulation runs. If delta time is large enough, this may run more than once per + * frame. If delta time is small enough, this may not run at all. + */ + class SH_API PhysicsUpdate final : public SHFixedSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - - PhysicsFixedUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - - void Execute (double dt) noexcept override; + PhysicsUpdate(); + void Execute(double dt) noexcept override; }; + /** + * @brief + * The physics update that runs after the simulation. This sets the rendering + * transforms and sends messages to scripting system for collision & trigger events. + */ class SH_API PhysicsPostUpdate final : public SHSystemRoutine { public: - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - PhysicsPostUpdate(); - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - void Execute(double dt) noexcept override; private: - - /*-------------------------------------------------------------------------------*/ - /* Function Members */ - /*-------------------------------------------------------------------------------*/ - + void syncTransforms(SHRigidBodyComponent* rbComponent) const noexcept; }; private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using EventFunctionPair = std::pair; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ + #ifdef SHEDITOR + static constexpr int NUM_EVENT_FUNCTIONS = 5; + #else + static constexpr int NUM_EVENT_FUNCTIONS = 4; + #endif + + // Event function container for cleanly registering to events + EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS]; + // System data bool worldUpdated; double interpolationFactor; double fixedDT; + // Sub-systems / managers + + SHPhysicsObjectManager physicsObjectManager; + /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ + SHEventHandle onSceneInit (SHEventPtr onSceneInitEvent); + SHEventHandle onSceneExit (SHEventPtr onSceneExitEvent); + + SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent); + SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent); + + + #ifdef SHEDITOR + + SHEventHandle onEditorPlay (SHEventPtr onEditorPlayEvent); + // We don't need an onEditorStop because on stop exits the scene, which is already handled above. + + #endif + }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 99e4fa41..9d648185 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -15,7 +15,7 @@ #include "Camera/SHCameraArmComponent.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" diff --git a/SHADE_Managed/src/Components/RigidBody.cxx b/SHADE_Managed/src/Components/RigidBody.cxx index a564402f..7b3604f2 100644 --- a/SHADE_Managed/src/Components/RigidBody.cxx +++ b/SHADE_Managed/src/Components/RigidBody.cxx @@ -34,7 +34,7 @@ namespace SHADE } void RigidBody::IsGravityEnabled::set(bool value) { - return GetNativeComponent()->SetGravityEnabled(value); + return GetNativeComponent()->SetIsGravityEnabled(value); } bool RigidBody::IsAllowedToSleep::get() { diff --git a/SHADE_Managed/src/Components/RigidBody.hxx b/SHADE_Managed/src/Components/RigidBody.hxx index 8bfe34aa..6ca39316 100644 --- a/SHADE_Managed/src/Components/RigidBody.hxx +++ b/SHADE_Managed/src/Components/RigidBody.hxx @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. #pragma once // External Dependencies -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" // Project Includes #include "Components/Component.hxx" diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index c388f0cd..3ace79ab 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -23,7 +23,7 @@ of DigiPen Institute of Technology is prohibited. #include "ECS_Base/Managers/SHEntityManager.h" #include "Math/Transform/SHTransformComponent.h" #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/Logger/SHLog.h" -- 2.40.1 From 36ceec5855faa477d292e9e105ca37a5a93e9ed2 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 5 Dec 2022 00:19:48 +0800 Subject: [PATCH 04/84] Added SceneInit & SceneExit events --- SHADE_Engine/src/Scene/SHSceneEvents.h | 10 +++ SHADE_Engine/src/Scene/SHSceneGraph.cpp | 46 ++++++------- SHADE_Engine/src/Scene/SHSceneGraph.h | 81 +++++++++++++++++++---- SHADE_Engine/src/Scene/SHSceneManager.cpp | 9 ++- SHADE_Engine/src/Scene/SHSceneNode.h | 13 ++-- 5 files changed, 115 insertions(+), 44 deletions(-) diff --git a/SHADE_Engine/src/Scene/SHSceneEvents.h b/SHADE_Engine/src/Scene/SHSceneEvents.h index c0d7dbc1..e76894bd 100644 --- a/SHADE_Engine/src/Scene/SHSceneEvents.h +++ b/SHADE_Engine/src/Scene/SHSceneEvents.h @@ -38,4 +38,14 @@ namespace SHADE SHSceneNode* childRemoved = nullptr; }; + struct SHSceneInitEvent + { + uint32_t sceneID = std::numeric_limits::max(); + }; + + struct SHSceneExitEvent + { + uint32_t sceneID = std::numeric_limits::max(); + }; + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index 6240b7bf..c040808f 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -27,7 +27,7 @@ namespace SHADE : root { nullptr } { // The root is set to the maximum entity. It should not be interfaced with. - root = AllocateNode(MAX_EID); + root = allocateNode(MAX_EID); } SHSceneGraph::~SHSceneGraph() noexcept @@ -239,7 +239,7 @@ namespace SHADE if (newParent == nullptr) newParent = root; - ChangeParent(NODE_ITER->second, newParent); + changeParent(NODE_ITER->second, newParent); SHEventManager::BroadcastEvent(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT); } @@ -284,7 +284,7 @@ namespace SHADE }; SHSceneNode* currentNode = NODE_ITER->second; - ChangeParent(currentNode, PARENT_ITER->second); + changeParent(currentNode, PARENT_ITER->second); SHEventManager::BroadcastEvent(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT); } @@ -310,7 +310,7 @@ namespace SHADE return NODE_ITER->second; } - SHSceneNode* newNode = AllocateNode(entityID); + SHSceneNode* newNode = allocateNode(entityID); if (parent == nullptr) { @@ -320,7 +320,7 @@ namespace SHADE } else { - ChangeParent(newNode, parent); + changeParent(newNode, parent); } return newNode; @@ -347,9 +347,9 @@ namespace SHADE // Remove reference of current node from parent SHSceneNode* currentNode = NODE_ITER->second; if (currentNode->parent != nullptr) - RemoveChild(currentNode->parent, currentNode); + removeChild(currentNode->parent, currentNode); - ReleaseNode(currentNode); + releaseNode(currentNode); return true; } @@ -357,16 +357,16 @@ namespace SHADE { // Remove reference of current node from parent if (nodeToRemove->parent != nullptr) - RemoveChild(nodeToRemove->parent, nodeToRemove); + removeChild(nodeToRemove->parent, nodeToRemove); - ReleaseNode(nodeToRemove); + releaseNode(nodeToRemove); return true; } void SHSceneGraph::Reset() noexcept { for (auto* node : entityNodeMap | std::views::values) - ReleaseNode(node); + releaseNode(node); } bool SHSceneGraph::IsChildOf(EntityID entityID, SHSceneNode* targetNode) noexcept @@ -456,39 +456,39 @@ namespace SHADE void SHSceneGraph::Traverse (const UnaryFunction& function) const { - TraverseAndInvokeFunction(root, function); + traverseAndInvokeFunction(root, function); } /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHSceneNode* SHSceneGraph::AllocateNode(EntityID entityID) + SHSceneNode* SHSceneGraph::allocateNode(EntityID entityID) { SHSceneNode* newNode = new SHSceneNode{entityID}; entityNodeMap.emplace(entityID, newNode); return newNode; } - void SHSceneGraph::ReleaseNode(SHSceneNode* node) noexcept + void SHSceneGraph::releaseNode(SHSceneNode* node) noexcept { SHASSERT(node != nullptr, "Attempting to release Invalid Node!") // Remove parent's reference to this node if there is a parent if (node->parent != nullptr) - RemoveChild(node->parent, node); + removeChild(node->parent, node); // Remove child's references to this node. Children end up as floating nodes. for (auto* child : node->GetChildren()) { - ChangeParent(child, nullptr); + changeParent(child, nullptr); } entityNodeMap.erase(node->GetEntityID()); delete node; } - void SHSceneGraph::ChangeParent(SHSceneNode* node, SHSceneNode* newParent) + void SHSceneGraph::changeParent(SHSceneNode* node, SHSceneNode* newParent) { // Handle self assignment if (node->parent != nullptr && newParent != nullptr && node->parent->entityID == newParent->entityID) @@ -496,7 +496,7 @@ namespace SHADE // Remove child if (node->parent) - RemoveChild(node->parent, node); + removeChild(node->parent, node); if (newParent == nullptr) { @@ -506,16 +506,16 @@ namespace SHADE node->parent = newParent; // Update parent's children - AddChild(newParent, node); + addChild(newParent, node); } - void SHSceneGraph::AddChild(SHSceneNode* node, SHSceneNode* newChild) + void SHSceneGraph::addChild(SHSceneNode* node, SHSceneNode* newChild) { SHASSERT(node != nullptr, "Attempting to modify a non-existent scene node!") SHASSERT(newChild != nullptr, "Attempting to add a non-existent child to a SceneNode!") if (newChild->parent) - RemoveChild(newChild->parent, newChild); + removeChild(newChild->parent, newChild); newChild->parent = node; node->children.emplace_back(newChild); @@ -529,7 +529,7 @@ namespace SHADE SHEventManager::BroadcastEvent(EVENT_DATA, SH_SCENEGRAPH_ADD_CHILD_EVENT); } - void SHSceneGraph::RemoveChild(SHSceneNode* node, SHSceneNode* childToRemove) + void SHSceneGraph::removeChild(SHSceneNode* node, SHSceneNode* childToRemove) { SHASSERT(node != nullptr, "Attempting to modify a non-existent scene node!") SHASSERT(childToRemove != nullptr, "Attempting to remove a non-existent child from a SceneNode!") @@ -550,12 +550,12 @@ namespace SHADE SHEventManager::BroadcastEvent(EVENT_DATA, SH_SCENEGRAPH_REMOVE_CHILD_EVENT); } - void SHSceneGraph::TraverseAndInvokeFunction(const SHSceneNode* node, const UnaryFunction& function) + void SHSceneGraph::traverseAndInvokeFunction(const SHSceneNode* node, const UnaryFunction& function) { for (auto* child : node->children) { function(child); - TraverseAndInvokeFunction(child, function); + traverseAndInvokeFunction(child, function); } } diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index 37d0e063..b72b1fb4 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -24,6 +24,10 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates a hierarchical tree for objects in the scene. + */ class SH_API SHSceneGraph { public: @@ -64,22 +68,75 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Changing the parent of a node will broadcast three events in the following order: + *
+ * 1. SHSceneGraphChangeParentEvent + * 2. SHSceneGraphRemoveChildEvent + * 3. SHSceneGraphAddChildEvent + *

+ * See the corresponding header file for the contents of the event struct. + */ void SetParent (EntityID entityID, SHSceneNode* newParent) noexcept; + + /** + * @brief + * Changing the parent of a node will broadcast three events in the following order: + *
+ * 1. SHSceneGraphChangeParentEvent + * 2. SHSceneGraphRemoveChildEvent + * 3. SHSceneGraphAddChildEvent + *

+ * See the corresponding header file for the contents of the event struct. + */ void SetParent (EntityID entityID, EntityID newParent) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Adding a node will broadcast two events in the following order: + *
+ * 1. SHSceneGraphChangeParentEvent + * 2. SHSceneGraphAddChildEvent + *

+ * See the corresponding header file for the contents of the event struct. + */ SHSceneNode* AddNode (EntityID entityID, SHSceneNode* parent = nullptr); - bool RemoveNode (EntityID entityID) noexcept; - bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; - void Reset () noexcept; - bool IsChildOf (EntityID entityID, SHSceneNode* targetNode) noexcept; - bool IsChildOf (EntityID entityID, EntityID targetID) noexcept; + /** + * @brief + * Removing a node will broadcast the SHSceneGraphRemoveChildEvent. + * See the corresponding header file for the contents of the event struct. + */ + bool RemoveNode (EntityID entityID) noexcept; - void Traverse (const UnaryFunction& function) const; + /** + * @brief + * Removing a node will broadcast the SHSceneGraphRemoveChildEvent. + * See the corresponding header file for the contents of the event struct. + */ + bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; + + /** + * @brief + * Clears all the scene nodes in the scene graph. + */ + void Reset () noexcept; + + bool IsChildOf (EntityID entityID, SHSceneNode* targetNode) noexcept; + bool IsChildOf (EntityID entityID, EntityID targetID) noexcept; + + /** + * @brief + * Traverses the graph and a depth-first manner and applies the the function onto each node. + * @param function + * A unary function that takes in a SHSceneNode pointer. + */ + void Traverse (const UnaryFunction& function) const; private: /*---------------------------------------------------------------------------------*/ @@ -93,14 +150,14 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHSceneNode* AllocateNode (EntityID entityID); - void ReleaseNode (SHSceneNode* node) noexcept; + SHSceneNode* allocateNode (EntityID entityID); + void releaseNode (SHSceneNode* node) noexcept; - void ChangeParent (SHSceneNode* node, SHSceneNode* newParent); - void AddChild (SHSceneNode* node, SHSceneNode* newChild); - void RemoveChild (SHSceneNode* node, SHSceneNode* childToRemove); + void changeParent (SHSceneNode* node, SHSceneNode* newParent); + void addChild (SHSceneNode* node, SHSceneNode* newChild); + void removeChild (SHSceneNode* node, SHSceneNode* childToRemove); - static void TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function); + static void traverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index 110aaea6..945e9ce1 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -17,6 +17,7 @@ #include "ECS_Base/Managers/SHSystemManager.h" //#include "FRC/SHFrameRateController.h" //#include "ECS_Base/System/SHApplication.h" +#include "SHSceneEvents.h" #include @@ -55,10 +56,11 @@ namespace SHADE if (currentScene) { currentScene->Free(); + SHEventManager::BroadcastEvent(SHSceneExitEvent{ currentSceneID }, SH_SCENE_ON_EXIT_EVENT); + currentScene->Unload(); SHEntityManager::DestroyAllEntity(); delete currentScene; - } if (!prevSceneReload) { @@ -84,6 +86,8 @@ namespace SHADE { currentScene->Load(); currentScene->Init(); + + SHEventManager::BroadcastEvent(SHSceneInitEvent{ currentSceneID }, SH_SCENE_ON_INIT_EVENT); } } else // restarting scene @@ -91,6 +95,8 @@ namespace SHADE nextSceneID = UINT32_MAX; currentScene->Free(); + SHEventManager::BroadcastEvent(SHSceneExitEvent{ currentSceneID }, SH_SCENE_ON_EXIT_EVENT); + if (cleanReload == true) { cleanReload = false; @@ -103,6 +109,7 @@ namespace SHADE SHEntityManager::DestroyAllEntity(); currentScene->Init(); + SHEventManager::BroadcastEvent(SHSceneInitEvent{ currentSceneID }, SH_SCENE_ON_INIT_EVENT); } } diff --git a/SHADE_Engine/src/Scene/SHSceneNode.h b/SHADE_Engine/src/Scene/SHSceneNode.h index 87bd8d0b..7f8e1dc3 100644 --- a/SHADE_Engine/src/Scene/SHSceneNode.h +++ b/SHADE_Engine/src/Scene/SHSceneNode.h @@ -15,20 +15,17 @@ // Project Headers #include "ECS_Base/Entity/SHEntity.h" #include "SH_API.h" -#include "SHSceneGraph.h" namespace SHADE { - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - class SHSceneGraph; - /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates an object in the scene that is part of the scene's hierarchy. + */ class SH_API SHSceneNode { private: @@ -66,7 +63,7 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetActive (bool newActiveState) noexcept; + void SetActive (bool newActiveState) noexcept; private: /*---------------------------------------------------------------------------------*/ -- 2.40.1 From 38b1c46d1f96a77023fe2f47cd2631f0645e0c21 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 5 Dec 2022 00:20:29 +0800 Subject: [PATCH 05/84] Added physics world and tested applied gravity for linear movement --- Assets/Scenes/PhysicsSandbox.shade | 21 ++- .../src/ECS_Base/Managers/SHEntityManager.cpp | 2 +- .../Inspector/SHEditorComponentView.hpp | 10 +- .../src/Math/Transform/SHTransformSystem.cpp | 2 - .../src/Physics/Dynamics/SHMotionState.cpp | 100 ++++++++++++++ .../src/Physics/Dynamics/SHMotionState.h | 93 +++++++++++++ .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 122 ++++++++++++++++++ .../Physics/{ => Dynamics}/SHPhysicsWorld.h | 52 ++++++-- .../src/Physics/Dynamics/SHRigidBody.cpp | 120 +++++++++-------- .../src/Physics/Dynamics/SHRigidBody.h | 37 ++++-- .../PhysicsObject/SHPhysicsObject.cpp | 13 +- .../Interface/PhysicsObject/SHPhysicsObject.h | 6 + .../PhysicsObject/SHPhysicsObjectManager.cpp | 42 +++++- .../PhysicsObject/SHPhysicsObjectManager.h | 10 +- .../SHRigidBodyComponent.cpp | 9 ++ .../RigidBodyComponent/SHRigidBodyComponent.h | 2 + SHADE_Engine/src/Physics/SHPhysicsWorld.cpp | 27 ---- .../Routines/SHPhysicsPostUpdateRoutine.cpp | 43 ++++-- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 40 +++--- .../Routines/SHPhysicsUpdateRoutine.cpp | 4 + .../src/Physics/System/SHPhysicsSystem.cpp | 87 +++++++++++-- .../src/Physics/System/SHPhysicsSystem.h | 12 +- .../Physics/System/SHPhysicsSystemInterface.h | 7 +- 23 files changed, 693 insertions(+), 168 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHMotionState.h create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp rename SHADE_Engine/src/Physics/{ => Dynamics}/SHPhysicsWorld.h (58%) delete mode 100644 SHADE_Engine/src/Physics/SHPhysicsWorld.cpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index a0b3c0c2..d6b77c17 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -9,10 +9,10 @@ Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: - Type: Static + Type: Dynamic Auto Mass: false Mass: 1 - Drag: 0 + Drag: 1 Angular Drag: 0 Use Gravity: true Gravity Scale: 1 @@ -25,4 +25,21 @@ Freeze Rotation Y: false Freeze Rotation Z: false IsActive: true + Scripts: ~ +- EID: 1 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Camera Component: + Position: {x: 0, y: 2, z: 5} + Pitch: 0 + Yaw: 0 + Roll: 0 + Width: 1920 + Height: 1080 + Near: 0.00999999978 + Far: 10000 + Perspective: true + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp index 1c603c57..f5f08674 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp +++ b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp @@ -162,7 +162,7 @@ namespace SHADE //SHSceneNode* parentNode = entityVec[eIndex]->GetSceneNode()->GetParent(); - //SHSceneGraph::RemoveChild(parentNode,entityVec[eIndex].get()); + //SHSceneGraph::removeChild(parentNode,entityVec[eIndex].get()); //TODO remove from parent and recursively delete child. diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 02614631..71d607f5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -252,12 +252,13 @@ namespace SHADE if(rbType == SHRigidBodyComponent::Type::DYNAMIC) //Dynamic only fields { SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetIsGravityEnabled(value);}, "Gravity"); - //SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); + SHEditorWidgets::DragFloat("Gravity Scale", [component] { return component->GetGravityScale(); }, [component](float const& value) { component->SetGravityScale(value); }, "Gravity Scale", 0.1f, 0.0f); + SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); } if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { - SHEditorWidgets::DragFloat("Drag", [component] {return component->GetDrag(); }, [component](float const& value) {component->SetDrag(value); }, "Drag"); - SHEditorWidgets::DragFloat("Angular Drag", [component] {return component->GetAngularDrag(); }, [component](float const& value) {component->SetAngularDrag(value); }, "Angular Drag"); + SHEditorWidgets::DragFloat("Drag", [component] {return component->GetDrag(); }, [component](float const& value) {component->SetDrag(value); }, "Drag", 0.1f, 0.0f); + SHEditorWidgets::DragFloat("Angular Drag", [component] {return component->GetAngularDrag(); }, [component](float const& value) {component->SetAngularDrag(value); }, "Angular Drag", 0.1f, 0.0f); SHEditorWidgets::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "Interpolate"); @@ -284,8 +285,7 @@ namespace SHADE //Debug Info (Read-Only) if(ImGui::CollapsingHeader("Debug Information", ImGuiTreeNodeFlags_DefaultOpen))//Dynamic or Kinematic only fields { - SHEditorWidgets::DragFloat("Mass", [component] { return component->GetMass(); }, [](float value){}, "Mass", 0.1f, 0.0f, std::numeric_limits::infinity(), "%.3f", ImGuiSliderFlags_ReadOnly); - //SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component] {return component->GetPosition(); }, [](SHVec3 const& value) {}, false, "Position", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component] {return component->GetPosition(); }, [](SHVec3 const& value) {}, false, "Position", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); //SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, [component] {return component->GetRotation(); }, [](SHVec3 const& value) {}, false, "Rotation", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index 03de360d..0a0ec092 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -246,8 +246,6 @@ namespace SHADE tf.world.position = SHVec3::Transform(tf.local.position, localToWorld); tf.world.scale = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One); - - if (convertRotation) { tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp new file mode 100644 index 00000000..2cca1c45 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp @@ -0,0 +1,100 @@ +/**************************************************************************************** + * \file SHMotionState.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Motion State. + * + * \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 + +// Primary Header +#include "SHMotionState.h" + +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMotionState::SHMotionState() noexcept + : hasMoved { false } + {} + + SHMotionState::SHMotionState(const SHMotionState& rhs) noexcept + : hasMoved { rhs.hasMoved } + , position { rhs.position } + , prevPosition { rhs.prevPosition } + {} + + SHMotionState::SHMotionState(SHMotionState&& rhs) noexcept + : hasMoved { rhs.hasMoved } + , position { rhs.position } + , prevPosition { rhs.prevPosition } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMotionState& SHMotionState::operator=(const SHMotionState& rhs) noexcept + { + if (this == &rhs) + return *this; + + hasMoved = rhs.hasMoved; + position = rhs.position; + prevPosition = rhs.prevPosition; + + return *this; + } + + SHMotionState& SHMotionState::operator=(SHMotionState&& rhs) noexcept + { + hasMoved = rhs.hasMoved; + position = rhs.position; + prevPosition = rhs.prevPosition; + + return *this; + } + + SHMotionState::operator bool() const noexcept + { + return hasMoved; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definition */ + /*-----------------------------------------------------------------------------------*/ + + void SHMotionState::ForcePosition(const SHVec3& newPosition) noexcept + { + hasMoved = false; + + prevPosition = newPosition; + position = newPosition; + } + + void SHMotionState::IntegratePosition(const SHVec3& velocity, float dt) noexcept + { + // Velocities are 0 when objects are static or sleeping. We do not want to integrate them here. + // This call should never reach here. + + hasMoved = true; + + prevPosition = position; + position += velocity * dt; + } + + SHVec3 SHMotionState::InterpolatePositions(float factor) const noexcept + { + return SHVec3::ClampedLerp(prevPosition, position, factor); + } + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h new file mode 100644 index 00000000..4cff9a8f --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h @@ -0,0 +1,93 @@ +/**************************************************************************************** + * \file SHMotionState.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Motion State. + * + * \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/Vector/SHVec3.h" + +namespace SHADE +{ + /*-------------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates the motion state of a rigid body in physics. + */ + struct SH_API SHMotionState + { + public: + /*-----------------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------------*/ + + bool hasMoved; + + SHVec3 position; + SHVec3 prevPosition; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-----------------------------------------------------------------------------------*/ + + SHMotionState () noexcept; + SHMotionState (const SHMotionState& rhs) noexcept; + SHMotionState (SHMotionState&& rhs) noexcept; + + ~SHMotionState() = default; + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*-----------------------------------------------------------------------------------*/ + + SHMotionState& operator= (const SHMotionState& rhs) noexcept; + SHMotionState& operator= (SHMotionState&& rhs) noexcept; + + operator bool () const noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Function Members */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Forcefully sets the position. Meant to be used when transform overrides the rigid body + * positions. + * @param newPosition + * The new position to set. + */ + void ForcePosition (const SHVec3& newPosition) noexcept; + + /** + * @brief + * Integrates the positions using velocity with respect to time. + * @param velocity + * The velocity to integrate. + * @param dt + * The delta time to integrate with respect to. + */ + void IntegratePosition (const SHVec3& velocity, float dt) noexcept; + + /** + * @brief + * Interpolates the position between the previous and the last using a given factor. + * @param factor + * The factor to interpolate by. Should be between 0 & 1. + * @returns + * The interpolated position meant for rendering. + */ + SHVec3 InterpolatePositions (float factor) const noexcept; + + }; + + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp new file mode 100644 index 00000000..7d6c7c5c --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -0,0 +1,122 @@ +/**************************************************************************************** + * \file SHPhysicsWorld.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics World. + * + * \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 + +// Primary Header +#include "SHPhysicsWorld.h" + +// Project Headers + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept + : settings { worldSettings } + { + rigidBodies.clear(); + SHLOG_INFO_D("Creating Physics World") + } + + SHPhysicsWorld::~SHPhysicsWorld() noexcept + { + rigidBodies.clear(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsWorld::AddRigidBody(SHRigidBody* rigidBody) noexcept + { + const bool INSERTED = rigidBodies.emplace(rigidBody->entityID, rigidBody).second; + if (!INSERTED) + { + SHLOG_WARNING_D("Attempting to add duplicate rigid body {} to the Physics World!", rigidBody->entityID) + } + } + + void SHPhysicsWorld::RemoveRigidBody(SHRigidBody* rigidBody) noexcept + { + rigidBodies.erase(rigidBody->entityID); + } + + void SHPhysicsWorld::Step(float dt) + { + for (auto* rigidBody : rigidBodies | std::views::values) + integrateForces(*rigidBody, dt); + + for (auto* rigidBody : rigidBodies | std::views::values) + integrateVelocities(*rigidBody, dt); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsWorld::integrateForces(SHRigidBody& rigidBody, float dt) const noexcept + { + if (rigidBody.bodyType != SHRigidBody::Type::DYNAMIC) + return; + + // Integrate forces and gravity into linear velocity + const SHVec3 LINEAR_ACCELERATION = rigidBody.accumulatedForce * rigidBody.invMass; + const SHVec3 GRAVITATIONAL_ACCELERATION = rigidBody.IsGravityEnabled() ? settings.gravity * rigidBody.gravityScale : SHVec3::Zero; + + rigidBody.linearVelocity += (LINEAR_ACCELERATION + GRAVITATIONAL_ACCELERATION) * dt; + + // Apply drag (exponentially applied) + rigidBody.linearVelocity *= 1.0f / (1.0f + dt * rigidBody.linearDrag); + } + + void SHPhysicsWorld::integrateVelocities(SHRigidBody& rigidBody, float dt) const noexcept + { + static const auto ENFORCE_CONSTRAINED_VELOCITIES = [](SHRigidBody& rigidBody) + { + // Enforce linear constraints + rigidBody.linearVelocity = SHVec3 + { + rigidBody.GetFreezePositionX() ? 0.0f : rigidBody.linearVelocity.x + , rigidBody.GetFreezePositionY() ? 0.0f : rigidBody.linearVelocity.y + , rigidBody.GetFreezePositionZ() ? 0.0f : rigidBody.linearVelocity.z + }; + + // TODO: Enforce angular constraints + }; + + // Always reset movement flag + rigidBody.motionState.hasMoved = false; + + // Set all velocities of static bodies to 0 + if (rigidBody.bodyType == SHRigidBody::Type::STATIC) + { + rigidBody.linearVelocity = SHVec3::Zero; + } + else // Dynamic & Kinematic bodies + { + // Both dynamic and kinematic can sleep when their velocities are under the thresholds. + if (!rigidBody.IsSleeping()) + { + ENFORCE_CONSTRAINED_VELOCITIES(rigidBody); + + rigidBody.motionState.IntegratePosition(rigidBody.linearVelocity, dt); + // TODO: Integrate orientations + } + } + + // Clear all forces + // We clear forces for static bodies as well for redundancy + rigidBody.ClearForces(); + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h similarity index 58% rename from SHADE_Engine/src/Physics/SHPhysicsWorld.h rename to SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index e872cd3c..eb96a021 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -10,7 +10,10 @@ #pragma once +#include + // Project Headers +#include "SHRigidBody.h" #include "Math/SHMath.h" #include "SH_API.h" @@ -20,7 +23,7 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - struct SH_API SHPhysicsWorldState + class SH_API SHPhysicsWorld { public: @@ -41,22 +44,55 @@ namespace SHADE bool sleepingEnabled = true; }; - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - WorldSettings settings; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHPhysicsWorldState() noexcept; + SHPhysicsWorld (const WorldSettings& worldSettings = WorldSettings{}) noexcept; + ~SHPhysicsWorld () noexcept; + + SHPhysicsWorld (const SHPhysicsWorld&) = delete; + SHPhysicsWorld (SHPhysicsWorld&&) = delete; + + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsWorld& operator=(const SHPhysicsWorld&) = delete; + SHPhysicsWorld& operator=(SHPhysicsWorld&&) = delete; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ + void AddRigidBody (SHRigidBody* rigidBody) noexcept; + void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; + + void Step (float dt); + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using RigidBodies = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + WorldSettings settings; + + RigidBodies rigidBodies; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept; + void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept; + }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 1867636c..8f99a8f5 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -26,7 +26,7 @@ namespace SHADE : entityID { eid } , bodyType { type } , invMass { type == Type::DYNAMIC ? 1.0f : 0.0f } - , linearDrag { type != Type::STATIC ? 0.01f : 0.0f } + , linearDrag { 0.01f } , gravityScale { 1.0f } , flags { 0U } { @@ -45,6 +45,7 @@ namespace SHADE , linearDrag { rhs.linearDrag } , gravityScale { rhs.gravityScale } , flags { rhs.flags } + , motionState { rhs.motionState } { // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. } @@ -56,6 +57,7 @@ namespace SHADE , linearDrag { rhs.linearDrag } , gravityScale { rhs.gravityScale } , flags { rhs.flags } + , motionState { std::move(rhs.motionState) } { // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. } @@ -70,28 +72,36 @@ namespace SHADE if (this == &rhs) return *this; - entityID = rhs.entityID; - bodyType = rhs.bodyType; - invMass = rhs.invMass; - linearDrag = rhs.linearDrag; - gravityScale = rhs.gravityScale; - flags = rhs.flags; + entityID = rhs.entityID; + bodyType = rhs.bodyType; + invMass = rhs.invMass; + linearDrag = rhs.linearDrag; + gravityScale = rhs.gravityScale; + flags = rhs.flags; + motionState = rhs.motionState; // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. + accumulatedForce = SHVec3::Zero; + linearVelocity = SHVec3::Zero; + angularVelocity = SHVec3::Zero; 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; + entityID = rhs.entityID; + bodyType = rhs.bodyType; + invMass = rhs.invMass; + linearDrag = rhs.linearDrag; + gravityScale = rhs.gravityScale; + flags = rhs.flags; + motionState = std::move(rhs.motionState); // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. + accumulatedForce = SHVec3::Zero; + linearVelocity = SHVec3::Zero; + angularVelocity = SHVec3::Zero; return *this; } @@ -105,118 +115,124 @@ namespace SHADE return bodyType; } - float SHRigidBody::GetMass() const noexcept + float SHRigidBody::GetMass() const noexcept { return 1.0f/ invMass; } - float SHRigidBody::GetLinearDrag() const noexcept + float SHRigidBody::GetLinearDrag() const noexcept { return linearDrag; } - float SHRigidBody::GetGravityScale() const noexcept + float SHRigidBody::GetGravityScale() const noexcept { return gravityScale; } - const SHVec3& SHRigidBody::GetAccumulatedForce() const noexcept + const SHVec3& SHRigidBody::GetAccumulatedForce() const noexcept { return accumulatedForce; } - const SHVec3& SHRigidBody::GetLinearVelocity() const noexcept + const SHVec3& SHRigidBody::GetLinearVelocity() const noexcept { return linearVelocity; } - const SHVec3& SHRigidBody::GetAngularVelocity() const noexcept + const SHVec3& SHRigidBody::GetAngularVelocity() const noexcept { return angularVelocity; } // Flags - bool SHRigidBody::IsActive() const noexcept + bool SHRigidBody::IsActive() const noexcept { static constexpr unsigned int FLAG_POS = 0; return flags & (1U << FLAG_POS); } - bool SHRigidBody::IsSleeping() const noexcept + bool SHRigidBody::IsSleeping() const noexcept { static constexpr unsigned int FLAG_POS = 1; return flags & (1U << FLAG_POS); } - bool SHRigidBody::IsSleepingEnabled() const noexcept + bool SHRigidBody::IsSleepingEnabled() const noexcept { static constexpr unsigned int FLAG_POS = 2; return flags & (1U << FLAG_POS); } - bool SHRigidBody::IsGravityEnabled() const noexcept + bool SHRigidBody::IsGravityEnabled() const noexcept { static constexpr unsigned int FLAG_POS = 3; return flags & (1U << FLAG_POS); } - bool SHRigidBody::IsAutoMassEnabled() const noexcept + bool SHRigidBody::IsAutoMassEnabled() const noexcept { static constexpr unsigned int FLAG_POS = 4; return flags & (1U << FLAG_POS); } - bool SHRigidBody::GetFreezePositionX() const noexcept + bool SHRigidBody::GetFreezePositionX() const noexcept { static constexpr unsigned int FLAG_POS = 10; return flags & (1U << FLAG_POS); } - bool SHRigidBody::GetFreezePositionY() const noexcept + bool SHRigidBody::GetFreezePositionY() const noexcept { static constexpr unsigned int FLAG_POS = 11; return flags & (1U << FLAG_POS); } - bool SHRigidBody::GetFreezePositionZ() const noexcept + bool SHRigidBody::GetFreezePositionZ() const noexcept { static constexpr unsigned int FLAG_POS = 12; return flags & (1U << FLAG_POS); } - bool SHRigidBody::GetFreezeRotationX() const noexcept + bool SHRigidBody::GetFreezeRotationX() const noexcept { static constexpr unsigned int FLAG_POS = 13; return flags & (1U << FLAG_POS); } - bool SHRigidBody::GetFreezeRotationY() const noexcept + bool SHRigidBody::GetFreezeRotationY() const noexcept { static constexpr unsigned int FLAG_POS = 14; return flags & (1U << FLAG_POS); } - bool SHRigidBody::GetFreezeRotationZ() const noexcept + bool SHRigidBody::GetFreezeRotationZ() const noexcept { static constexpr unsigned int FLAG_POS = 15; return flags & (1U << FLAG_POS); } + SHMotionState& SHRigidBody::GetMotionState() noexcept + { + return motionState; + } + + /*-----------------------------------------------------------------------------------*/ /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBody::SetType(Type newType) noexcept + void SHRigidBody::SetType(Type newType) noexcept { if (newType == bodyType) return; - bodyType = newType; - invMass = newType == Type::DYNAMIC ? 1.0f : 0.0f; + bodyType = newType; + invMass = newType == Type::DYNAMIC ? 1.0f : 0.0f; } - void SHRigidBody::SetMass(float newMass) noexcept + void SHRigidBody::SetMass(float newMass) noexcept { if (bodyType != Type::DYNAMIC) { @@ -235,7 +251,7 @@ namespace SHADE // TODO: Recompute inertia tensor } - void SHRigidBody::SetLinearDrag(float newLinearDrag) noexcept + void SHRigidBody::SetLinearDrag(float newLinearDrag) noexcept { if (bodyType == Type::STATIC) { @@ -252,17 +268,17 @@ namespace SHADE linearDrag = newLinearDrag; } - void SHRigidBody::SetGravityScale(float newGravityScale) noexcept + void SHRigidBody::SetGravityScale(float newGravityScale) noexcept { gravityScale = newGravityScale; } - void SHRigidBody::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept + void SHRigidBody::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { linearVelocity = newLinearVelocity; } - void SHRigidBody::SetIsActive(bool isActive) noexcept + void SHRigidBody::SetIsActive(bool isActive) noexcept { static constexpr unsigned int FLAG_POS = 0; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -270,7 +286,7 @@ namespace SHADE isActive ? flags |= VALUE : flags &= ~VALUE; } - void SHRigidBody::SetIsSleeping(bool isSleeping) noexcept + void SHRigidBody::SetIsSleeping(bool isSleeping) noexcept { static constexpr unsigned int FLAG_POS = 1; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -278,7 +294,7 @@ namespace SHADE isSleeping ? flags |= VALUE : flags &= ~VALUE; } - void SHRigidBody::SetSleepingEnabled(bool enableSleeping) noexcept + void SHRigidBody::SetSleepingEnabled(bool enableSleeping) noexcept { static constexpr unsigned int FLAG_POS = 2; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -295,7 +311,7 @@ namespace SHADE } } - void SHRigidBody::SetGravityEnabled(bool enableGravity) noexcept + void SHRigidBody::SetGravityEnabled(bool enableGravity) noexcept { static constexpr unsigned int FLAG_POS = 3; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -303,7 +319,7 @@ namespace SHADE enableGravity ? flags |= VALUE : flags &= ~VALUE; } - void SHRigidBody::SetAutoMassEnabled(bool enableAutoMass) noexcept + void SHRigidBody::SetAutoMassEnabled(bool enableAutoMass) noexcept { static constexpr unsigned int FLAG_POS = 4; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -321,7 +337,7 @@ namespace SHADE } } - void SHRigidBody::SetFreezePositionX(bool freezePositionX) noexcept + void SHRigidBody::SetFreezePositionX(bool freezePositionX) noexcept { static constexpr unsigned int FLAG_POS = 10; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -338,7 +354,7 @@ namespace SHADE } } - void SHRigidBody::SetFreezePositionY(bool freezePositionY) noexcept + void SHRigidBody::SetFreezePositionY(bool freezePositionY) noexcept { static constexpr unsigned int FLAG_POS = 11; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -355,7 +371,7 @@ namespace SHADE } } - void SHRigidBody::SetFreezePositionZ(bool freezePositionZ) noexcept + void SHRigidBody::SetFreezePositionZ(bool freezePositionZ) noexcept { static constexpr unsigned int FLAG_POS = 12; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -372,7 +388,7 @@ namespace SHADE } } - void SHRigidBody::SetFreezeRotationX(bool freezeRotationX) noexcept + void SHRigidBody::SetFreezeRotationX(bool freezeRotationX) noexcept { static constexpr unsigned int FLAG_POS = 13; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -389,7 +405,7 @@ namespace SHADE } } - void SHRigidBody::SetFreezeRotationY(bool freezeRotationY) noexcept + void SHRigidBody::SetFreezeRotationY(bool freezeRotationY) noexcept { static constexpr unsigned int FLAG_POS = 14; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -406,7 +422,7 @@ namespace SHADE } } - void SHRigidBody::SetFreezeRotationZ(bool freezeRotationZ) noexcept + void SHRigidBody::SetFreezeRotationZ(bool freezeRotationZ) noexcept { static constexpr unsigned int FLAG_POS = 15; static constexpr uint16_t VALUE = 1U << FLAG_POS; @@ -424,10 +440,10 @@ namespace SHADE } /*-----------------------------------------------------------------------------------*/ - /* Member Function Definitions */ + /* Public Member Function Definition */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBody::AddForce(const SHVec3& force, const SHVec3& pos) noexcept + void SHRigidBody::AddForce(const SHVec3& force, const SHVec3& pos) noexcept { if (bodyType != Type::DYNAMIC) return; @@ -436,7 +452,7 @@ namespace SHADE // Compute torque when force is offset } - void SHRigidBody::AddImpulse(const SHVec3& impulse, const SHVec3& pos) noexcept + void SHRigidBody::AddImpulse(const SHVec3& impulse, const SHVec3& pos) noexcept { if (bodyType != Type::DYNAMIC) return; @@ -444,7 +460,7 @@ namespace SHADE linearVelocity += impulse * invMass; } - void SHRigidBody::ClearForces() noexcept + void SHRigidBody::ClearForces() noexcept { accumulatedForce = SHVec3::Zero; } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 77b29292..dbf2344f 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -13,7 +13,7 @@ // Project Headers #include "ECS_Base/SHECSMacros.h" #include "Math/Vector/SHVec3.h" -#include "SH_API.h" +#include "SHMotionState.h" namespace SHADE { @@ -27,6 +27,13 @@ namespace SHADE */ class SH_API SHRigidBody { + private: + /*-----------------------------------------------------------------------------------*/ + /* Friends */ + /*-----------------------------------------------------------------------------------*/ + + friend class SHPhysicsWorld; + public: /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -83,13 +90,16 @@ namespace SHADE [[nodiscard]] bool GetFreezeRotationY () const noexcept; [[nodiscard]] bool GetFreezeRotationZ () const noexcept; + [[nodiscard]] SHMotionState& GetMotionState () noexcept; + /*-----------------------------------------------------------------------------------*/ /* Setter Functions */ /*-----------------------------------------------------------------------------------*/ /** * @brief - * Changing the type from non-Dynamic to Dynamic will set the default mass. + * Changing the type from non-Dynamic to Dynamic will set the default + * mass and drag values. */ void SetType (Type newType) noexcept; @@ -111,7 +121,6 @@ namespace SHADE void SetGravityScale (float newGravityScale) noexcept; - void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; // Flags @@ -164,22 +173,24 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ // The entityID here is only meant for linking with the actual component in the engine. - EntityID entityID; + EntityID entityID; - Type bodyType; + Type bodyType; - float invMass; - float linearDrag; + float invMass; + float linearDrag; - float gravityScale; + float gravityScale; + + SHVec3 accumulatedForce; - SHVec3 accumulatedForce; - - SHVec3 linearVelocity; - SHVec3 angularVelocity; + SHVec3 linearVelocity; + SHVec3 angularVelocity; // aZ aY aX pZ pY pX 0 0 0 0 0 autoMass enableGravity enableSleeping sleeping active - uint16_t flags; + uint16_t flags; + + SHMotionState motionState; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp index 44452868..b6e5ac40 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -44,9 +44,8 @@ namespace SHADE delete rigidBody; } - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ + /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ SHPhysicsObject& SHPhysicsObject::operator=(const SHPhysicsObject& rhs) noexcept @@ -71,4 +70,14 @@ namespace SHADE return *this; } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHPhysicsObject::IsEmpty() const noexcept + { + return rigidBody == nullptr; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h index 2be5844d..f297a6fb 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h @@ -48,5 +48,11 @@ namespace SHADE SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept; SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept; + + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + bool IsEmpty() const noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp index dccca97b..e6e92ba5 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp @@ -14,6 +14,7 @@ #include "SHPhysicsObjectManager.h" // Project Headers +#include "Math/Transform/SHTransformComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Physics/Interface/SHCollisionShape.h" #include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" @@ -21,16 +22,25 @@ namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObjectManager::~SHPhysicsObjectManager() noexcept + { + RemoveAllObjects(); + } + /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsObjectManager::EntityObjectMap& SHPhysicsObjectManager::GetPhysicsObjects() noexcept + SHPhysicsObjectManager::EntityObjectMap& SHPhysicsObjectManager::GetPhysicsObjects() noexcept { return physicsObjects; } - const SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID entityID) noexcept + const SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID entityID) noexcept { const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) @@ -68,6 +78,17 @@ namespace SHADE , static_cast(rigidBodyComponent->GetType()) }; + SHMotionState& motionState = physicsObject->rigidBody->GetMotionState(); + + if (const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent(entityID); TRANSFORM_COMPONENT) + { + motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); + } + else + { + motionState.ForcePosition(SHVec3::Zero); + } + // Link with the component rigidBodyComponent->SetRigidBody(physicsObject->rigidBody); @@ -85,7 +106,7 @@ namespace SHADE physicsObject->rigidBody = nullptr; // Destroy empty physics objects - if (physicsObject->rigidBody == nullptr) + if (physicsObject->IsEmpty()) destroyPhysicsObject(entityID); } @@ -101,7 +122,15 @@ namespace SHADE void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept { - // Unlink with the component + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + if (PHYSICS_OBJECT_ITERATOR != physicsObjects.end()) + { + SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + + // Destroy empty physics objects + if (physicsObject->IsEmpty()) + destroyPhysicsObject(entityID); + } // TODO: Broadcast event } @@ -120,6 +149,11 @@ namespace SHADE // TODO: Broadcast event } + void SHPhysicsObjectManager::RemoveAllObjects() noexcept + { + physicsObjects.clear(); + } + /*-----------------------------------------------------------------------------------*/ /* Private Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h index 17a1d3a1..6449a2d8 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h @@ -40,7 +40,8 @@ namespace SHADE /* Constructors & Destructor */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsObjectManager() noexcept = default; + SHPhysicsObjectManager () noexcept = default; + ~SHPhysicsObjectManager () noexcept; /*-----------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -107,6 +108,13 @@ namespace SHADE */ void RemoveCollisionShape (EntityID entityID, uint8_t shapeID) noexcept; + /** + * @brief + * Removes all physics object in the manager. This is only meant to be called when + * the world is being destroyed or the scene is being changed. + */ + void RemoveAllObjects () noexcept; + private: /*-----------------------------------------------------------------------------------*/ /* Data Members */ diff --git a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp index 5924c612..ddc51fbc 100644 --- a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp @@ -182,6 +182,15 @@ namespace SHADE return SHVec3::Zero; } + SHVec3 SHRigidBodyComponent::GetPosition() const noexcept + { + if (rigidBody) + return rigidBody->GetMotionState().position; + + return SHVec3::Zero; + } + + /*-----------------------------------------------------------------------------------*/ /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h index ae0bd3ec..bfb1717b 100644 --- a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h @@ -97,6 +97,8 @@ namespace SHADE [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; + [[nodiscard]] SHVec3 GetPosition () const noexcept; + /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp deleted file mode 100644 index d54d3f86..00000000 --- a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsWorld.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Physics World. - * - * \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 - -// Primary Header -#include "SHPhysicsWorld.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Members Definitions */ - /*-----------------------------------------------------------------------------------*/ - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 9b1c0015..5f18c450 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -15,6 +15,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/Transform/SHTransformComponent.h" #include "Scripting/SHScriptEngine.h" @@ -39,24 +40,40 @@ namespace SHADE if (scriptingSystem == nullptr) { - SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); + SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); } - // Interpolate transforms for rendering + const float FACTOR = static_cast(physicsSystem->interpolationFactor); + + // Interpolate transforms for rendering. + // Only rigid bodies can move due to physics, so we run through the rigid body component dense set. + const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); + for (auto& rigidBodyComponent : RIGIDBODY_DENSE) + { + auto* transformComponent = SHComponentManager::GetComponent_s(rigidBodyComponent.GetEID()); + if (!transformComponent) + continue; + + if (!rigidBodyComponent.rigidBody) + continue; + + if (const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); MOTION_STATE) + { + SHVec3 renderPosition = rigidBodyComponent.IsInterpolating() + ? MOTION_STATE.InterpolatePositions(FACTOR) + : MOTION_STATE.position; + + /* + * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. + */ + + transformComponent->SetWorldPosition(renderPosition); + // TODO: SetOrientation + } + } // Collision & Trigger messages if (scriptingSystem != nullptr) scriptingSystem->ExecuteCollisionFunctions(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsSystem::PhysicsPostUpdate::syncTransforms(SHRigidBodyComponent* rbComponent) const noexcept - { - - } - } diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index a0f348f4..eda69161 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -36,27 +36,27 @@ namespace SHADE auto* physicsSystem = reinterpret_cast(GetSystem()); // Get all physics objects & sync transforms - for (auto& physicsObject : physicsSystem->physicsObjectManager.GetPhysicsObjects() | std::views::values) - syncTransforms(&physicsObject); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsSystem::PhysicsPreUpdate::syncTransforms(SHPhysicsObject* physicsObject) const noexcept - { - const EntityID EID = physicsObject->entityID; - - // Get relevant components: Transform, Rigidbody & Collider - const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(EID); - - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(EID); - auto* colliderComponent = SHComponentManager::GetComponent_s(EID); - - if (TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged()) + for (auto& [entityID, physicsObject] : physicsSystem->physicsObjectManager.GetPhysicsObjects()) { - // Sync the objects transforms + const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); + + // We assume that all engine components and physics object components have been successfully linked + + if (TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged()) + { + // Sync the objects transforms + const SHVec3 WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + + if (physicsObject.rigidBody) + { + SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); + + motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); + // TODO: Force Orientation + } + } + + // TODO: Sync Collider Transform with World Transform } } } diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp index 77da8706..6ae53b31 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp @@ -47,7 +47,11 @@ namespace SHADE int count = 0; while (accumulatedTime > FIXED_DT) { + if (scriptEngine) + scriptEngine->ExecuteFixedUpdates(); + if (physicsSystem->physicsWorld) + physicsSystem->physicsWorld->Step(static_cast(FIXED_DT)); accumulatedTime -= FIXED_DT; ++count; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 98a69087..b4ff6961 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -28,10 +28,11 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsSystem::SHPhysicsSystem() + SHPhysicsSystem::SHPhysicsSystem() noexcept : worldUpdated { false } , interpolationFactor { 0.0 } , fixedDT { DEFAULT_FIXED_STEP } + , physicsWorld { nullptr } { // Add more events here to register them @@ -45,6 +46,11 @@ namespace SHADE #endif } + SHPhysicsSystem::~SHPhysicsSystem() noexcept + { + delete physicsWorld; + } + /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -141,24 +147,66 @@ namespace SHADE SHEventHandle SHPhysicsSystem::onSceneInit(SHEventPtr onSceneInitEvent) { /* - * TODO: * If a world already exists, destroy it - * Recreate the world + * Recreate the world. * * If there is an editor and editor mode is already playing, link all entities with the world immediately. */ + // Destroy an existing world if there is one. + //! This should almost never happen. + if (physicsWorld) + { + // Remove all references of physics objects from the world + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + { + if (PHYSICS_OBJECT.rigidBody) + physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); + } + + delete physicsWorld; + physicsWorld = nullptr; + } + + // 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(); + if (EDITOR && EDITOR->editorState == SHEditor::State::PLAY) + { + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + { + if (PHYSICS_OBJECT.rigidBody) + physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); + } + } + + #endif + return onSceneInitEvent.get()->handle; } SHEventHandle SHPhysicsSystem::onSceneExit(SHEventPtr onSceneExitEvent) { /* - * TODO: * Destroy the physics world. * Destroy all physics objects. */ + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + { + if (PHYSICS_OBJECT.rigidBody) + physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); + } + + delete physicsWorld; + physicsWorld = nullptr; + return onSceneExitEvent.get()->handle; } @@ -181,8 +229,17 @@ namespace SHADE // Link engine components with physics object component if (IS_RIGID_BODY) + { physicsObjectManager.AddRigidBody(EID); + if (physicsWorld) + { + auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; + physicsWorld->AddRigidBody(rigidBody); + } + } + + if (IS_COLLIDER) physicsObjectManager.AddCollider(EID); } @@ -209,7 +266,16 @@ namespace SHADE // Link engine components with physics object component if (IS_RIGID_BODY) + { + if (physicsWorld) + { + auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; + physicsWorld->RemoveRigidBody(rigidBody); + } + physicsObjectManager.RemoveRigidBody(EID); + } + if (IS_COLLIDER) physicsObjectManager.RemoveCollider(EID); @@ -222,10 +288,15 @@ namespace SHADE SHEventHandle SHPhysicsSystem::onEditorPlay(SHEventPtr onEditorPlayEvent) { - /* - * TODO: - * Link all entities with the world. - */ + // Add all physics components to the physics world + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + { + // Add rigid body if it exists + if (PHYSICS_OBJECT.rigidBody) + physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); + + // TODO: Add Collider if it exists + } return onEditorPlayEvent.get()->handle; } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index 1562241f..7d7dece5 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -16,6 +16,7 @@ #include "ECS_Base/System/SHFixedSystemRoutine.h" #include "Events/SHEvent.h" +#include "Physics/Dynamics/SHPhysicsWorld.h" #include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h" #include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" @@ -34,7 +35,8 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHPhysicsSystem(); + SHPhysicsSystem () noexcept; + ~SHPhysicsSystem() noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -75,9 +77,6 @@ namespace SHADE public: PhysicsPreUpdate(); void Execute(double dt) noexcept override; - - private: - void syncTransforms(SHPhysicsObject* physicsObject) const noexcept; }; /** @@ -103,9 +102,6 @@ namespace SHADE public: PhysicsPostUpdate(); void Execute(double dt) noexcept override; - - private: - void syncTransforms(SHRigidBodyComponent* rbComponent) const noexcept; }; private: @@ -136,6 +132,8 @@ namespace SHADE // Sub-systems / managers + SHPhysicsWorld* physicsWorld; + SHPhysicsObjectManager physicsObjectManager; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index 0664f367..ed190cc9 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -49,8 +49,9 @@ namespace SHADE /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo() noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; - [[nodiscard]] static double GetFixedDT () noexcept; + [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; + [[nodiscard]] static double GetFixedDT () noexcept; + [[nodiscard]] static int GetFixedUpdateRate () noexcept; }; } -- 2.40.1 From 74e50e10bdc5c7c203b96238c31617e6fdeb87aa Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 9 Dec 2022 01:15:43 +0800 Subject: [PATCH 06/84] Refactored the colliders? This took me 4 days omg --- SHADE_Application/src/Scenes/SBMainScene.cpp | 2 +- SHADE_Application/src/Scenes/SBTestScene.cpp | 30 +- .../Inspector/SHEditorComponentView.hpp | 34 +- .../Inspector/SHEditorInspector.cpp | 2 +- SHADE_Engine/src/Math/Geometry/SHSphere.cpp | 44 --- SHADE_Engine/src/Math/Geometry/SHSphere.h | 119 ++++-- .../CollisionShapes/SHCollisionShape.cpp | 191 +++++++++ .../CollisionShapes}/SHCollisionShape.h | 83 ++-- .../SHCollisionShapeFactory.cpp | 77 ++++ .../CollisionShapes/SHCollisionShapeFactory.h | 86 ++++ .../CollisionShapes/SHCollisionShapeID.h | 101 +++++ .../CollisionShapes/SHCollisionShapeID.hpp | 66 ++++ .../SHSphereCollisionShape.cpp | 183 +++++++++ .../CollisionShapes/SHSphereCollisionShape.h | 123 ++++++ .../src/Physics/Collision/SHCollider.cpp | 327 ++++++++++++++++ .../src/Physics/Collision/SHCollider.h | 170 ++++++++ .../src/Physics/Collision/SHCollisionInfo.cpp | 11 +- .../src/Physics/Collision/SHCollisionInfo.h | 2 +- .../SHPhysicsMaterial.cpp | 0 .../SHPhysicsMaterial.h | 0 .../src/Physics/Dynamics/SHMotionState.cpp | 2 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 27 +- .../src/Physics/Dynamics/SHPhysicsWorld.h | 20 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 13 + .../src/Physics/Dynamics/SHRigidBody.h | 13 +- .../PhysicsObject/SHPhysicsObject.cpp | 89 ++++- .../Interface/PhysicsObject/SHPhysicsObject.h | 53 ++- .../PhysicsObject/SHPhysicsObjectManager.cpp | 110 +++--- .../PhysicsObject/SHPhysicsObjectManager.h | 45 +-- .../Physics/Interface/SHColliderComponent.cpp | 54 +-- .../Physics/Interface/SHColliderComponent.h | 38 +- .../Physics/Interface/SHCollisionShape.cpp | 368 ------------------ .../SHRigidBodyComponent.cpp | 8 - .../SHRigidBodyComponent.h | 7 +- SHADE_Engine/src/Physics/SHPhysicsEvents.h | 2 +- .../Routines/SHPhysicsPostUpdateRoutine.cpp | 23 +- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 33 +- .../src/Physics/System/SHPhysicsSystem.cpp | 97 +++-- .../src/Physics/System/SHPhysicsSystem.h | 2 +- .../src/Serialization/SHSerialization.cpp | 2 +- .../src/Serialization/SHYAMLConverters.h | 34 +- SHADE_Managed/src/Components/Collider.cxx | 49 ++- SHADE_Managed/src/Components/Collider.h++ | 6 +- SHADE_Managed/src/Components/RigidBody.hxx | 2 +- SHADE_Managed/src/Engine/ECS.cxx | 2 +- 45 files changed, 1934 insertions(+), 816 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp rename SHADE_Engine/src/Physics/{Interface => Collision/CollisionShapes}/SHCollisionShape.h (75%) create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h create mode 100644 SHADE_Engine/src/Physics/Collision/SHCollider.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/SHCollider.h rename SHADE_Engine/src/Physics/{Interface => Collision}/SHPhysicsMaterial.cpp (100%) rename SHADE_Engine/src/Physics/{Interface => Collision}/SHPhysicsMaterial.h (100%) delete mode 100644 SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp rename SHADE_Engine/src/Physics/Interface/{RigidBodyComponent => }/SHRigidBodyComponent.cpp (98%) rename SHADE_Engine/src/Physics/Interface/{RigidBodyComponent => }/SHRigidBodyComponent.h (96%) diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp index 6c875518..dd713980 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -11,7 +11,7 @@ #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 9e3fa8ab..a300e6b9 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -10,7 +10,7 @@ #include "Scripting/SHScriptEngine.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" @@ -92,7 +92,7 @@ namespace Sandbox floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC); - floorCollider.AddBoundingBox(); + //floorCollider.AddBoundingBox(); // Create blank entity with a script //testObj = SHADE::SHEntityManager::CreateEntity(); @@ -113,9 +113,9 @@ namespace Sandbox racoonTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); racoonTransform.SetWorldPosition({ -3.0f, -2.0f, -5.0f }); - racoonCollider.AddBoundingBox(); - racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f)); - racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); + //racoonCollider.AddBoundingBox(); + //racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f)); + //racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); auto racoonItemLocation = SHEntityManager::CreateEntity(); auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s(racoonItemLocation); @@ -138,15 +138,15 @@ namespace Sandbox itemTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); itemTransform.SetWorldPosition({ 0.0f, -2.0f, -5.0f }); - itemCollider.AddBoundingBox(); - itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f)); - itemCollider.GetCollisionShape(1).SetIsTrigger(true); + //itemCollider.AddBoundingBox(); + //itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f)); + //itemCollider.GetCollisionShape(1).SetIsTrigger(true); - itemCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); - itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); + //itemCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); + //itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); - itemCollider.GetCollisionShape(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); - itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f)); + //itemCollider.GetCollisionShape(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); + //itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f)); itemRigidBody.SetInterpolate(false); itemRigidBody.SetFreezeRotationX(true); @@ -167,9 +167,9 @@ namespace Sandbox AITransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); AITransform.SetWorldPosition({ -8.0f, -2.0f, 2.5f }); - AICollider.AddBoundingBox(); - AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); - AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); + //AICollider.AddBoundingBox(); + //AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); + //AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); AIRigidBody.SetInterpolate(false); AIRigidBody.SetFreezeRotationX(true); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 71d607f5..774697f1 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -322,37 +322,37 @@ namespace SHADE { DrawContextMenu(component); - auto& colliders = component->GetCollisionShapes(); - int const size = static_cast(colliders.size()); - ImGui::BeginChild("Collision Shapes", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true); + auto* colliders = component->GetCollisionShapes(); + int const size = colliders ? static_cast(colliders->size()) : 0; + ImGui::BeginChild("Collision Shapes", { 0.0f, colliders->empty() ? 1.0f : 250.0f }, true); std::optional colliderToDelete{ std::nullopt }; for (int i{}; i < size; ++i) { ImGui::PushID(i); - SHCollisionShape* collider = &component->GetCollisionShape(i); + SHCollisionShape* collider = component->GetCollisionShape(i); auto cursorPos = ImGui::GetCursorPos(); //collider->IsTrigger if (collider->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(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 }); + // + //const auto* BOX = reinterpret_cast(collider->GetShape()); + //SHEditorWidgets::DragVec3 + //( + // "Half Extents", { "X", "Y", "Z" }, + // [BOX] { return BOX->GetRelativeExtents(); }, + // [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } else if (collider->GetType() == SHCollisionShape::Type::SPHERE) { SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - const auto* SPHERE = reinterpret_cast(collider->GetShape()); + auto* SPHERE = reinterpret_cast(collider); SHEditorWidgets::DragFloat ( "Radius", [SPHERE] { return SPHERE->GetRelativeRadius(); }, - [collider](float const& value) { collider->SetBoundingSphere(value); }); + [SPHERE](float const& value) { SPHERE->SetRelativeRadius(value); }); } else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) { @@ -393,7 +393,7 @@ namespace SHADE } if (colliderToDelete.has_value()) { - component->RemoveCollider(colliderToDelete.value()); + component->GetCollider()->RemoveCollisionShape(colliderToDelete.value()); } ImGui::EndChild(); @@ -401,11 +401,11 @@ namespace SHADE { if (ImGui::Selectable("Box Collider")) { - component->AddBoundingBox(); + //component->AddBoundingBox(); } if (ImGui::Selectable("Sphere Collider")) { - component->AddBoundingSphere(); + component->GetCollider()->AddSphereCollisionShape(1.0f); } ImGui::EndMenu(); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index f0d3e3e5..83647da7 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -14,7 +14,7 @@ #include "Scripting/SHScriptEngine.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" #include "Camera/SHCameraComponent.h" #include "Camera/SHCameraArmComponent.h" diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp index 54935251..7dca00c0 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp @@ -25,13 +25,11 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHSphere::SHSphere() noexcept - : RelativeRadius { 1.0f } { type = Type::SPHERE; } SHSphere::SHSphere(const SHVec3& center, float radius) noexcept - : RelativeRadius { 1.0f } { type = Type::SPHERE; @@ -48,7 +46,6 @@ namespace SHADE Center = rhs.Center; Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; } SHSphere::SHSphere(SHSphere&& rhs) noexcept @@ -57,7 +54,6 @@ namespace SHADE Center = rhs.Center; Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; } /*-----------------------------------------------------------------------------------*/ @@ -74,7 +70,6 @@ namespace SHADE { Center = rhs.Center; Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; } return *this; @@ -90,50 +85,11 @@ namespace SHADE { Center = rhs.Center; Radius = rhs.Radius; - RelativeRadius = rhs.RelativeRadius; } return *this; } - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHVec3 SHSphere::GetCenter() const noexcept - { - return Center; - } - - float SHSphere::GetWorldRadius() const noexcept - { - return Radius; - } - - float SHSphere::GetRelativeRadius() const noexcept - { - return RelativeRadius; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHSphere::SetCenter(const SHVec3& center) noexcept - { - Center = center; - } - - void SHSphere::SetWorldRadius(float newWorldRadius) noexcept - { - Radius = newWorldRadius; - } - - void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept - { - RelativeRadius = newRelativeRadius; - } - /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.h b/SHADE_Engine/src/Math/Geometry/SHSphere.h index e056f21a..91771a21 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.h +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.h @@ -23,7 +23,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ class SH_API SHSphere : public SHShape, - private DirectX::BoundingSphere + public DirectX::BoundingSphere { public: /*---------------------------------------------------------------------------------*/ @@ -32,8 +32,8 @@ namespace SHADE SHSphere () noexcept; SHSphere (const SHVec3& center, float radius) noexcept; - SHSphere (const SHSphere& rhs) noexcept; - SHSphere (SHSphere&& rhs) noexcept; + SHSphere (const SHSphere& rhs) noexcept; + SHSphere (SHSphere&& rhs) noexcept; ~SHSphere () override = default; @@ -44,49 +44,100 @@ namespace SHADE SHSphere& operator= (const SHSphere& rhs) noexcept; SHSphere& operator= (SHSphere&& rhs) noexcept; - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] float GetWorldRadius () const noexcept; - [[nodiscard]] float GetRelativeRadius () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetCenter (const SHVec3& center) noexcept; - void SetWorldRadius (float newWorldRadius) noexcept; - void SetRelativeRadius (float newRelativeRadius) noexcept; - /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Checks if a point is inside the sphere. + * @param point + * The point to check. + * @return + * True if the point is inside the sphere. + */ [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override; - [[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept; - [[nodiscard]] float Volume () const noexcept; - [[nodiscard]] float SurfaceArea () const noexcept; + /** + * @brief + * Casts a ray against the sphere. + * @param ray + * The ray to cast. + * @return + * The result of the raycast.
+ * 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 sphere is contained by this sphere. + * @param rhs + * The sphere to check. + * @return + * True if the other sphere is completely contained by this sphere. + */ + [[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept; + + /** + * @brief + * Calculates the volume of the sphere. + */ + [[nodiscard]] float Volume () const noexcept; + + /** + * @brief + * Calculates the surface area of the sphere. + */ + [[nodiscard]] float SurfaceArea () const noexcept; /*---------------------------------------------------------------------------------*/ /* Static Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept; - [[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept; - [[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept; + /** + * @brief + * Combines two spheres to form a larger sphere. + * If one sphere is completely contained by the other, the result is the larger sphere. + * @return + * The combined sphere. + */ + [[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept; + + /** + * @brief + * Checks if two spheres are intersecting. + * @return + * True if they are intersecting. + */ + [[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept; + + /** + * @brief + * Builds a single sphere from multiple spheres. + * @param spheres + * The set of spheres to build from. + * @param numSpheres + * The number of spheres in the set to build from. + * @return + * A sphere that contains all the spheres in the set. + */ + [[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept; + + /** + * @brief + * Builds a sphere from a set of vertices. + * @param vertices + * The vertices to build a sphere 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 + * A sphere that contains all the vertices in the set. + */ [[nodiscard]] static SHSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - float RelativeRadius; - }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp new file mode 100644 index 00000000..845634fe --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -0,0 +1,191 @@ +/**************************************************************************************** + * \file SHCollider.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Collider. + * + * \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 + +// Primary Header +#include "SHCollisionShape.h" + +// Project Headers +#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Reflection/SHReflectionMetadata.h" +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionShape::SHCollisionShape(SHCollisionShapeID id, Type colliderType) + : id { id } + , flags { 0 } + , collisionTag { SHCollisionTagMatrix::GetTag(0) } + { + flags |= 1U << SHUtilities::ConvertEnum(colliderType); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHCollisionShape::GetFriction() const noexcept + { + return material.GetFriction(); + } + + float SHCollisionShape::GetBounciness() const noexcept + { + return material.GetBounciness(); + } + + float SHCollisionShape::GetDensity() const noexcept + { + return material.GetDensity(); + } + + const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept + { + return material; + } + + const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept + { + return positionOffset; + } + + const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept + { + return rotationOffset; + } + + SHCollisionShape::Type SHCollisionShape::GetType() const noexcept + { + for (int i = 0; i < SHUtilities::ConvertEnum(Type::COUNT); ++i) + { + const uint8_t FLAG_VALUE = 1U << SHUtilities::ConvertEnum(static_cast(i)); + + if (flags & FLAG_VALUE) + return static_cast(i); + } + + return Type::INVALID; + } + + bool SHCollisionShape::IsTrigger() const noexcept + { + static constexpr int FLAG_POS = 3; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + return flags & FLAG_VALUE; + } + + bool SHCollisionShape::IsColliding() const noexcept + { + static constexpr int FLAG_POS = 4; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + return flags & FLAG_VALUE; + } + + bool SHCollisionShape::GetDebugDrawState() const noexcept + { + static constexpr int FLAG_POS = 6; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + return flags & FLAG_VALUE; + } + + const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept + { + return *collisionTag; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionShape::SetFriction(float friction) noexcept + { + material.SetFriction(friction); + } + + void SHCollisionShape::SetBounciness(float bounciness) noexcept + { + material.SetBounciness(bounciness); + } + + void SHCollisionShape::SetDensity(float density) noexcept + { + material.SetDensity(density); + } + + void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept + { + material = newMaterial; + } + + void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept + { + positionOffset = posOffset; + } + + void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept + { + rotationOffset = rotOffset; + } + + void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept + { + static constexpr int FLAG_POS = 3; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + isTrigger ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; + } + + void SHCollisionShape::SetDebugDrawState(bool isDebugDrawing) noexcept + { + static constexpr int FLAG_POS = 6; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + isDebugDrawing ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; + } + + void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept + { + collisionTag = newCollisionTag; + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + +} // namespace SHADE + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::enumeration("Collider Type") + ( + value("Box", SHCollisionShape::Type::BOX), + value("Sphere", SHCollisionShape::Type::SPHERE) + // TODO(Diren): Add More Shapes + ); + + registration::class_("Collider") + .property("IsTrigger" , &SHCollisionShape::IsTrigger , &SHCollisionShape::SetIsTrigger ) + .property("Friction" , &SHCollisionShape::GetFriction , &SHCollisionShape::SetFriction ) + .property("Bounciness" , &SHCollisionShape::GetBounciness , &SHCollisionShape::SetBounciness ) + .property("Density" , &SHCollisionShape::GetDensity , &SHCollisionShape::SetDensity ) + .property("Position Offset" , &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset) + .property("Rotation Offset" , &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true)); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h similarity index 75% rename from SHADE_Engine/src/Physics/Interface/SHCollisionShape.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 597814a6..420c0d6e 100644 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollider.h + * \file SHCollisionShape.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Collider. + * \brief Interface for a Base CollisionShape Class. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -16,8 +16,9 @@ #include "ECS_Base/Entity/SHEntity.h" #include "Math/Geometry/SHShape.h" #include "Math/SHQuaternion.h" -#include "SHPhysicsMaterial.h" #include "Physics/Collision/SHCollisionTags.h" +#include "Physics/Collision/SHPhysicsMaterial.h" +#include "SHCollisionShapeID.h" namespace SHADE { @@ -34,7 +35,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHColliderComponent; - friend class SHPhysicsObject; + friend class SHCollisionShapeFactory; public: /*---------------------------------------------------------------------------------*/ @@ -46,87 +47,87 @@ namespace SHADE BOX , SPHERE , CAPSULE + + , COUNT + , INVALID = -1 }; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionShape (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT); + SHCollisionShape (SHCollisionShapeID id, Type colliderType = Type::BOX); - SHCollisionShape (const SHCollisionShape& rhs) noexcept; - SHCollisionShape (SHCollisionShape&& rhs) noexcept; - ~SHCollisionShape () noexcept; + SHCollisionShape (const SHCollisionShape& rhs) noexcept = default; + SHCollisionShape (SHCollisionShape&& rhs) noexcept = default; + virtual ~SHCollisionShape () noexcept = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept; - SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept; + SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept = default; + SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept = default; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool HasChanged () const noexcept; - - [[nodiscard]] bool IsTrigger () const noexcept; - - [[nodiscard]] Type GetType () const noexcept; - - [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; + // Material Properties + // TODO: Remove individual setters once instanced materials are supported [[nodiscard]] float GetFriction () const noexcept; [[nodiscard]] float GetBounciness () const noexcept; [[nodiscard]] float GetDensity () const noexcept; [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; + // Offsets + [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; - [[nodiscard]] const SHShape* GetShape () const noexcept; + // Flags + + [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] bool IsTrigger () const noexcept; + [[nodiscard]] bool IsColliding () const noexcept; + [[nodiscard]] bool GetDebugDrawState () const noexcept; + + + [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetBoundingBox (const SHVec3& halfExtents); - void SetBoundingSphere (float radius); - - void SetIsTrigger (bool isTrigger) noexcept; - void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; void SetFriction (float friction) noexcept; void SetBounciness (float bounciness) noexcept; void SetDensity (float density) noexcept; void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; - void SetPositionOffset (const SHVec3& posOffset) noexcept; - void SetRotationOffset (const SHVec3& rotOffset) noexcept; + void SetPositionOffset (const SHVec3& posOffset) noexcept; + void SetRotationOffset (const SHVec3& rotOffset) noexcept; - private: + // Flags + void SetIsTrigger (bool isTrigger) noexcept; + void SetDebugDrawState (bool isDebugDrawing) noexcept; + + void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; + + protected: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; - EntityID entityID; // The entity this collider belongs to - bool isTrigger; - bool dirty; + SHCollisionShapeID id; - SHShape* shape; - SHPhysicsMaterial material; + SHPhysicsMaterial material; - SHVec3 positionOffset; - SHVec3 rotationOffset; + SHVec3 positionOffset; + SHVec3 rotationOffset; - SHCollisionTag* collisionTag; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - void CopyShape(const SHShape* rhs); + uint8_t flags; // 0 debugDraw wasColliding isColliding trigger capsule sphere box + SHCollisionTag* collisionTag; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp new file mode 100644 index 00000000..293d5c2a --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp @@ -0,0 +1,77 @@ +/**************************************************************************************** + * \file SHCollisionShapeFactory.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Collison Shape Factory Class. + * + * \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 + +// Primary Header +#include "SHCollisionShapeFactory.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionShapeFactory::~SHCollisionShapeFactory() noexcept + { + // Free all shapes in each container + for (auto* sphereCollisionShape : spheres | std::views::values) + DestroyShape(sphereCollisionShape); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSphereCollisionShape* SHCollisionShapeFactory::CreateSphere(SHCollisionShapeID id, const SHSphereCreateInfo& createInfo) + { + const auto RESULT = spheres.emplace(id, new SHSphereCollisionShape{ id }); + if (RESULT.second) + { + SHSphereCollisionShape* sphere = RESULT.first->second; + + sphere->Center = createInfo.Center; + sphere->Radius = createInfo.Radius; + sphere->relativeRadius = createInfo.RelativeRadius; + sphere->scale = createInfo.Scale; + + return sphere; + } + + return spheres.find(id)->second; + } + + void SHCollisionShapeFactory::DestroyShape(SHCollisionShape* shape) + { + switch (shape->GetType()) + { + case SHCollisionShape::Type::BOX: + { + break; + } + case SHCollisionShape::Type::SPHERE: + { + SHSphereCollisionShape* sphere = spheres.find(shape->id)->second; + + delete sphere; + sphere = nullptr; + + spheres.erase(shape->id); + + break; + } + case SHCollisionShape::Type::CAPSULE: + { + break; + } + default: break; + } + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h new file mode 100644 index 00000000..f5820317 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h @@ -0,0 +1,86 @@ +/**************************************************************************************** + * \file SHCollisionShapeFactory.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collison Shape Factory Class. + * + * \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 + +// Project Header +#include "SHSphereCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a class for Creating and Destroying Collision Shapes.
+ * All memory for collision shapes are handled in this factory class.
+ * TODO: Support instancing of shapes + */ + class SH_API SHCollisionShapeFactory final + { + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShapeFactory () noexcept = default; + ~SHCollisionShapeFactory () noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Creates a sphere collision shape. + * @param id + * The ID of the shape. + * @param createInfo + * The info to create the sphere with. + * @return + * A newly sphere collision shape. + */ + SHSphereCollisionShape* CreateSphere (SHCollisionShapeID id, const SHSphereCreateInfo& createInfo); + + /** + * @brief + * Destroys a collision shape. + * * @param eid + * The entity the shape belongs to. + * @param shapeID + * The ID of the shape. + * @param shape + * The shape to destroy. + */ + void DestroyShape (SHCollisionShape* shape); + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + // We use unordered maps for fast lookup when deleting. + // 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; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Spheres spheres; + // TODO: Add boxes, capsules and hulls + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h new file mode 100644 index 00000000..a0f78177 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h @@ -0,0 +1,101 @@ +/**************************************************************************************** + * \file SHCollisionShapeKey.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collison Shape ID Class and it's hashing function + * + * \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 "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + struct SHCollisionShapeIDHash; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates an identifier for a collision shape. + */ + union SHCollisionShapeID + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend struct SHCollisionShapeIDHash; + + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShapeID (EntityID eid, uint32_t shapeID) noexcept; + SHCollisionShapeID (const SHCollisionShapeID& rhs) noexcept; + SHCollisionShapeID (SHCollisionShapeID&& rhs) noexcept; + + ~SHCollisionShapeID () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShapeID& operator=(const SHCollisionShapeID& rhs) noexcept; + SHCollisionShapeID& operator=(SHCollisionShapeID&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + bool operator==(const SHCollisionShapeID& rhs) const; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct IDs + { + public: + EntityID entityID = MAX_EID; + uint32_t shapeID = std::numeric_limits::max(); + }; + + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + uint64_t value; + IDs ids; + }; + + /** + * @brief + * Encapsulates a functor to hash a CollisionShapeKey + */ + struct SHCollisionShapeIDHash + { + public: + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + std::size_t operator()(const SHCollisionShapeID& id) const; + }; + +} // namespace SHADE + +#include "SHCollisionShapeID.hpp" diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp new file mode 100644 index 00000000..234b2f6f --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp @@ -0,0 +1,66 @@ +/**************************************************************************************** + * \file SHCollisionShapeKey.hpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Inlined Implementations for a Collison Shape ID Class and + * it's hashing function. + * + * \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 "SHCollisionShapeID.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + inline SHCollisionShapeID::SHCollisionShapeID(EntityID eid, uint32_t shapeID) noexcept + : ids { eid, shapeID } + {} + + inline SHCollisionShapeID::SHCollisionShapeID(const SHCollisionShapeID& rhs) noexcept + : ids { rhs.ids.entityID, rhs.ids.shapeID } + {} + + inline SHCollisionShapeID::SHCollisionShapeID(SHCollisionShapeID&& rhs) noexcept + : ids { rhs.ids.entityID, rhs.ids.shapeID } + {} + + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + inline SHCollisionShapeID& SHCollisionShapeID::operator=(const SHCollisionShapeID& rhs) noexcept + { + if (this == &rhs) + return *this; + + value = rhs.value; + + return *this; + } + + inline SHCollisionShapeID& SHCollisionShapeID::operator=(SHCollisionShapeID&& rhs) noexcept + { + value = rhs.value; + + return *this; + } + + inline bool SHCollisionShapeID::operator==(const SHCollisionShapeID& rhs) const + { + return value == rhs.value; + } + + inline std::size_t SHCollisionShapeIDHash::operator()(const SHCollisionShapeID& id) const + { + return std::hash()(id.value); + } +} diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp new file mode 100644 index 00000000..3f79b381 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -0,0 +1,183 @@ +/**************************************************************************************** + * \file SHSphereCollisionShape.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Sphere 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 + +// Primary Header +#include "SHSphereCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSphereCollisionShape::SHSphereCollisionShape(SHCollisionShapeID id) noexcept + : SHCollisionShape (id, SHCollisionShape::Type::SPHERE) + , SHSphere () + , relativeRadius { 1.0f } + , scale { 1.0f } + {} + + SHSphereCollisionShape::SHSphereCollisionShape(const SHSphereCollisionShape& rhs) noexcept + : SHCollisionShape (rhs.id, SHCollisionShape::Type::SPHERE) + , SHSphere (rhs.Center, rhs.Radius) + , relativeRadius { rhs.relativeRadius } + , scale { rhs.scale } + { + + material = rhs.material; + positionOffset = rhs.positionOffset; + 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; + } + + SHSphereCollisionShape::SHSphereCollisionShape(SHSphereCollisionShape&& rhs) noexcept + : SHCollisionShape (rhs.id, SHCollisionShape::Type::SPHERE) + , SHSphere (rhs.Center, rhs.Radius) + , relativeRadius { rhs.relativeRadius } + , scale { rhs.scale } + { + + material = rhs.material; + positionOffset = rhs.positionOffset; + 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 */ + /*-----------------------------------------------------------------------------------*/ + + SHSphereCollisionShape& SHSphereCollisionShape::operator=(const SHSphereCollisionShape& rhs) noexcept + { + if (this == &rhs) + return *this; + + // Collision Shape Properties + + id = rhs.id; + material = rhs.material; + positionOffset = rhs.positionOffset; + 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; + + // Sphere Properties + + Center = rhs.Center; + Radius = rhs.Radius; + + // Local Properties + + relativeRadius = rhs.relativeRadius; + scale = rhs.scale; + + return *this; + } + + SHSphereCollisionShape& SHSphereCollisionShape::operator=(SHSphereCollisionShape&& rhs) noexcept + { + // Collision Shape Properties + + id = rhs.id; + material = rhs.material; + positionOffset = rhs.positionOffset; + 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; + + // Sphere Properties + + Center = rhs.Center; + Radius = rhs.Radius; + + // Local Properties + + relativeRadius = rhs.relativeRadius; + scale = rhs.scale; + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHVec3& SHSphereCollisionShape::GetCenter() const noexcept + { + return Center; + } + + float SHSphereCollisionShape::GetWorldRadius() const noexcept + { + return Radius; + } + + float SHSphereCollisionShape::GetRelativeRadius() const noexcept + { + return relativeRadius; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHSphereCollisionShape::SetCenter(const SHVec3& newCenter) noexcept + { + Center = newCenter; + } + + void SHSphereCollisionShape::SetWorldRadius(float newWorldRadius) noexcept + { + Radius = newWorldRadius; + + // Recompute Relative radius + relativeRadius = 2.0f * Radius / scale; + } + + void SHSphereCollisionShape::SetRelativeRadius(float newRelativeRadius) noexcept + { + relativeRadius = newRelativeRadius; + + // Recompute world radius + Radius = relativeRadius * scale * 0.5f; + } + + void SHSphereCollisionShape::SetScale(float maxScale) noexcept + { + scale = std::fabs(maxScale); + + // Recompute world radius + Radius = relativeRadius * scale * 0.5f; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHSphereCollisionShape::TestPoint(const SHVec3& point) const noexcept + { + return SHSphere::TestPoint(point); + } + + SHRaycastResult SHSphereCollisionShape::Raycast(const SHRay& ray) const noexcept + { + return SHSphere::Raycast(ray); + } + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h new file mode 100644 index 00000000..0a8c0321 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -0,0 +1,123 @@ +/**************************************************************************************** + * \file SHSphereCollisionShape.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Sphere 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/SHSphere.h" +#include "SHCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates the information to create a sphere. + */ + struct SHSphereCreateInfo + { + public: + SHVec3 Center = SHVec3::Zero; + float Radius = 1.0f; + float RelativeRadius = 1.0f; + float Scale = 1.0f; + }; + + /** + * @brief + * Encapsulate a Sphere Collision Shape used for Physics Simulations. + */ + class SH_API SHSphereCollisionShape : public SHCollisionShape + , private SHSphere + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHCollider; + friend class SHCompositeCollider; + friend class SHCollisionShapeFactory; + + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHSphereCollisionShape (SHCollisionShapeID id) noexcept; + SHSphereCollisionShape (const SHSphereCollisionShape& rhs) noexcept; + SHSphereCollisionShape (SHSphereCollisionShape&& rhs) noexcept; + + ~SHSphereCollisionShape () override = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHSphereCollisionShape& operator= (const SHSphereCollisionShape& rhs) noexcept; + SHSphereCollisionShape& operator= (SHSphereCollisionShape&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const SHVec3& GetCenter () const noexcept; + [[nodiscard]] float GetWorldRadius () const noexcept; + [[nodiscard]] float GetRelativeRadius () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetCenter (const SHVec3& newCenter) noexcept; + void SetWorldRadius (float newWorldRadius) noexcept; + void SetRelativeRadius (float newRelativeRadius) noexcept; + void SetScale (float maxScale) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Tests if a point is inside the sphere. + * @param point + * The point to test. + * @return + * True if the point is inside the sphere. + */ + bool TestPoint (const SHVec3& point) const noexcept override; + + /** + * @brief + * Casts a ray against this sphere. + * @param ray + * The ray to cast. + * @return + * An object holding the results of the raycast.
+ * See the corresponding header for the contents of the object. + */ + SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + + // TODO: Compute Moment of Inertia + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + float relativeRadius; + float scale; // Intended to be passed in by the base collider. + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp new file mode 100644 index 00000000..e950c4fb --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -0,0 +1,327 @@ +/**************************************************************************************** + * \file SHCollider.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Base Collider Class. + * + * \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 + +// Primary Header +#include "SHCollider.h" + +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept + : entityID { eid } + , shapeIDCounter { 0 } + , rigidBody { nullptr } + , shapeFactory { nullptr } + , transform { worldTransform } + {} + + SHCollider::SHCollider(const SHCollider& rhs) noexcept + : entityID { rhs.entityID } + , shapeIDCounter { rhs.shapeIDCounter } + , rigidBody { rhs.rigidBody } + , shapeFactory { rhs.shapeFactory } + , transform { rhs.transform } + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) + return; + } + + copyShapes(rhs); + } + + SHCollider::SHCollider(SHCollider&& rhs) noexcept + : entityID { rhs.entityID } + , shapeIDCounter { rhs.shapeIDCounter } + , rigidBody { rhs.rigidBody } + , shapeFactory { rhs.shapeFactory } + , transform { rhs.transform } + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) + return; + } + + copyShapes(rhs); + } + + SHCollider::~SHCollider() noexcept + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add destroy collider!", entityID) + return; + } + + for (auto* shape : shapes) + shapeFactory->DestroyShape(shape); + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollider& SHCollider::operator=(const SHCollider& rhs) noexcept + { + if (this == &rhs) + return *this; + + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) + return *this; + } + + entityID = rhs.entityID; + rigidBody = rhs.rigidBody; + shapeFactory = rhs.shapeFactory; + transform = rhs.transform; + + copyShapes(rhs); + + return *this; + } + + SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) + return *this; + } + + entityID = rhs.entityID; + rigidBody = rhs.rigidBody; + shapeFactory = rhs.shapeFactory; + transform = rhs.transform; + + copyShapes(rhs); + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHTransform& SHCollider::GetTransform() const noexcept + { + return transform; + } + + const SHVec3& SHCollider::GetPosition() const noexcept + { + return transform.position; + } + + const SHQuaternion& SHCollider::GetOrientation() const noexcept + { + return transform.orientation; + } + + const SHVec3& SHCollider::GetScale() const noexcept + { + return transform.scale; + } + + const SHCollider::CollisionShapes& SHCollider::GetCollisionShapes() const noexcept + { + return shapes; + } + + SHCollisionShape* SHCollider::GetCollisionShape(int index) const + { + const int NUM_SHAPES = static_cast(shapes.size()); + + if (index < 0 || index >= NUM_SHAPES) + throw std::invalid_argument("Out-of-range index!"); + + return shapes[index]; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::SetRigidBody(SHRigidBody* rb) noexcept + { + rigidBody = rb; + } + + void SHCollider::SetTransform(const SHTransform& newTransform) noexcept + { + transform = newTransform; + } + + void SHCollider::SetPosition(const SHVec3& newPosition) noexcept + { + transform.position = newPosition; + } + + void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept + { + transform.orientation = newOrientation; + } + + void SHCollider::SetScale(const SHVec3& newScale) noexcept + { + transform.scale = newScale; + } + + void SHCollider::SetFactory(SHCollisionShapeFactory* factory) noexcept + { + shapeFactory = factory; + } + + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHMatrix& SHCollider::ComputeTransformTRS() noexcept + { + return transform.ComputeTRS(); + } + + int SHCollider::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add new shape!", entityID) + return -1; + } + + // Compute world radius + const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z })); + + // 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 SHSphereCreateInfo SPHERE_CREATE_INFO + { + .Center = SHVec3::Transform(posOffset, TRS) + , .Radius = relativeRadius * SPHERE_SCALE * 0.5f + , .RelativeRadius = relativeRadius + , .Scale = SPHERE_SCALE + }; + + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, shapeIDCounter }; + + SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + ++shapeIDCounter; + + // Set offsets + sphere->positionOffset = posOffset; + sphere->rotationOffset = rotOffset; + + shapes.emplace_back(sphere); + return static_cast(shapes.size()); + } + + void SHCollider::RemoveCollisionShape(int index) + { + if (!shapeFactory) + { + SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add remove shape!", entityID) + return; + } + + const int NUM_SHAPES = static_cast(shapes.size()); + + if (index < 0 || index >= NUM_SHAPES) + throw std::invalid_argument("Out-of-range index!"); + + auto shapeIter = shapes.begin(); + for (int i = 0; i < NUM_SHAPES; ++i, ++shapeIter) + { + if (i == index) + break; + } + + shapeFactory->DestroyShape(*shapeIter); + *shapeIter = nullptr; + + // Remove the shape from the container to prevent accessing a nullptr + shapeIter = shapes.erase(shapeIter); + + SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) + } + + void SHCollider::RecomputeShapes() const noexcept + { + + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::copyShapes(const SHCollider& rhsCollider) + { + shapeIDCounter = 0; + for (const auto* shape : rhsCollider.shapes) + { + copyShape(shape); + ++shapeIDCounter; + } + } + + void SHCollider::copyShape(const SHCollisionShape* rhsShape) + { + switch (rhsShape->GetType()) + { + case SHCollisionShape::Type::BOX: + { + break; + } + case SHCollisionShape::Type::SPHERE: + { + const SHSphereCollisionShape* RHS_SPHERE = dynamic_cast(rhsShape); + + const SHSphereCreateInfo SPHERE_CREATE_INFO + { + .Center = RHS_SPHERE->Center + , .Radius = RHS_SPHERE->Radius + , .RelativeRadius = RHS_SPHERE->relativeRadius + , .Scale = RHS_SPHERE->scale + }; + + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, shapeIDCounter }; + + SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + *sphere = *RHS_SPHERE; + + shapes.emplace_back(sphere); + + break; + } + case SHCollisionShape::Type::CAPSULE: + { + break; + } + default: break; + } + + ++shapeIDCounter; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h new file mode 100644 index 00000000..37d96caa --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -0,0 +1,170 @@ +/**************************************************************************************** + * \file SHCollider.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Base Collider Class. + * + * \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/Entity/SHEntity.h" +#include "Math/Transform/SHTransform.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHRigidBody; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Base class for a collider. + * There are only two collider types supported by SHADE Engine: Composite & Hull + */ + class SH_API SHCollider + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsWorld; + + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using CollisionShapes = std::vector; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Constructor for a collider. + * @param eid + * The entity this collider belongs to. + * @param worldTransform + * The world transform for the collider. Defaults to the identity transform. + * This is particularly important for composite colliders for offsets & relative sizes. + * @return + */ + SHCollider (EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; + SHCollider (const SHCollider& rhs) noexcept; + SHCollider (SHCollider&& rhs) noexcept; + ~SHCollider () noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollider& operator=(const SHCollider& rhs) noexcept; + SHCollider& operator=(SHCollider&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const SHTransform& GetTransform () const noexcept; + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + [[nodiscard]] const SHVec3& GetScale () const noexcept; + + [[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept; + [[nodiscard]] SHCollisionShape* GetCollisionShape (int index) const; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetRigidBody (SHRigidBody* rb) noexcept; + + void SetTransform (const SHTransform& newTransform) noexcept; + void SetPosition (const SHVec3& newPosition) noexcept; + void SetOrientation (const SHQuaternion& newOrientation) noexcept; + void SetScale (const SHVec3& newScale) noexcept; + + void SetFactory (SHCollisionShapeFactory* factory) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Computes the TRS for the collider's transform + * @return + * The computed TRS. + */ + const SHMatrix& ComputeTransformTRS() noexcept; + + /** + * @brief + * Adds a sphere collision shape. + * @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.
+ * 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 + * Removes a shape from the container. Removal reduces the size of the container. + * If removing all, perform removal from back to front. + * @param index + * The index of the shape to remove. + * @throws + * Invalid argument for out-of-range indices. + */ + void RemoveCollisionShape (int index); + + /** + * @brief + * Recomputes the transforms for all shapes in this composite collider. + */ + void RecomputeShapes () const noexcept; + + protected: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + EntityID entityID; + uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. + + SHRigidBody* rigidBody; + SHCollisionShapeFactory* shapeFactory; + + SHTransform transform; + + CollisionShapes shapes; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void copyShapes (const SHCollider& rhsCollider); + void copyShape (const SHCollisionShape* rhsShape); + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp index 43ad05ca..a28686e0 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp @@ -13,6 +13,11 @@ // Primary Header #include "SHCollisionInfo.h" +// Project Headers +#include "Physics/Collision/SHCollider.h" +#include "Physics/Interface/SHColliderComponent.h" + + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -77,12 +82,14 @@ namespace SHADE const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept { - return &SHComponentManager::GetComponent(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]); + const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_A]); + return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_A]); } const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept { - return &SHComponentManager::GetComponent(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]); + const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_B]); + return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_B]); } SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h index dfcf4f22..d2dad647 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h @@ -12,7 +12,7 @@ // Project Headers #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp b/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp rename to SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.cpp diff --git a/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h similarity index 100% rename from SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h rename to SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp index 2cca1c45..91b5a688 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp @@ -74,7 +74,7 @@ namespace SHADE void SHMotionState::ForcePosition(const SHVec3& newPosition) noexcept { - hasMoved = false; + hasMoved = true; prevPosition = newPosition; position = newPosition; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 7d6c7c5c..0d7434f6 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -40,7 +40,7 @@ namespace SHADE void SHPhysicsWorld::AddRigidBody(SHRigidBody* rigidBody) noexcept { - const bool INSERTED = rigidBodies.emplace(rigidBody->entityID, rigidBody).second; + const bool INSERTED = rigidBodies.emplace(rigidBody).second; if (!INSERTED) { SHLOG_WARNING_D("Attempting to add duplicate rigid body {} to the Physics World!", rigidBody->entityID) @@ -49,15 +49,34 @@ namespace SHADE void SHPhysicsWorld::RemoveRigidBody(SHRigidBody* rigidBody) noexcept { - rigidBodies.erase(rigidBody->entityID); + rigidBodies.erase(rigidBody); + + // Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep + } + + void SHPhysicsWorld::AddCollider(SHCollider* collider) noexcept + { + const bool INSERTED = colliders.emplace(collider).second; + if (!INSERTED) + { + SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID) + } + } + + void SHPhysicsWorld::RemoveCollider(SHCollider* collider) noexcept + { + colliders.erase(collider); + + // 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::Step(float dt) { - for (auto* rigidBody : rigidBodies | std::views::values) + for (auto* rigidBody : rigidBodies) integrateForces(*rigidBody, dt); - for (auto* rigidBody : rigidBodies | std::views::values) + for (auto* rigidBody : rigidBodies) integrateVelocities(*rigidBody, dt); } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index eb96a021..499230dd 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -10,12 +10,12 @@ #pragma once -#include +#include // Project Headers +#include "Physics/Collision/SHCollider.h" #include "SHRigidBody.h" -#include "Math/SHMath.h" -#include "SH_API.h" + namespace SHADE { @@ -66,8 +66,11 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void AddRigidBody (SHRigidBody* rigidBody) noexcept; - void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; + void AddRigidBody (SHRigidBody* rigidBody) noexcept; + void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; + + void AddCollider (SHCollider* collider) noexcept; + void RemoveCollider (SHCollider* collider) noexcept; void Step (float dt); @@ -76,7 +79,11 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using RigidBodies = std::unordered_map; + //! I realise using a set may be dangerous with pointers. An unordered_map may be better, but I don't need the entityIDs so... + + using Colliders = std::unordered_set; + using RigidBodies = std::unordered_set; + /*---------------------------------------------------------------------------------*/ /* Data Members */ @@ -84,6 +91,7 @@ namespace SHADE WorldSettings settings; + Colliders colliders; RigidBodies rigidBodies; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 8f99a8f5..e79a8c91 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -14,6 +14,7 @@ #include "SHRigidBody.h" // Project Headers +#include "Physics/Collision/SHCollider.h" #include "Tools/Logger/SHLogger.h" namespace SHADE @@ -24,6 +25,7 @@ namespace SHADE SHRigidBody::SHRigidBody(EntityID eid, Type type) noexcept : entityID { eid } + , collider { nullptr } , bodyType { type } , invMass { type == Type::DYNAMIC ? 1.0f : 0.0f } , linearDrag { 0.01f } @@ -40,6 +42,7 @@ namespace SHADE SHRigidBody::SHRigidBody(const SHRigidBody& rhs) noexcept : entityID { rhs.entityID } + , collider { nullptr } , bodyType { rhs.bodyType } , invMass { rhs.invMass } , linearDrag { rhs.linearDrag } @@ -52,6 +55,7 @@ namespace SHADE SHRigidBody::SHRigidBody(SHRigidBody&& rhs) noexcept : entityID { rhs.entityID } + , collider { nullptr } , bodyType { rhs.bodyType } , invMass { rhs.invMass } , linearDrag { rhs.linearDrag } @@ -73,6 +77,8 @@ namespace SHADE return *this; entityID = rhs.entityID; + // Deep copy the collider + *collider = *rhs.collider; bodyType = rhs.bodyType; invMass = rhs.invMass; linearDrag = rhs.linearDrag; @@ -91,6 +97,8 @@ namespace SHADE SHRigidBody& SHRigidBody::operator=(SHRigidBody&& rhs) noexcept { entityID = rhs.entityID; + // Deep copy the collider + *collider = *rhs.collider; bodyType = rhs.bodyType; invMass = rhs.invMass; linearDrag = rhs.linearDrag; @@ -223,6 +231,11 @@ namespace SHADE /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHRigidBody::SetCollider(SHCollider* c) noexcept + { + collider = c; + } + void SHRigidBody::SetType(Type newType) noexcept { if (newType == bodyType) diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index dbf2344f..1edf5cf6 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -11,12 +11,18 @@ #pragma once // Project Headers -#include "ECS_Base/SHECSMacros.h" +#include "ECS_Base/Entity/SHEntity.h" #include "Math/Vector/SHVec3.h" #include "SHMotionState.h" namespace SHADE { + /*-------------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-------------------------------------------------------------------------------------*/ + + class SHCollider; + /*-------------------------------------------------------------------------------------*/ /* Type Definitions */ /*-------------------------------------------------------------------------------------*/ @@ -96,6 +102,8 @@ namespace SHADE /* Setter Functions */ /*-----------------------------------------------------------------------------------*/ + void SetCollider (SHCollider* c) noexcept; + /** * @brief * Changing the type from non-Dynamic to Dynamic will set the default @@ -174,6 +182,7 @@ namespace SHADE // The entityID here is only meant for linking with the actual component in the engine. EntityID entityID; + SHCollider* collider; Type bodyType; @@ -187,7 +196,7 @@ namespace SHADE SHVec3 linearVelocity; SHVec3 angularVelocity; - // aZ aY aX pZ pY pX 0 0 0 0 0 autoMass enableGravity enableSleeping sleeping active + // aZ aY aX pZ pY pX 0 0 0 0 inIsland autoMass enableGravity enableSleeping sleeping active uint16_t flags; SHMotionState motionState; diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp index b6e5ac40..ee33016a 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -26,15 +26,13 @@ namespace SHADE SHPhysicsObject::SHPhysicsObject(const SHPhysicsObject& rhs) noexcept : entityID { rhs.entityID } { - // Perform a deep copy of the components - *rigidBody = *rhs.rigidBody; + deepCopyComponents(rhs.rigidBody, rhs.collider); } SHPhysicsObject::SHPhysicsObject(SHPhysicsObject&& rhs) noexcept : entityID { rhs.entityID } { - // Perform a deep copy of the components - *rigidBody = *rhs.rigidBody; + deepCopyComponents(rhs.rigidBody, rhs.collider); } SHPhysicsObject::~SHPhysicsObject() noexcept @@ -42,6 +40,10 @@ namespace SHADE entityID = MAX_EID; delete rigidBody; + rigidBody = nullptr; + + delete collider; + collider = nullptr; } /*-----------------------------------------------------------------------------------*/ @@ -53,20 +55,18 @@ namespace SHADE if (this == &rhs) return *this; - entityID = rhs.entityID; + entityID = rhs.entityID; - // Perform a deep copy of the components - *rigidBody = *rhs.rigidBody; + deepCopyComponents(rhs.rigidBody, rhs.collider); return *this; } SHPhysicsObject& SHPhysicsObject::operator=(SHPhysicsObject&& rhs) noexcept { - entityID = rhs.entityID; + entityID = rhs.entityID; - // Perform a deep copy of the components - *rigidBody = *rhs.rigidBody; + deepCopyComponents(rhs.rigidBody, rhs.collider); return *this; } @@ -77,7 +77,74 @@ namespace SHADE bool SHPhysicsObject::IsEmpty() const noexcept { - return rigidBody == nullptr; + return rigidBody == nullptr && collider == nullptr; + } + + SHRigidBody* SHPhysicsObject::CreateRigidBody(SHRigidBody::Type bodyType) + { + if (rigidBody) + { + SHLOG_INFO_D("Rigid body for Entity {} has already been created!", entityID) + return rigidBody; + } + + rigidBody = new SHRigidBody{ entityID, bodyType }; + + // Link with collider if it exists + if (collider) + collider->SetRigidBody(rigidBody); + + return rigidBody; + } + + void SHPhysicsObject::DestroyRigidBody() noexcept + { + delete rigidBody; + rigidBody = nullptr; + + // Unlink with collider + if (collider) + collider->SetRigidBody(nullptr); + } + + SHCollider* SHPhysicsObject::CreateCollider(const SHTransform& transform) + { + if (collider) + { + SHLOG_INFO_D("Collider for Entity {} has already been created!", entityID) + return collider; + } + + collider = new SHCollider{ entityID, transform }; + + // Link with rigidBody if it exists + if (rigidBody) + rigidBody->SetCollider(collider); + + return collider; + } + + void SHPhysicsObject::DestroyCollider() noexcept + { + delete collider; + collider = nullptr; + + // Unlink with rigid body + if (rigidBody) + rigidBody->SetCollider(nullptr); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsObject::deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCollider* rhsCollider) + { + if (rhsRigidBody) + rigidBody = new SHRigidBody{ *rhsRigidBody }; + + if (rhsCollider) + collider = new SHCollider { *rhsCollider }; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h index f297a6fb..2550543b 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h @@ -11,6 +11,7 @@ #pragma once // Project Headers +#include "Physics/Collision/SHCollider.h" #include "Physics/Dynamics/SHRigidBody.h" namespace SHADE @@ -32,6 +33,7 @@ namespace SHADE EntityID entityID = MAX_EID; SHRigidBody* rigidBody = nullptr; + SHCollider* collider = nullptr; /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -53,6 +55,55 @@ namespace SHADE /* Member Functions */ /*-----------------------------------------------------------------------------------*/ - bool IsEmpty() const noexcept; + /** + * @brief + * Checks if the physics object has a rigid body or a collider. + * @return + * True if the physics object has neither a rigid body nor a collider. + */ + [[nodiscard]] bool IsEmpty () const noexcept; + + /** + * @brief + * Creates a rigid body for this physics object. + * @param bodyType + * The rigid body's type. Can be modified after creation. + * @return + * Pointer to the rigid body that was created. The memory of this rigid body is managed + * by the physics object itself. + */ + SHRigidBody* CreateRigidBody (SHRigidBody::Type bodyType); + + /** + * @brief + * Destroys the rigid body of this physics object and frees the memory. + */ + void DestroyRigidBody () noexcept; + + /** + * @brief + * Creates a collider for this physics object. + * @param colliderType + * The collider's type. Should not be modified after creation. + * @param transform. + * The world transform of the collider. Defaults to the identity transform. + * @return + * Pointer to the collider that was created. The memory of this collider is managed + * by the physics object itself. + */ + SHCollider* CreateCollider (const SHTransform& transform = SHTransform::Identity); + + /** + * @brief + * Destroys the collider of this physics object and frees the memory. + */ + void DestroyCollider () noexcept; + + private: + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + void deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCollider* rhsCollider); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp index e6e92ba5..61a77f28 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp @@ -16,8 +16,7 @@ // Project Headers #include "Math/Transform/SHTransformComponent.h" #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/SHCollisionShape.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Tools/Utilities/SHUtilities.h" namespace SHADE @@ -58,66 +57,68 @@ namespace SHADE void SHPhysicsObjectManager::AddRigidBody(EntityID entityID) noexcept { - SHPhysicsObject* physicsObject = nullptr; - - const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); - if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) - physicsObject = createPhysicsObject(entityID); - else - physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID); // Get the component auto* rigidBodyComponent = SHComponentManager::GetComponent(entityID); // Create a new rigidbody in the physics object - // We assume none has already been made + const auto RIGID_BODY_TYPE = static_cast(rigidBodyComponent->GetType()); + auto* rigidBody = physicsObject->CreateRigidBody(RIGID_BODY_TYPE); - physicsObject->rigidBody = new SHRigidBody + SHVec3 worldPos = SHVec3::Zero; + // TODO: Force orientation + + if (const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); TRANSFORM_COMPONENT) { - entityID - , static_cast(rigidBodyComponent->GetType()) - }; - - SHMotionState& motionState = physicsObject->rigidBody->GetMotionState(); - - if (const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent(entityID); TRANSFORM_COMPONENT) - { - motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); - } - else - { - motionState.ForcePosition(SHVec3::Zero); + worldPos = TRANSFORM_COMPONENT->GetWorldPosition(); } + SHMotionState& motionState = rigidBody->GetMotionState(); + motionState.ForcePosition(worldPos); + // Link with the component - rigidBodyComponent->SetRigidBody(physicsObject->rigidBody); - - // TODO: Broadcast event + rigidBodyComponent->SetRigidBody(rigidBody); } void SHPhysicsObjectManager::RemoveRigidBody(EntityID entityID) noexcept { const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); - if (PHYSICS_OBJECT_ITERATOR != physicsObjects.end()) - { - SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) + return; - delete physicsObject->rigidBody; - physicsObject->rigidBody = nullptr; + SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; - // Destroy empty physics objects - if (physicsObject->IsEmpty()) - destroyPhysicsObject(entityID); - } + physicsObject->DestroyRigidBody(); - // TODO: Broadcast event + // Destroy empty physics objects + if (physicsObject->IsEmpty()) + destroyPhysicsObject(entityID); } void SHPhysicsObjectManager::AddCollider(EntityID entityID) noexcept { - // Link with the component + SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID); - // TODO: Broadcast event + // Get the component + auto* colliderComponent = SHComponentManager::GetComponent(entityID); + + SHTransform worldTransform = SHTransform::Identity; + if (const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); TRANSFORM_COMPONENT) + { + worldTransform.position = TRANSFORM_COMPONENT->GetWorldPosition(); + worldTransform.orientation = TRANSFORM_COMPONENT->GetWorldOrientation(); + worldTransform.scale = TRANSFORM_COMPONENT->GetWorldScale(); + + worldTransform.ComputeTRS(); + } + + // Create a new composite collider in the physics object + physicsObject->CreateCollider(worldTransform); + physicsObject->collider->SetFactory(&shapeFactory); + + // Link with the component + colliderComponent->SetCollider(physicsObject->collider); } void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept @@ -127,30 +128,17 @@ namespace SHADE { SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; + physicsObject->DestroyCollider(); + // Destroy empty physics objects if (physicsObject->IsEmpty()) destroyPhysicsObject(entityID); } - - // TODO: Broadcast event - } - - void SHPhysicsObjectManager::AddCollisionShape(EntityID entityID, uint8_t shapeID) noexcept - { - // Link with the component - - // TODO: Broadcast event - } - - void SHPhysicsObjectManager::RemoveCollisionShape(EntityID entityID, uint8_t shapeID) noexcept - { - // Unlink with the component - - // TODO: Broadcast event } void SHPhysicsObjectManager::RemoveAllObjects() noexcept { + // Physics objects itself will delete the object physicsObjects.clear(); } @@ -164,6 +152,18 @@ namespace SHADE return &NEW_OBJECT->second; } + SHPhysicsObject* SHPhysicsObjectManager::ensurePhysicsObject(EntityID entityID) + { + const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); + + SHPhysicsObject* physicsObject = PHYSICS_OBJECT_ITERATOR == physicsObjects.end() + ? createPhysicsObject(entityID) + : &PHYSICS_OBJECT_ITERATOR->second; + + return physicsObject; + } + + void SHPhysicsObjectManager::destroyPhysicsObject(EntityID entityID) { physicsObjects.erase(entityID); diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h index 6449a2d8..ca260a02 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h @@ -14,6 +14,7 @@ // Project Headers #include "SHPhysicsObject.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h" namespace SHADE { @@ -26,7 +27,7 @@ namespace SHADE * Encapsulates a manager for physics objects that links raw physics components with the * engine's components. */ - class SHPhysicsObjectManager + class SH_API SHPhysicsObjectManager { private: /*-----------------------------------------------------------------------------------*/ @@ -60,7 +61,7 @@ namespace SHADE * @param entityID * The entity to link the new rigid body to. */ - void AddRigidBody (EntityID entityID) noexcept; + void AddRigidBody (EntityID entityID) noexcept; /** * @brief @@ -68,66 +69,48 @@ namespace SHADE * @param entityID * The entity to destroy the rigid body of. */ - void RemoveRigidBody (EntityID entityID) noexcept; + void RemoveRigidBody (EntityID entityID) noexcept; /** * @brief - * Creates a collider and links it with the collider component. + * Creates a composite collider and links it with the collider component. * @param entityID * The entity to link the new collider to. */ - void AddCollider (EntityID entityID) noexcept; + void AddCollider (EntityID entityID) noexcept; /** * @brief - * Destroys a collider and removes the link with the collider component. + * Destroys a composite collider and removes the link with the collider component. * @param entityID * The entity to destroy the collider of. */ - void RemoveCollider (EntityID entityID) noexcept; - - /** - * @brief - * Creates a collision shape for composite colliders and links it with the - * collider component. - * @param eientityIDd - * The entity to create a collision shape for. - * @param shapeID - * The id of the shape being created. - */ - void AddCollisionShape (EntityID entityID, uint8_t shapeID) noexcept; - - /** - * @brief - * Destroys a collision shape for composite colliders and removes the link with the - * collider component. - * @param entityID - * The entity to destroy the collision shape of. - * @param shapeID - * The id of the shape being destroyed. - */ - void RemoveCollisionShape (EntityID entityID, uint8_t shapeID) noexcept; + void RemoveCollider (EntityID entityID) noexcept; /** * @brief * Removes all physics object in the manager. This is only meant to be called when * the world is being destroyed or the scene is being changed. */ - void RemoveAllObjects () noexcept; + void RemoveAllObjects () noexcept; private: /*-----------------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------------*/ - EntityObjectMap physicsObjects; + EntityObjectMap physicsObjects; + SHCollisionShapeFactory shapeFactory; /*-----------------------------------------------------------------------------------*/ /* Member Functions */ /*-----------------------------------------------------------------------------------*/ SHPhysicsObject* createPhysicsObject (EntityID entityID); + SHPhysicsObject* ensurePhysicsObject (EntityID entityID); void destroyPhysicsObject (EntityID entityID); + + }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index eef92493..d345290c 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -25,57 +25,43 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHColliderComponent::SHColliderComponent() noexcept + : collider { nullptr } {} /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept + SHCollider* const SHColliderComponent::GetCollider() const noexcept { - return collisionShapes; + return collider; } - SHCollisionShape& SHColliderComponent::GetCollisionShape(int index) + const SHCollider::CollisionShapes* const SHColliderComponent::GetCollisionShapes() const noexcept { - if (index < 0 || static_cast(index) >= collisionShapes.size()) - throw std::invalid_argument("Out-of-range access!"); + if (!collider) + return nullptr; - return collisionShapes[index]; + return &collider->GetCollisionShapes(); } + + SHCollisionShape* const SHColliderComponent::GetCollisionShape(int index) const + { + if (!collider) + return nullptr; + + return collider->GetCollisionShape(index); + } + + /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ + /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHColliderComponent::OnCreate() + void SHColliderComponent::SetCollider(SHCollider* c) noexcept { - - } - - void SHColliderComponent::OnDestroy() - { - - } - - void SHColliderComponent::RecomputeCollisionShapes() noexcept - { - - } - - int SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset, const SHVec3& rotOffset) noexcept - { - return 0; - } - - int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept - { - return 0; - } - - void SHColliderComponent::RemoveCollider(int index) - { - + collider = c; } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index 15a02173..83fb235c 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -14,14 +14,7 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" -#include "Math/Geometry/SHBox.h" -#include "Math/Geometry/SHSphere.h" -#include "SHCollisionShape.h" - -//namespace SHADE -//{ -// class SHPhysicsSystem; -//} +#include "Physics/Collision/SHCollider.h" namespace SHADE { @@ -39,12 +32,6 @@ namespace SHADE friend class SHPhysicsSystem; friend class SHPhysicsObject; - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using CollisionShapes = std::vector; - public: /*---------------------------------------------------------------------------------*/ @@ -67,33 +54,22 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool HasChanged () const noexcept; - - [[nodiscard]] const CollisionShapes& GetCollisionShapes() const noexcept; - [[nodiscard]] SHCollisionShape& GetCollisionShape (int index); + [[nodiscard]] SHCollider* const GetCollider () const noexcept; + [[nodiscard]] const SHCollider::CollisionShapes* const GetCollisionShapes() const noexcept; + [[nodiscard]] SHCollisionShape* const GetCollisionShape (int index) const; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void OnCreate () override; - void OnDestroy () override; - - void RecomputeCollisionShapes () noexcept; - - void RemoveCollider (int index); - - int AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero) noexcept; - int AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept; + void SetCollider(SHCollider* c) noexcept; private: - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHVec3 scale; - CollisionShapes collisionShapes; + SHCollider* collider; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp deleted file mode 100644 index 4dd506f9..00000000 --- a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/**************************************************************************************** - * \file SHCollider.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Collider. - * - * \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 - -// Primary Header -#include "SHCollisionShape.h" -// Project Headers -#include "Math/Geometry/SHBox.h" -#include "Math/Geometry/SHSphere.h" -#include "Math/SHMathHelpers.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" -#include "Reflection/SHReflectionMetadata.h" -#include "SHColliderComponent.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionShape::SHCollisionShape(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial) - : type { colliderType } - , entityID { eid } - , isTrigger { false } - , dirty { true } - , shape { nullptr } - , material { physicsMaterial } - , collisionTag { SHCollisionTagMatrix::GetTag(0) } - { - switch (type) - { - case Type::BOX: - { - shape = new SHBox{ SHVec3::Zero, SHVec3::One }; - break; - } - case Type::SPHERE: - { - shape = new SHSphere{ SHVec3::Zero, 0.5f }; - break; - } - default: break; - } - } - - SHCollisionShape::SHCollisionShape(const SHCollisionShape& rhs) noexcept - : type { rhs.type} - , entityID { rhs.entityID } - , isTrigger { rhs.isTrigger } - , dirty { true } - , shape { nullptr } - , material { rhs.material } - , positionOffset { rhs.positionOffset } - , rotationOffset { rhs.rotationOffset } - , collisionTag { rhs.collisionTag } - { - CopyShape(rhs.shape); - } - - SHCollisionShape::SHCollisionShape(SHCollisionShape&& rhs) noexcept - : type { rhs.type} - , entityID { rhs.entityID } - , isTrigger { rhs.isTrigger } - , dirty { true } - , shape { nullptr } - , material { rhs.material } - , positionOffset { rhs.positionOffset } - , rotationOffset { rhs.rotationOffset } - , collisionTag { rhs.collisionTag } - { - CopyShape(rhs.shape); - } - - SHCollisionShape::~SHCollisionShape() noexcept - { - shape = nullptr; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionShape& SHCollisionShape::operator=(const SHCollisionShape& rhs) noexcept - { - if (this == &rhs) - return *this; - - type = rhs.type; - entityID = rhs.entityID; - isTrigger = rhs.isTrigger; - dirty = true; - material = rhs.material; - positionOffset = rhs.positionOffset; - rotationOffset = rhs.rotationOffset; - collisionTag = rhs.collisionTag; - - delete shape; - CopyShape(rhs.shape); - - return *this; - } - - SHCollisionShape& SHCollisionShape::operator=(SHCollisionShape&& rhs) noexcept - { - type = rhs.type; - entityID = rhs.entityID; - isTrigger = rhs.isTrigger; - dirty = true; - material = rhs.material; - positionOffset = rhs.positionOffset; - rotationOffset = rhs.rotationOffset; - collisionTag = rhs.collisionTag; - - delete shape; - CopyShape(rhs.shape); - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHCollisionShape::HasChanged() const noexcept - { - return dirty; - } - - bool SHCollisionShape::IsTrigger() const noexcept - { - return isTrigger; - } - - SHCollisionShape::Type SHCollisionShape::GetType() const noexcept - { - return type; - } - - const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept - { - return *collisionTag; - } - - float SHCollisionShape::GetFriction() const noexcept - { - return material.GetFriction(); - } - - float SHCollisionShape::GetBounciness() const noexcept - { - return material.GetBounciness(); - } - - float SHCollisionShape::GetDensity() const noexcept - { - return material.GetDensity(); - } - - const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept - { - return material; - } - - const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept - { - return positionOffset; - } - - const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept - { - return rotationOffset; - } - - const SHShape* SHCollisionShape::GetShape() const noexcept - { - return shape; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::SetBoundingBox(const SHVec3& halfExtents) - { - //dirty = true; - - //const auto* COLLIDER = SHComponentManager::GetComponent(entityID); - //auto* box = reinterpret_cast(shape); - - //SHVec3 correctedHalfExtents = halfExtents; - - //// Get current relative halfExtents for error checking. 0 is ignored - //const SHVec3& CURRENT_RELATIVE_EXTENTS = box->GetRelativeExtents(); - //for (size_t i = 0; i < SHVec3::SIZE; ++i) - //{ - // if (SHMath::CompareFloat(halfExtents[i], 0.0f)) - // correctedHalfExtents[i] = CURRENT_RELATIVE_EXTENTS[i]; - //} - // - //// Set the half extents relative to world scale - //const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale() * 0.5f; - - //if (type != Type::BOX) - //{ - // type = Type::BOX; - - // delete shape; - // shape = new SHBox{ positionOffset, WORLD_EXTENTS }; - //} - - //box->SetWorldExtents(WORLD_EXTENTS); - //box->SetRelativeExtents(correctedHalfExtents); - } - - void SHCollisionShape::SetBoundingSphere(float radius) - { - //dirty = true; - - //auto* sphere = reinterpret_cast(shape); - //const auto* COLLIDER = SHComponentManager::GetComponent(entityID); - - //// Get current relative halfExtents for error checking. 0 is ignored - //const float CURRENT_RELATIVE_RADIUS = sphere->GetRelativeRadius(); - //if (SHMath::CompareFloat(radius, 0.0f)) - // radius = CURRENT_RELATIVE_RADIUS; - - //// Set the radius relative to world scale - //const SHVec3 WORLD_SCALE = COLLIDER->GetScale(); - //const float MAX_SCALE = SHMath::Max({ WORLD_SCALE.x, WORLD_SCALE.y, WORLD_SCALE.z }); - //const float WORLD_RADIUS = radius * MAX_SCALE * 0.5f; - - //if (type != Type::SPHERE) - //{ - // type = Type::SPHERE; - - // delete shape; - // shape = new SHSphere{ positionOffset, WORLD_RADIUS }; - //} - - //sphere->SetWorldRadius(WORLD_RADIUS); - //sphere->SetRelativeRadius(radius); - } - - void SHCollisionShape::SetIsTrigger(bool trigger) noexcept - { - dirty = true; - isTrigger = trigger; - } - - void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept - { - dirty = true; - collisionTag = newCollisionTag; - } - - void SHCollisionShape::SetFriction(float friction) noexcept - { - dirty = true; - material.SetFriction(friction); - } - - void SHCollisionShape::SetBounciness(float bounciness) noexcept - { - dirty = true; - material.SetBounciness(bounciness); - } - - void SHCollisionShape::SetDensity(float density) noexcept - { - dirty = true; - material.SetDensity(density); - } - - void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept - { - dirty = true; - material = newMaterial; - } - - void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept - { - dirty = true; - positionOffset = posOffset; - - switch (type) - { - case Type::BOX: - { - reinterpret_cast(shape)->SetCenter(positionOffset); - break; - } - case Type::SPHERE: - { - reinterpret_cast(shape)->SetCenter(positionOffset); - break; - } - default: break; - } - } - - void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept - { - dirty = true; - rotationOffset = rotOffset; - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::CopyShape(const SHShape* rhs) - { - switch (type) - { - case Type::BOX: - { - const auto* RHS_BOX = reinterpret_cast(rhs); - - shape = new SHBox{ positionOffset, RHS_BOX->GetWorldExtents() }; - auto* lhsBox = reinterpret_cast(shape); - lhsBox->SetRelativeExtents(RHS_BOX->GetRelativeExtents()); - - break; - } - case Type::SPHERE: - { - const auto* RHS_SPHERE = reinterpret_cast(rhs); - - shape = new SHSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() }; - auto* lhsSphere = reinterpret_cast(shape); - lhsSphere->SetRelativeRadius(RHS_SPHERE->GetRelativeRadius()); - - break; - } - default: break; - } - } - -} // namespace SHADE - -RTTR_REGISTRATION -{ - using namespace SHADE; - using namespace rttr; - - registration::enumeration("Collider Type") - ( - value("Box", SHCollisionShape::Type::BOX), - value("Sphere", SHCollisionShape::Type::SPHERE) - // TODO(Diren): Add More Shapes - ); - - registration::class_("Collider") - .property("IsTrigger" , &SHCollisionShape::IsTrigger , &SHCollisionShape::SetIsTrigger ) - .property("Friction" , &SHCollisionShape::GetFriction , &SHCollisionShape::SetFriction ) - .property("Bounciness" , &SHCollisionShape::GetBounciness , &SHCollisionShape::SetBounciness ) - .property("Density" , &SHCollisionShape::GetDensity , &SHCollisionShape::SetDensity ) - .property("Position Offset" , &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset) - .property("Rotation Offset" , &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true)); -} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp similarity index 98% rename from SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp rename to SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index ddc51fbc..da848f09 100644 --- a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -10,17 +10,9 @@ #include -// External Dependencies -#include - // Primary Header #include "SHRigidBodyComponent.h" -// Project Headers -#include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/Dynamics/SHRigidBody.h" -#include "Physics/System/SHPhysicsSystem.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h similarity index 96% rename from SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h rename to SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index bfb1717b..7d377184 100644 --- a/SHADE_Engine/src/Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -15,15 +15,10 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" #include "Math/Vector/SHVec3.h" +#include "Physics/Dynamics/SHRigidBody.h" namespace SHADE { - /*-------------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-------------------------------------------------------------------------------------*/ - - class SHRigidBody; - /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/SHPhysicsEvents.h b/SHADE_Engine/src/Physics/SHPhysicsEvents.h index ae48a75b..35217347 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsEvents.h +++ b/SHADE_Engine/src/Physics/SHPhysicsEvents.h @@ -11,7 +11,7 @@ #pragma once // Project Headers -#include "Interface/SHCollisionShape.h" +#include "Collision/CollisionShapes/SHCollisionShape.h" namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 5f18c450..cd4b1cff 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -57,19 +57,20 @@ namespace SHADE if (!rigidBodyComponent.rigidBody) continue; - if (const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); MOTION_STATE) - { - SHVec3 renderPosition = rigidBodyComponent.IsInterpolating() - ? MOTION_STATE.InterpolatePositions(FACTOR) - : MOTION_STATE.position; + const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); - /* - * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. - */ + if (!MOTION_STATE) + continue; - transformComponent->SetWorldPosition(renderPosition); - // TODO: SetOrientation - } + SHVec3 renderPosition = rigidBodyComponent.IsInterpolating() ? MOTION_STATE.InterpolatePositions(FACTOR) : MOTION_STATE.position; + + /* + * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. + */ + + + transformComponent->SetWorldPosition(renderPosition); + // TODO: SetOrientation } // Collision & Trigger messages diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index eda69161..c03571db 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -40,23 +40,32 @@ namespace SHADE { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); + if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) + return; + + const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); + const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale(); + // We assume that all engine components and physics object components have been successfully linked - if (TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged()) + if (physicsObject.rigidBody) { - // Sync the objects transforms - const SHVec3 WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); - if (physicsObject.rigidBody) - { - SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); - - motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); - // TODO: Force Orientation - } + motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); + // TODO: Force Orientation } - // TODO: Sync Collider Transform with World Transform + if (physicsObject.collider) + { + physicsObject.collider->SetPosition(WORLD_POS); + physicsObject.collider->SetOrientation(WORLD_ROT); + physicsObject.collider->SetScale(WORLD_SCL); + + physicsObject.collider->RecomputeShapes(); + } } } -} + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index b4ff6961..d7bece3b 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -162,6 +162,9 @@ namespace SHADE { if (PHYSICS_OBJECT.rigidBody) physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); + + if (PHYSICS_OBJECT.collider) + physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); } delete physicsWorld; @@ -177,13 +180,16 @@ namespace SHADE // This is for handling scene changes while the editor is active. const auto* EDITOR = SHSystemManager::GetSystem(); - if (EDITOR && EDITOR->editorState == SHEditor::State::PLAY) + 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) - physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); - } + if (PHYSICS_OBJECT.rigidBody) + physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); + + if (PHYSICS_OBJECT.collider) + physicsWorld->AddCollider(PHYSICS_OBJECT.collider); } #endif @@ -202,6 +208,9 @@ namespace SHADE { if (PHYSICS_OBJECT.rigidBody) physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); + + if (PHYSICS_OBJECT.collider) + physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); } delete physicsWorld; @@ -223,25 +232,34 @@ namespace SHADE const bool IS_COLLIDER = ADDED_ID == COLLIDER_COMPONENT_ID; // Check if its a physics component - if (IS_RIGID_BODY || IS_COLLIDER) + const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER; + if (!IS_PHYSICS_COMPONENT) + return onComponentAddedEvent.get()->handle; + + const EntityID EID = EVENT_DATA->eid; + + // Link engine components with physics object component + if (IS_RIGID_BODY) { - const EntityID EID = EVENT_DATA->eid; + physicsObjectManager.AddRigidBody(EID); - // Link engine components with physics object component - if (IS_RIGID_BODY) + if (physicsWorld) { - physicsObjectManager.AddRigidBody(EID); - - if (physicsWorld) - { - auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; - physicsWorld->AddRigidBody(rigidBody); - } + auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; + physicsWorld->AddRigidBody(rigidBody); } + } - if (IS_COLLIDER) - physicsObjectManager.AddCollider(EID); + if (IS_COLLIDER) + { + physicsObjectManager.AddCollider(EID); + + if (physicsWorld) + { + auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; + physicsWorld->AddCollider(collider); + } } return onComponentAddedEvent.get()->handle; @@ -260,27 +278,35 @@ namespace SHADE const bool IS_COLLIDER = REMOVED_DATA == COLLIDER_COMPONENT_ID; // Check if its a physics component - if (IS_RIGID_BODY || IS_COLLIDER) + const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER; + if (!IS_PHYSICS_COMPONENT) + return onComponentRemovedEvent.get()->handle; + + const EntityID EID = EVENT_DATA->eid; + + if (IS_RIGID_BODY) { - const EntityID EID = EVENT_DATA->eid; - - // Link engine components with physics object component - if (IS_RIGID_BODY) + if (physicsWorld) { - if (physicsWorld) - { - auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; - physicsWorld->RemoveRigidBody(rigidBody); - } - - physicsObjectManager.RemoveRigidBody(EID); + auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; + physicsWorld->RemoveRigidBody(rigidBody); } - - if (IS_COLLIDER) - physicsObjectManager.RemoveCollider(EID); + physicsObjectManager.RemoveRigidBody(EID); } + if (IS_COLLIDER) + { + if (physicsWorld) + { + auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; + physicsWorld->RemoveCollider(collider); + } + + physicsObjectManager.RemoveCollider(EID); + } + + return onComponentRemovedEvent.get()->handle; } @@ -295,7 +321,8 @@ namespace SHADE if (PHYSICS_OBJECT.rigidBody) physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); - // TODO: Add Collider if it exists + if (PHYSICS_OBJECT.collider) + physicsWorld->AddCollider(PHYSICS_OBJECT.collider); } return onEditorPlayEvent.get()->handle; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index 7d7dece5..2a351e86 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -18,7 +18,7 @@ #include "Physics/Dynamics/SHPhysicsWorld.h" #include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 9d648185..99e4fa41 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -15,7 +15,7 @@ #include "Camera/SHCameraArmComponent.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index e1cb8181..cbbe8505 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -1,9 +1,7 @@ #pragma once #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" -#include "Math/Geometry/SHBox.h" -#include "Math/Geometry/SHSphere.h" -#include "Physics/Interface/SHCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" #include "Resource/SHResourceManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" @@ -134,14 +132,14 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - const auto* BOX = reinterpret_cast(rhs.GetShape()); - node[HalfExtents] = BOX->GetRelativeExtents(); + //const auto* BOX = reinterpret_cast(rhs.GetShape()); + //node[HalfExtents] = BOX->GetRelativeExtents(); } break; case SHCollisionShape::Type::SPHERE: { - const auto* SPHERE = reinterpret_cast(rhs.GetShape()); - node[Radius] = SPHERE->GetRelativeRadius(); + const auto& SPHERE = dynamic_cast(rhs); + node[Radius] = SPHERE.GetRelativeRadius(); } break; case SHCollisionShape::Type::CAPSULE: break; @@ -172,14 +170,17 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - if (node[HalfExtents].IsDefined()) - rhs.SetBoundingBox(node[HalfExtents].as()); + //if (node[HalfExtents].IsDefined()) + // rhs.SetBoundingBox(node[HalfExtents].as()); } break; case SHCollisionShape::Type::SPHERE: { if (node[Radius].IsDefined()) - rhs.SetBoundingSphere(node[Radius].as()); + { + auto* sphere = dynamic_cast(&rhs); + sphere->SetRelativeRadius(node[Radius].as()); + } } break; case SHCollisionShape::Type::CAPSULE: break; @@ -207,11 +208,10 @@ namespace YAML static Node encode(SHColliderComponent& rhs) { Node node, collidersNode; - auto const& colliders = rhs.GetCollisionShapes(); - int const numColliders = static_cast(colliders.size()); + int const numColliders = static_cast(rhs.GetCollisionShapes()->size()); for (int i = 0; i < numColliders; ++i) { - auto& collider = rhs.GetCollisionShape(i); + auto& collider = *rhs.GetCollisionShape(i); Node colliderNode = convert::encode(collider); if (colliderNode.IsDefined()) collidersNode[i] = colliderNode; @@ -233,14 +233,16 @@ namespace YAML if (!ok) return false; + auto* collider = rhs.GetCollider(); + switch (colliderType) { - case SHCollisionShape::Type::BOX: rhs.AddBoundingBox(); break; - case SHCollisionShape::Type::SPHERE: rhs.AddBoundingSphere(); break; + case SHCollisionShape::Type::BOX: break; + case SHCollisionShape::Type::SPHERE: collider->AddSphereCollisionShape(1.0f); break; case SHCollisionShape::Type::CAPSULE: break; default:; } - YAML::convert::decode(colliderNode, rhs.GetCollisionShape(numColliders++)); + YAML::convert::decode(colliderNode, *collider->GetCollisionShape(numColliders++)); } } return true; diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 414e79b7..1c84637a 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -107,7 +107,7 @@ namespace SHADE try { - auto& shape = collider->GetCollisionShape(arrayIndex); + auto& shape = *collider->GetCollisionShape(arrayIndex); return shape; } catch (std::invalid_argument&) @@ -128,35 +128,39 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 BoxCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + //return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + return Vector3::Zero; } void BoxCollider::Center::set(Vector3 value) { - getNativeCollisionShape().SetCenter(Convert::ToNative(value)); + //getNativeCollisionShape().SetCenter(Convert::ToNative(value)); } Vector3 BoxCollider::HalfExtents::get() { - return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + //return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + return Vector3::Zero; } void BoxCollider::HalfExtents::set(Vector3 value) { - getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); + //getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); } Vector3 BoxCollider::Min::get() { - return Convert::ToCLI(getNativeCollisionShape().GetMin()); + //return Convert::ToCLI(getNativeCollisionShape().GetMin()); + return Vector3::Zero; } void BoxCollider::Min::set(Vector3 value) { - getNativeCollisionShape().SetMin(Convert::ToNative(value)); + //getNativeCollisionShape().SetMin(Convert::ToNative(value)); } Vector3 BoxCollider::Max::get() { - return Convert::ToCLI(getNativeCollisionShape().GetMax()); + //return Convert::ToCLI(getNativeCollisionShape().GetMax()); + return Vector3::Zero; } void BoxCollider::Max::set(Vector3 value) { - getNativeCollisionShape().SetMax(Convert::ToNative(value)); + //getNativeCollisionShape().SetMax(Convert::ToNative(value)); } /*---------------------------------------------------------------------------------*/ @@ -164,11 +168,13 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool BoxCollider::TestPoint(Vector3 point) { - return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + //return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + return false; } bool BoxCollider::Raycast(Ray ray, float maxDistance) { - return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + //return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + return false; } /*---------------------------------------------------------------------------------*/ @@ -176,19 +182,19 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 SphereCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + return Convert::ToCLI(getNativeCollisionShape().GetCenter()); } void SphereCollider::Center::set(Vector3 value) { - getNativeCollisionShape().SetCenter(Convert::ToNative(value)); + getNativeCollisionShape().SetCenter(Convert::ToNative(value)); } float SphereCollider::Radius::get() { - return getNativeCollisionShape().GetWorldRadius(); + return getNativeCollisionShape().GetWorldRadius(); } void SphereCollider::Radius::set(float value) { - getNativeCollisionShape().SetWorldRadius(value); + getNativeCollisionShape().SetWorldRadius(value); } /*---------------------------------------------------------------------------------*/ @@ -196,11 +202,11 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool SphereCollider::TestPoint(Vector3 point) { - return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); } bool SphereCollider::Raycast(Ray ray, float maxDistance) { - return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); } /*---------------------------------------------------------------------------------*/ @@ -231,7 +237,10 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ int Collider::CollisionShapeCount::get() { - return static_cast(GetNativeComponent()->GetCollisionShapes().size()); + if (const auto* shapes = GetNativeComponent()->GetCollisionShapes()) + return static_cast(shapes->size()); + + return -1; } /*---------------------------------------------------------------------------------*/ @@ -311,10 +320,10 @@ namespace SHADE // Populate the list int i = 0; - for (const auto& collider : GetNativeComponent()->GetCollisionShapes()) + for (const auto* collider : *GetNativeComponent()->GetCollisionShapes()) { CollisionShape^ bound = nullptr; - switch (collider.GetType()) + switch (collider->GetType()) { case SHCollisionShape::Type::BOX: bound = gcnew BoxCollider(i, Owner.GetEntity()); diff --git a/SHADE_Managed/src/Components/Collider.h++ b/SHADE_Managed/src/Components/Collider.h++ index 8ea648aa..c2e732f4 100644 --- a/SHADE_Managed/src/Components/Collider.h++ +++ b/SHADE_Managed/src/Components/Collider.h++ @@ -27,11 +27,11 @@ namespace SHADE try { - auto& shape = collider->GetCollisionShape(arrayIndex); - if (shape.GetType() != SHCollisionShape::Type::BOX) + auto* shape = collider->GetCollisionShape(arrayIndex); + if (!shape || shape->GetType() == SHCollisionShape::Type::INVALID) throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); - return reinterpret_cast(shape); + return dynamic_cast(*shape); } catch (std::invalid_argument&) { diff --git a/SHADE_Managed/src/Components/RigidBody.hxx b/SHADE_Managed/src/Components/RigidBody.hxx index 6ca39316..8bfe34aa 100644 --- a/SHADE_Managed/src/Components/RigidBody.hxx +++ b/SHADE_Managed/src/Components/RigidBody.hxx @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. #pragma once // External Dependencies -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" // Project Includes #include "Components/Component.hxx" diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 3ace79ab..c388f0cd 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -23,7 +23,7 @@ of DigiPen Institute of Technology is prohibited. #include "ECS_Base/Managers/SHEntityManager.h" #include "Math/Transform/SHTransformComponent.h" #include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/RigidBodyComponent/SHRigidBodyComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/Logger/SHLog.h" -- 2.40.1 From c1d77029142e5631a0293b7e9bd2f1018de89525 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 11 Dec 2022 20:12:26 +0800 Subject: [PATCH 07/84] Moved debug draw state to colliders. Synced collider positions with rigid bodies --- Assets/Scenes/PhysicsSandbox.shade | 11 +++ .../src/Application/SBApplication.cpp | 3 + .../Inspector/SHEditorComponentView.hpp | 37 +++++----- .../CollisionShapes/SHCollisionShape.cpp | 18 +---- .../CollisionShapes/SHCollisionShape.h | 11 +-- .../SHCollisionTagMatrix.cpp | 0 .../SHCollisionTagMatrix.h | 0 .../{ => CollisionTags}/SHCollisionTags.cpp | 0 .../{ => CollisionTags}/SHCollisionTags.h | 0 .../src/Physics/Collision/SHCollider.cpp | 74 ++++++++++++++++++- .../src/Physics/Collision/SHCollider.h | 33 ++++++--- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 19 +++-- .../Routines/SHPhysicsDebugDrawRoutine.cpp | 60 +++++++++++++++ .../Routines/SHPhysicsPostUpdateRoutine.cpp | 4 +- .../src/Physics/System/SHPhysicsSystem.cpp | 10 +-- .../src/Physics/System/SHPhysicsSystem.h | 21 +++++- 16 files changed, 230 insertions(+), 71 deletions(-) rename SHADE_Engine/src/Physics/Collision/{ => CollisionTags}/SHCollisionTagMatrix.cpp (100%) rename SHADE_Engine/src/Physics/Collision/{ => CollisionTags}/SHCollisionTagMatrix.h (100%) rename SHADE_Engine/src/Physics/Collision/{ => CollisionTags}/SHCollisionTags.cpp (100%) rename SHADE_Engine/src/Physics/Collision/{ => CollisionTags}/SHCollisionTags.h (100%) create mode 100644 SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index d6b77c17..f600c4ae 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -25,6 +25,17 @@ Freeze Rotation Y: false Freeze Rotation Z: false IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Type: Sphere + Radius: 1 + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true Scripts: ~ - EID: 1 Name: Default diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index a58839c5..3cb504c0 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -111,6 +111,9 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); +#ifdef SHEDITOR + SHSystemManager::RegisterRoutine(); +#endif SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 774697f1..dfc89df1 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -322,18 +322,21 @@ namespace SHADE { DrawContextMenu(component); - auto* colliders = component->GetCollisionShapes(); - int const size = colliders ? static_cast(colliders->size()) : 0; - ImGui::BeginChild("Collision Shapes", { 0.0f, colliders->empty() ? 1.0f : 250.0f }, true); + auto* collider = component->GetCollider(); + SHEditorWidgets::CheckBox("Draw Colliders", [collider] { return collider->GetDebugDrawState(); }, [collider](bool value) { collider->SetDebugDrawState(value); }); + + auto* collisionShapes = component->GetCollisionShapes(); + int const size = collisionShapes ? static_cast(collisionShapes->size()) : 0; + ImGui::BeginChild("Collision Shapes", { 0.0f, collisionShapes->empty() ? 1.0f : 250.0f }, true); std::optional colliderToDelete{ std::nullopt }; for (int i{}; i < size; ++i) { ImGui::PushID(i); - SHCollisionShape* collider = component->GetCollisionShape(i); + SHCollisionShape* shape = component->GetCollisionShape(i); auto cursorPos = ImGui::GetCursorPos(); //collider->IsTrigger - if (collider->GetType() == SHCollisionShape::Type::BOX) + if (shape->GetType() == SHCollisionShape::Type::BOX) { //SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); // @@ -344,42 +347,42 @@ namespace SHADE // [BOX] { return BOX->GetRelativeExtents(); }, // [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } - else if (collider->GetType() == SHCollisionShape::Type::SPHERE) + 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(collider); + auto* SPHERE = reinterpret_cast(shape); SHEditorWidgets::DragFloat ( "Radius", [SPHERE] { return SPHERE->GetRelativeRadius(); }, [SPHERE](float const& value) { SPHERE->SetRelativeRadius(value); }); } - else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) + else if (shape->GetType() == SHCollisionShape::Type::CAPSULE) { } { - SHEditorWidgets::CheckBox("Is Trigger", [collider] { return collider->IsTrigger(); }, [collider](bool value) { collider->SetIsTrigger(value); }); + SHEditorWidgets::CheckBox("Is Trigger", [shape] { return shape->IsTrigger(); }, [shape](bool value) { shape->SetIsTrigger(value); }); if(ImGui::CollapsingHeader("Physics Material")) { - SHEditorWidgets::DragFloat("Friction", [collider] { return collider->GetFriction(); }, [collider](float value) { collider->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f); - SHEditorWidgets::DragFloat("Bounciness", [collider] { return collider->GetBounciness(); }, [collider](float value) { collider->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f); - SHEditorWidgets::DragFloat("Mass Density", [collider] { return collider->GetDensity(); }, [collider](float value) { collider->SetDensity(value); }, "Mass Density", 0.1f, 0.0f); + SHEditorWidgets::DragFloat("Friction", [shape] { return shape->GetFriction(); }, [shape](float value) { shape->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f); + SHEditorWidgets::DragFloat("Bounciness", [shape] { return shape->GetBounciness(); }, [shape](float value) { shape->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f); + SHEditorWidgets::DragFloat("Mass Density", [shape] { return shape->GetDensity(); }, [shape](float value) { shape->SetDensity(value); }, "Mass Density", 0.1f, 0.0f); } SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f }); - SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&shape] {return shape->GetPositionOffset(); }, [&shape](SHVec3 const& vec) {shape->SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, - [&collider] + [&shape] { - auto offset = collider->GetRotationOffset(); + auto offset = shape->GetRotationOffset(); return offset; }, - [&collider](SHVec3 const& vec) + [&shape](SHVec3 const& vec) { - collider->SetRotationOffset(vec); + shape->SetRotationOffset(vec); }, true); SHEditorWidgets::EndPanel(); } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index 845634fe..2f4e3819 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -14,7 +14,7 @@ #include "SHCollisionShape.h" // Project Headers -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Reflection/SHReflectionMetadata.h" #include "Tools/Utilities/SHUtilities.h" @@ -95,14 +95,6 @@ namespace SHADE return flags & FLAG_VALUE; } - bool SHCollisionShape::GetDebugDrawState() const noexcept - { - static constexpr int FLAG_POS = 6; - static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; - - return flags & FLAG_VALUE; - } - const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept { return *collisionTag; @@ -150,14 +142,6 @@ namespace SHADE isTrigger ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; } - void SHCollisionShape::SetDebugDrawState(bool isDebugDrawing) noexcept - { - static constexpr int FLAG_POS = 6; - static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; - - isDebugDrawing ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - } - void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept { collisionTag = newCollisionTag; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 420c0d6e..c05baddd 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -16,7 +16,7 @@ #include "ECS_Base/Entity/SHEntity.h" #include "Math/Geometry/SHShape.h" #include "Math/SHQuaternion.h" -#include "Physics/Collision/SHCollisionTags.h" +#include "Physics/Collision/CollisionTags/SHCollisionTags.h" #include "Physics/Collision/SHPhysicsMaterial.h" #include "SHCollisionShapeID.h" @@ -44,8 +44,8 @@ namespace SHADE enum class Type { - BOX - , SPHERE + SPHERE + , BOX , CAPSULE , COUNT @@ -91,8 +91,6 @@ namespace SHADE [[nodiscard]] Type GetType () const noexcept; [[nodiscard]] bool IsTrigger () const noexcept; [[nodiscard]] bool IsColliding () const noexcept; - [[nodiscard]] bool GetDebugDrawState () const noexcept; - [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; @@ -110,7 +108,6 @@ namespace SHADE // Flags void SetIsTrigger (bool isTrigger) noexcept; - void SetDebugDrawState (bool isDebugDrawing) noexcept; void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; @@ -126,7 +123,7 @@ namespace SHADE SHVec3 positionOffset; SHVec3 rotationOffset; - uint8_t flags; // 0 debugDraw wasColliding isColliding trigger capsule sphere box + uint8_t flags; // 0 0 wasColliding isColliding trigger capsule sphere box SHCollisionTag* collisionTag; RTTR_ENABLE() diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.h diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.cpp diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionTags.h b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHCollisionTags.h rename to SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.h diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index e950c4fb..1d29a585 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -25,14 +25,22 @@ namespace SHADE SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept : entityID { eid } , shapeIDCounter { 0 } +#ifdef SHEDITOR + , debugDraw { false } +#endif , rigidBody { nullptr } , shapeFactory { nullptr } , transform { worldTransform } - {} + { + + } SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } +#ifdef SHEDITOR + , debugDraw { rhs.debugDraw } +#endif , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -49,6 +57,9 @@ namespace SHADE SHCollider::SHCollider(SHCollider&& rhs) noexcept : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } +#ifdef SHEDITOR + , debugDraw { rhs.debugDraw } +#endif , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -94,6 +105,10 @@ namespace SHADE shapeFactory = rhs.shapeFactory; transform = rhs.transform; + #ifdef SHEDITOR + debugDraw = rhs.debugDraw; + #endif + copyShapes(rhs); return *this; @@ -112,6 +127,10 @@ namespace SHADE shapeFactory = rhs.shapeFactory; transform = rhs.transform; + #ifdef SHEDITOR + debugDraw = rhs.debugDraw; + #endif + copyShapes(rhs); return *this; @@ -121,6 +140,13 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ +#ifdef SHEDITOR + bool SHCollider::GetDebugDrawState() const noexcept + { + return debugDraw; + } +#endif + const SHTransform& SHCollider::GetTransform() const noexcept { return transform; @@ -160,6 +186,13 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ +#ifdef SHEDITOR + void SHCollider::SetDebugDrawState(bool state) noexcept + { + debugDraw = state; + } +#endif + void SHCollider::SetRigidBody(SHRigidBody* rb) noexcept { rigidBody = rb; @@ -190,7 +223,6 @@ namespace SHADE shapeFactory = factory; } - /*-----------------------------------------------------------------------------------*/ /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -266,9 +298,28 @@ namespace SHADE SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) } - void SHCollider::RecomputeShapes() const noexcept + void SHCollider::RecomputeShapes() noexcept { - + for (auto* shape : shapes) + { + switch (shape->GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + recomputeSphere(dynamic_cast(shape)); + break; + } + case SHCollisionShape::Type::BOX: + { + break; + } + case SHCollisionShape::Type::CAPSULE: + { + break; + } + default: break; + } + } } /*-----------------------------------------------------------------------------------*/ @@ -324,4 +375,19 @@ namespace SHADE ++shapeIDCounter; } + void SHCollider::recomputeSphere(SHSphereCollisionShape* sphere) noexcept + { + // Recompute world radius + const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z })); + sphere->SetScale(SPHERE_SCALE); + + // Recompute center + const SHQuaternion FINAL_ROT = transform.orientation * SHQuaternion::FromEuler(sphere->rotationOffset); + const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(transform.position); + + const SHVec3 NEW_CENTER = SHVec3::Transform(sphere->positionOffset, TRS); + sphere->SetCenter(NEW_CENTER); + } + + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 37d96caa..cab433a5 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -78,6 +78,10 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + #ifdef SHEDITOR + [[nodiscard]] bool GetDebugDrawState () const noexcept; + #endif + [[nodiscard]] const SHTransform& GetTransform () const noexcept; [[nodiscard]] const SHVec3& GetPosition () const noexcept; [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; @@ -90,14 +94,18 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetRigidBody (SHRigidBody* rb) noexcept; + #ifdef SHEDITOR + void SetDebugDrawState (bool state) noexcept; + #endif - void SetTransform (const SHTransform& newTransform) noexcept; - void SetPosition (const SHVec3& newPosition) noexcept; - void SetOrientation (const SHQuaternion& newOrientation) noexcept; - void SetScale (const SHVec3& newScale) noexcept; + void SetRigidBody (SHRigidBody* rb) noexcept; - void SetFactory (SHCollisionShapeFactory* factory) noexcept; + void SetTransform (const SHTransform& newTransform) noexcept; + void SetPosition (const SHVec3& newPosition) noexcept; + void SetOrientation (const SHQuaternion& newOrientation) noexcept; + void SetScale (const SHVec3& newScale) noexcept; + + void SetFactory (SHCollisionShapeFactory* factory) noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ @@ -125,6 +133,7 @@ namespace SHADE * 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 /** @@ -142,7 +151,7 @@ namespace SHADE * @brief * Recomputes the transforms for all shapes in this composite collider. */ - void RecomputeShapes () const noexcept; + void RecomputeShapes () noexcept; protected: /*---------------------------------------------------------------------------------*/ @@ -152,6 +161,10 @@ namespace SHADE EntityID entityID; uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. + #ifdef SHEDITOR + bool debugDraw; + #endif + SHRigidBody* rigidBody; SHCollisionShapeFactory* shapeFactory; @@ -163,8 +176,10 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - void copyShapes (const SHCollider& rhsCollider); - void copyShape (const SHCollisionShape* rhsShape); + void copyShapes (const SHCollider& rhsCollider); + void copyShape (const SHCollisionShape* rhsShape); + + void recomputeSphere (SHSphereCollisionShape* sphere) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 0d7434f6..e6c02168 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -122,15 +122,20 @@ namespace SHADE { rigidBody.linearVelocity = SHVec3::Zero; } - else // Dynamic & Kinematic bodies + // Dynamic & Kinematic bodies + // Both dynamic and kinematic can sleep when their velocities are under the thresholds. + else if (!rigidBody.IsSleeping()) { - // Both dynamic and kinematic can sleep when their velocities are under the thresholds. - if (!rigidBody.IsSleeping()) - { - ENFORCE_CONSTRAINED_VELOCITIES(rigidBody); + ENFORCE_CONSTRAINED_VELOCITIES(rigidBody); - rigidBody.motionState.IntegratePosition(rigidBody.linearVelocity, dt); - // TODO: Integrate orientations + rigidBody.motionState.IntegratePosition(rigidBody.linearVelocity, dt); + // TODO: Integrate orientations + + // Sync with collider transforms if a collider is present + if (rigidBody.collider) + { + rigidBody.collider->SetPosition(rigidBody.motionState.position); + // TODO: Sync orientations } } diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp new file mode 100644 index 00000000..c73e8ab7 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -0,0 +1,60 @@ +/**************************************************************************************** + * \file SHPhysicsDebugDrawRoutine.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Debug-Draw Routine + * + * \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 + +// Primary Header +#include "Physics/System/SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" + +#include "Scripting/SHScriptEngine.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::PhysicsDebugDraw::PhysicsDebugDraw() + : SHSystemRoutine { "Physics Debug Draw", false } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::PhysicsDebugDraw::Execute(double) noexcept + { + auto* physicsSystem = reinterpret_cast(GetSystem()); + + // Get debug drawing system + auto* debugDrawSystem = SHSystemManager::GetSystem(); + if (!debugDrawSystem) + { + SHLOG_ERROR("Debug draw system unavailable! Colliders cannot be drawn!") + return; + } + + //SHPhysicsDebugDraw& physicsDebugRenderer = physicsSystem->debugRenderer; + + //if (!physicsDebugRenderer.GetDebugDrawState()) + // return; + + //// Draw colliders + //if (physicsDebugRenderer.GetDrawSpecificCollidersState()) + // physicsDebugRenderer.DrawSpecificColliders(debugDrawSystem); + //else if (physicsDebugRenderer.GetDrawAllCollidersState()) + // physicsDebugRenderer.DrawAllColliders(debugDrawSystem); + } +} diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index cd4b1cff..d5492cdf 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -15,6 +15,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Math/Transform/SHTransformComponent.h" #include "Scripting/SHScriptEngine.h" @@ -77,4 +78,5 @@ namespace SHADE if (scriptingSystem != nullptr) scriptingSystem->ExecuteCollisionFunctions(); } -} + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index d7bece3b..59cd68fb 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -19,7 +19,7 @@ #include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Physics/Interface/SHColliderComponent.h" namespace SHADE @@ -42,7 +42,7 @@ namespace SHADE eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_ON_EXIT_EVENT }; #ifdef SHEDITOR - eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT }; + eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT }; #endif } @@ -189,7 +189,7 @@ namespace SHADE physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->AddCollider(PHYSICS_OBJECT.collider); + physicsWorld->AddCollider(PHYSICS_OBJECT.collider); } #endif @@ -210,7 +210,7 @@ namespace SHADE physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); + physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); } delete physicsWorld; @@ -322,7 +322,7 @@ namespace SHADE physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->AddCollider(PHYSICS_OBJECT.collider); + physicsWorld->AddCollider(PHYSICS_OBJECT.collider); } return onEditorPlayEvent.get()->handle; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index 2a351e86..ca73df81 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -21,7 +21,6 @@ #include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/Interface/SHColliderComponent.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -95,7 +94,8 @@ namespace SHADE /** * @brief * The physics update that runs after the simulation. This sets the rendering - * transforms and sends messages to scripting system for collision & trigger events. + * transforms and sends messages to scripting system for collision & trigger events.
+ * */ class SH_API PhysicsPostUpdate final : public SHSystemRoutine { @@ -104,6 +104,21 @@ namespace SHADE void Execute(double dt) noexcept override; }; + #ifdef SHEDITOR + /** + * @brief + * If the editor is enabled, this routine invokes debug drawing for colliders. + * and collision information. + */ + class SH_API PhysicsDebugDraw final : public SHSystemRoutine + { + public: + PhysicsDebugDraw(); + void Execute(double dt) noexcept override; + }; + + #endif + private: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -125,7 +140,6 @@ namespace SHADE EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS]; // System data - bool worldUpdated; double interpolationFactor; double fixedDT; @@ -133,7 +147,6 @@ namespace SHADE // Sub-systems / managers SHPhysicsWorld* physicsWorld; - SHPhysicsObjectManager physicsObjectManager; /*---------------------------------------------------------------------------------*/ -- 2.40.1 From bf8a410fa2a933656b68d5df749010c18c5182ee Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 11 Dec 2022 20:33:30 +0800 Subject: [PATCH 08/84] Fixed bug where colliders were not properly deserialised --- .../Collision/CollisionShapes/SHCollisionShapeFactory.cpp | 3 +-- SHADE_Engine/src/Serialization/SHYAMLConverters.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp index 293d5c2a..d6ef5f0d 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp @@ -59,12 +59,11 @@ namespace SHADE case SHCollisionShape::Type::SPHERE: { SHSphereCollisionShape* sphere = spheres.find(shape->id)->second; + spheres.erase(shape->id); delete sphere; sphere = nullptr; - spheres.erase(shape->id); - break; } case SHCollisionShape::Type::CAPSULE: diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index cbbe8505..73b22fd6 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -237,8 +237,8 @@ namespace YAML switch (colliderType) { - case SHCollisionShape::Type::BOX: break; case SHCollisionShape::Type::SPHERE: collider->AddSphereCollisionShape(1.0f); break; + case SHCollisionShape::Type::BOX: break; case SHCollisionShape::Type::CAPSULE: break; default:; } -- 2.40.1 From 0cebedeee09f32c092966a9aba30e4da1a51616a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 11 Dec 2022 20:44:40 +0800 Subject: [PATCH 09/84] Fixed compile errors with merged scene init and exit events --- SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp | 4 ++-- SHADE_Engine/src/Scene/SHSceneManager.cpp | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 59cd68fb..388adadc 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -38,8 +38,8 @@ namespace SHADE eventFunctions[0] = { &SHPhysicsSystem::onComponentAdded , SH_COMPONENT_ADDED_EVENT }; eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT }; - eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_ON_INIT_EVENT }; - eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_ON_EXIT_EVENT }; + 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 }; diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index d3b84d6a..79e8818a 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -62,8 +62,6 @@ namespace SHADE SHEventManager::BroadcastEvent(exitEvent, SH_SCENE_EXIT_PRE); currentScene->Free(); - SHEventManager::BroadcastEvent(SHSceneExitEvent{ currentSceneID }, SH_SCENE_ON_EXIT_EVENT); - currentScene->Unload(); SHEntityManager::DestroyAllEntity(); @@ -112,8 +110,6 @@ namespace SHADE SHEventManager::BroadcastEvent(exitEvent, SH_SCENE_EXIT_PRE); currentScene->Free(); - SHEventManager::BroadcastEvent(SHSceneExitEvent{ currentSceneID }, SH_SCENE_ON_EXIT_EVENT); - if (cleanReload == true) { cleanReload = false; -- 2.40.1 From af3a5e7dc9313c5cbbc14123b3b8e533af715812 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 13 Dec 2022 03:54:37 +0800 Subject: [PATCH 10/84] Re-implemented Collider Debug Drawing --- Assets/Scenes/PhysicsSandbox.shade | 1 + .../src/Application/SBApplication.cpp | 7 +- .../Inspector/SHEditorComponentView.hpp | 3 +- SHADE_Engine/src/Events/SHEventDefines.h | 26 +-- .../src/Physics/Collision/SHCollider.cpp | 62 ++++--- .../src/Physics/Collision/SHCollider.h | 6 - .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 2 + .../Physics/Interface/SHColliderComponent.cpp | 19 ++- .../Physics/Interface/SHColliderComponent.h | 10 +- SHADE_Engine/src/Physics/SHPhysicsEvents.h | 10 +- .../Routines/SHPhysicsDebugDrawRoutine.cpp | 78 ++++++--- .../Routines/SHPhysicsPostUpdateRoutine.cpp | 1 - .../System/SHPhysicsDebugDrawSystem.cpp | 158 ++++++++++++++++++ .../Physics/System/SHPhysicsDebugDrawSystem.h | 150 +++++++++++++++++ .../src/Physics/System/SHPhysicsSystem.cpp | 3 +- .../src/Physics/System/SHPhysicsSystem.h | 33 ++-- .../src/Serialization/SHYAMLConverters.h | 8 + 17 files changed, 482 insertions(+), 95 deletions(-) create mode 100644 SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp create mode 100644 SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index f600c4ae..0005b35e 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -26,6 +26,7 @@ Freeze Rotation Z: false IsActive: true Collider Component: + DrawColliders: true Colliders: - Is Trigger: false Type: Sphere diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 3cb504c0..aa5a4f0e 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -31,6 +31,7 @@ #include "Input/SHInputManager.h" #include "Math/Transform/SHTransformSystem.h" #include "Physics/System/SHPhysicsSystem.h" +#include "Physics/System/SHPhysicsDebugDrawSystem.h" #include "Scripting/SHScriptEngine.h" #include "UI/SHUISystem.h" @@ -83,7 +84,6 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHGraphicsSystem* graphicsSystem = static_cast(SHSystemManager::GetSystem()); - SHPhysicsSystem* physicsSystem = SHSystemManager::GetSystem(); // Link up SHDebugDraw SHSystemManager::CreateSystem(); @@ -98,6 +98,8 @@ namespace Sandbox editor->SetSDLWindow(sdlWindow); editor->SetSHWindow(&window); } + + SHSystemManager::CreateSystem(); #endif // Create Routines @@ -111,8 +113,9 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + #ifdef SHEDITOR - SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); #endif SHSystemManager::RegisterRoutine(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index dfc89df1..dd531708 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -322,8 +322,7 @@ namespace SHADE { DrawContextMenu(component); - auto* collider = component->GetCollider(); - SHEditorWidgets::CheckBox("Draw Colliders", [collider] { return collider->GetDebugDrawState(); }, [collider](bool value) { collider->SetDebugDrawState(value); }); + SHEditorWidgets::CheckBox("Draw Colliders", [component] { return component->GetDebugDrawState(); }, [component](bool value) { component->SetDebugDrawState(value); }); auto* collisionShapes = component->GetCollisionShapes(); int const size = collisionShapes ? static_cast(collisionShapes->size()) : 0; diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index bdc4c505..2a45da1b 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -10,16 +10,18 @@ constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT { 1 }; constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 }; constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 }; constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 }; -constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 }; -constexpr SHEventIdentifier SH_SCENEGRAPH_ADD_CHILD_EVENT { 6 }; -constexpr SHEventIdentifier SH_SCENEGRAPH_REMOVE_CHILD_EVENT { 7 }; -constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 8 }; -constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 9 }; -constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 10 }; -constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 11 }; -constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 12 }; -constexpr SHEventIdentifier SH_SCENE_INIT_PRE { 13 }; -constexpr SHEventIdentifier SH_SCENE_INIT_POST { 14 }; -constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 }; -constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; +constexpr SHEventIdentifier SH_SCENE_INIT_PRE { 5 }; +constexpr SHEventIdentifier SH_SCENE_INIT_POST { 6 }; +constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 7 }; +constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 8 }; +constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 9 }; +constexpr SHEventIdentifier SH_SCENEGRAPH_ADD_CHILD_EVENT { 10 }; +constexpr SHEventIdentifier SH_SCENEGRAPH_REMOVE_CHILD_EVENT { 11 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 12 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 13 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_DRAW_EVENT { 14 }; +constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 15 }; +constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 16 }; +constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 17 }; + diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 1d29a585..b64bab53 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -14,7 +14,10 @@ #include "SHCollider.h" // Project Headers +#include "Events/SHEvent.h" #include "Math/SHMathHelpers.h" +#include "Physics/SHPhysicsEvents.h" + namespace SHADE { @@ -25,9 +28,7 @@ namespace SHADE SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept : entityID { eid } , shapeIDCounter { 0 } -#ifdef SHEDITOR , debugDraw { false } -#endif , rigidBody { nullptr } , shapeFactory { nullptr } , transform { worldTransform } @@ -38,9 +39,7 @@ namespace SHADE SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } -#ifdef SHEDITOR , debugDraw { rhs.debugDraw } -#endif , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -57,9 +56,7 @@ namespace SHADE SHCollider::SHCollider(SHCollider&& rhs) noexcept : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } -#ifdef SHEDITOR , debugDraw { rhs.debugDraw } -#endif , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -101,14 +98,11 @@ namespace SHADE } entityID = rhs.entityID; + debugDraw = rhs.debugDraw; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; - #ifdef SHEDITOR - debugDraw = rhs.debugDraw; - #endif - copyShapes(rhs); return *this; @@ -123,14 +117,11 @@ namespace SHADE } entityID = rhs.entityID; + debugDraw = rhs.debugDraw; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; - #ifdef SHEDITOR - debugDraw = rhs.debugDraw; - #endif - copyShapes(rhs); return *this; @@ -140,12 +131,10 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ -#ifdef SHEDITOR bool SHCollider::GetDebugDrawState() const noexcept { return debugDraw; } -#endif const SHTransform& SHCollider::GetTransform() const noexcept { @@ -186,12 +175,23 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ -#ifdef SHEDITOR void SHCollider::SetDebugDrawState(bool state) noexcept { debugDraw = state; + + #ifdef SHEDITOR + + // Broadcast event for the Debug Draw system to catch + const SHColliderOnDebugDrawEvent EVENT_DATA + { + .entityID = entityID + , .debugDrawState = debugDraw + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_DRAW_EVENT); + + #endif } -#endif void SHCollider::SetRigidBody(SHRigidBody* rb) noexcept { @@ -236,7 +236,7 @@ namespace SHADE { if (!shapeFactory) { - SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add new shape!", entityID) + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add new shape!", entityID) return -1; } @@ -266,6 +266,17 @@ namespace SHADE sphere->rotationOffset = rotOffset; shapes.emplace_back(sphere); + + // Broadcast Event for adding a shape + const SHPhysicsColliderAddedEvent EVENT_DATA + { + .entityID = entityID + , .colliderType = SHCollisionShape::Type::SPHERE + , .colliderIndex = static_cast(shapes.size()) + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + return static_cast(shapes.size()); } @@ -273,7 +284,7 @@ namespace SHADE { if (!shapeFactory) { - SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add remove shape!", entityID) + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add remove shape!", entityID) return; } @@ -289,12 +300,22 @@ namespace SHADE break; } + const SHPhysicsColliderRemovedEvent EVENT_DATA + { + .entityID = entityID + , .colliderType = (*shapeIter)->GetType() + , .colliderIndex = index + }; + shapeFactory->DestroyShape(*shapeIter); *shapeIter = nullptr; // Remove the shape from the container to prevent accessing a nullptr shapeIter = shapes.erase(shapeIter); + // Broadcast Event for removing a shape + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); + SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) } @@ -386,6 +407,7 @@ namespace SHADE const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(transform.position); const SHVec3 NEW_CENTER = SHVec3::Transform(sphere->positionOffset, TRS); + sphere->SetCenter(NEW_CENTER); } diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index cab433a5..927c6155 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -78,9 +78,7 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - #ifdef SHEDITOR [[nodiscard]] bool GetDebugDrawState () const noexcept; - #endif [[nodiscard]] const SHTransform& GetTransform () const noexcept; [[nodiscard]] const SHVec3& GetPosition () const noexcept; @@ -94,9 +92,7 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - #ifdef SHEDITOR void SetDebugDrawState (bool state) noexcept; - #endif void SetRigidBody (SHRigidBody* rb) noexcept; @@ -161,9 +157,7 @@ namespace SHADE EntityID entityID; uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. - #ifdef SHEDITOR bool debugDraw; - #endif SHRigidBody* rigidBody; SHCollisionShapeFactory* shapeFactory; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index e6c02168..7422d6ff 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -136,6 +136,8 @@ namespace SHADE { rigidBody.collider->SetPosition(rigidBody.motionState.position); // TODO: Sync orientations + + rigidBody.collider->RecomputeShapes(); } } diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index d345290c..7425f418 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -54,7 +54,14 @@ namespace SHADE return collider->GetCollisionShape(index); } + bool SHColliderComponent::GetDebugDrawState() const noexcept + { + if (!collider) + return false; + return collider->GetDebugDrawState(); + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -64,6 +71,13 @@ namespace SHADE collider = c; } + void SHColliderComponent::SetDebugDrawState(bool state) noexcept + { + if (collider) + collider->SetDebugDrawState(state); + } + + } // namespace SHADE RTTR_REGISTRATION @@ -71,5 +85,6 @@ RTTR_REGISTRATION using namespace rttr; using namespace SHADE; - registration::class_("Collider Component"); -} \ No newline at end of file + registration::class_("Collider Component") + .property("Is Debug Drawing", &SHColliderComponent::GetDebugDrawState, &SHColliderComponent::SetDebugDrawState); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index 83fb235c..d62b9b90 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -58,11 +58,19 @@ namespace SHADE [[nodiscard]] const SHCollider::CollisionShapes* const GetCollisionShapes() const noexcept; [[nodiscard]] SHCollisionShape* const GetCollisionShape (int index) const; + // Required for serialisation + + [[nodiscard]] bool GetDebugDrawState () const noexcept; + /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCollider(SHCollider* c) noexcept; + void SetCollider (SHCollider* c) noexcept; + + // Required for serialisation + + void SetDebugDrawState (bool state) noexcept; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/SHPhysicsEvents.h b/SHADE_Engine/src/Physics/SHPhysicsEvents.h index 35217347..2f78b6ee 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsEvents.h +++ b/SHADE_Engine/src/Physics/SHPhysicsEvents.h @@ -13,7 +13,6 @@ // Project Headers #include "Collision/CollisionShapes/SHCollisionShape.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -28,9 +27,16 @@ namespace SHADE }; struct SHPhysicsColliderRemovedEvent + { + EntityID entityID; + SHCollisionShape::Type colliderType; + int colliderIndex; + }; + + struct SHColliderOnDebugDrawEvent { EntityID entityID; - int colliderIndex; + bool debugDrawState; }; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index c73e8ab7..72b2aad5 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHPhysicsDebugDrawRoutine.cpp + * \file SHPhysicsDebugDrawRutine.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for the Physics Debug-Draw Routine + * \brief Implementation for the Physics Debut Draw Routine * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -11,14 +11,13 @@ #include // Primary Header -#include "Physics/System/SHPhysicsSystem.h" +#include "Physics/System/SHPhysicsDebugDrawSystem.h" // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" - -#include "Scripting/SHScriptEngine.h" - +#include "Math/Transform/SHTransformComponent.h" +#include "Physics/System/SHPhysicsSystem.h" namespace SHADE { @@ -26,35 +25,64 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsSystem::PhysicsDebugDraw::PhysicsDebugDraw() - : SHSystemRoutine { "Physics Debug Draw", false } + SHPhysicsDebugDrawSystem::PhysicsDebugDraw::PhysicsDebugDraw() + : SHSystemRoutine { "Physics Debug-Draw", true } {} /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsSystem::PhysicsDebugDraw::Execute(double) noexcept + void SHPhysicsDebugDrawSystem::PhysicsDebugDraw::Execute(double) noexcept { - auto* physicsSystem = reinterpret_cast(GetSystem()); - - // Get debug drawing system - auto* debugDrawSystem = SHSystemManager::GetSystem(); - if (!debugDrawSystem) - { - SHLOG_ERROR("Debug draw system unavailable! Colliders cannot be drawn!") + auto* physicsDebugDrawSystem = reinterpret_cast(GetSystem()); + + if (!physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::ACTIVE)) return; + + auto* physicsSystem = SHSystemManager::GetSystem(); + auto* debugDrawSystem = SHSystemManager::GetSystem(); + + const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS); + const bool DRAW_CONTACTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::CONTACTS); + const bool DRAW_RAYCASTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::RAYCASTS); + const bool DRAW_BROADPHASE = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::BROADPHASE); + + // If draw all colliders is active, get all colliders from the dense set and draw. + // Else we check if any colliders have been flagged for drawing. + if (DRAW_COLLIDERS) + { + const auto& COLLIDER_COMPONENT_DENSE = SHComponentManager::GetDense(); + for (const auto& COLLIDER_COMPONENT : COLLIDER_COMPONENT_DENSE) + { + const auto* COLLIDER = COLLIDER_COMPONENT.GetCollider(); + drawCollider(debugDrawSystem, *COLLIDER); + } + } + else if (!physicsDebugDrawSystem->collidersToDraw.empty()) + { + for (const auto EID : physicsDebugDrawSystem->collidersToDraw) + { + const auto* COLLIDER = SHComponentManager::GetComponent(EID)->GetCollider(); + drawCollider(debugDrawSystem, *COLLIDER); + } } - //SHPhysicsDebugDraw& physicsDebugRenderer = physicsSystem->debugRenderer; + if (DRAW_CONTACTS) + { + // TODO + } - //if (!physicsDebugRenderer.GetDebugDrawState()) - // return; + if (DRAW_RAYCASTS) + { + // TODO + physicsDebugDrawSystem->raysToDraw.clear(); + } - //// Draw colliders - //if (physicsDebugRenderer.GetDrawSpecificCollidersState()) - // physicsDebugRenderer.DrawSpecificColliders(debugDrawSystem); - //else if (physicsDebugRenderer.GetDrawAllCollidersState()) - // physicsDebugRenderer.DrawAllColliders(debugDrawSystem); + if (DRAW_BROADPHASE) + { + // TODO + } } -} + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index d5492cdf..8e7450ce 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -15,7 +15,6 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" -#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Math/Transform/SHTransformComponent.h" #include "Scripting/SHScriptEngine.h" diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp new file mode 100644 index 00000000..77241ae9 --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -0,0 +1,158 @@ +/**************************************************************************************** + * \file SHPhysicsDebugDrawSystem.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics Debug Draw System + * + * \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 + +// Primary Header +#include "SHPhysicsDebugDrawSystem.h" + +// Project Header +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Physics/SHPhysicsEvents.h" +#include "Tools/Utilities/SHUtilities.h" + +namespace SHADE +{ + const SHColour SHPhysicsDebugDrawSystem::DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::COUNT)] + { + SHColour::GREEN // Colliders + , SHColour::PURPLE // Triggers + , SHColour::RED // Contacts + , SHColour::ORANGE // Raycasts + , SHColour::CYAN // Broadphase + }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept + : flags { 0 } + { + collidersToDraw.clear(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHPhysicsDebugDrawSystem::GetFlagState(DebugDrawFlags flag) const noexcept + { + const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); + return flags & ENUM_VALUE; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsDebugDrawSystem::SetFlagState(DebugDrawFlags flag, bool state) noexcept + { + const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); + state ? flags |= ENUM_VALUE : flags &= ~ENUM_VALUE; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsDebugDrawSystem::Init() + { + SystemFamily::GetID(); + + // Register collider draw event + const std::shared_ptr EVENT_RECEIVER = std::make_shared>(this, &SHPhysicsDebugDrawSystem::onColliderDraw); + const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast(EVENT_RECEIVER); + + SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_DRAW_EVENT, EVENT_RECEIVER_PTR); + } + + void SHPhysicsDebugDrawSystem::Exit() + { + + } + + void SHPhysicsDebugDrawSystem::AddRaycast(const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept + { + + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHEventHandle SHPhysicsDebugDrawSystem::onColliderDraw(SHEventPtr onColliderDrawEvent) + { + const auto& EVENT_DATA = reinterpret_cast*>(onColliderDrawEvent.get())->data; + + if (EVENT_DATA->debugDrawState) + { + if (collidersToDraw.empty()) + SetFlagState(DebugDrawFlags::ACTIVE, true); + + collidersToDraw.emplace(EVENT_DATA->entityID); + } + else + { + collidersToDraw.erase(EVENT_DATA->entityID); + + if (collidersToDraw.empty()) + SetFlagState(DebugDrawFlags::ACTIVE, false); + } + + return onColliderDrawEvent.get()->handle; + } + + void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept + { + for (const auto* SHAPE : collider.GetCollisionShapes()) + { + switch (SHAPE->GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + const SHSphereCollisionShape* SPHERE = dynamic_cast(SHAPE); + drawSphere(debugDrawSystem, *SPHERE); + + break; + } + case SHCollisionShape::Type::BOX: + { + break; + } + case SHCollisionShape::Type::CAPSULE: + { + break; + } + default: break; + } + } + } + + void SHPhysicsDebugDrawSystem::drawSphere(SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere) noexcept + { + const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(sphere.IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)]; + debugDrawSystem->DrawSphere(DRAW_COLOUR, sphere.GetCenter(), sphere.GetWorldRadius()); + } + + void SHPhysicsDebugDrawSystem::drawContact(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept + { + static const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)]; + } + + void SHPhysicsDebugDrawSystem::drawRaycast(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept + { + static const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)]; + } + + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h new file mode 100644 index 00000000..423ab62a --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -0,0 +1,150 @@ +/**************************************************************************************** + * \file SHPhysicsDebugDrawSystem.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the Physics Debug Draw System + * + * \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 + +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" +#include "ECS_Base/System/SHSystem.h" +#include "ECS_Base/System/SHSystemRoutine.h" +#include "Events/SHEvent.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" +#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHPhysicsRaycastResult.h" +#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHPhysicsDebugDrawSystem final : public SHSystem + { + public: + + enum class DebugDrawFlags : uint8_t + { + ACTIVE = 0x0001 + , COLLIDERS = 0x0002 + , CONTACTS = 0x0004 + , RAYCASTS = 0x0008 + , BROADPHASE = 0x0010 + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsDebugDrawSystem () noexcept; + ~SHPhysicsDebugDrawSystem() noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetFlagState (DebugDrawFlags flag, bool state) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void Init () override; + void Exit () override; + + void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* System Routines */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * If the editor is enabled, this routine invokes debug drawing for colliders and collision information. + */ + class SH_API PhysicsDebugDraw final : public SHSystemRoutine + { + public: + PhysicsDebugDraw(); + void Execute(double dt) noexcept override; + }; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + union DebugDrawInfo + { + struct Contact + { + SHVec3 worldPos; + SHVec3 normal; + } contact; + + struct Raycast + { + SHVec3 start; + SHVec3 end; + } raycast; + }; + + using Colliders = std::unordered_set; + using Raycasts = std::vector; + using Contacts = std::vector; + + enum class Colours + { + COLLIDER + , TRIGGER + , CONTACT + , RAYCAST + , BROADPHASE + + , COUNT + }; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static const SHColour DEBUG_DRAW_COLOURS[static_cast(Colours::COUNT)]; + + // 0 0 0 drawBroadphase drawRaycasts drawContacts drawAllColliders debugDrawActive + uint8_t flags; + + Colliders collidersToDraw; + Raycasts raysToDraw; + Contacts contactToDraw; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); + + static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; + static void drawSphere (SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere) noexcept; + + static void drawContact (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept; + static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; + + }; + + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 388adadc..20084ebe 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -110,13 +110,12 @@ namespace SHADE void SHPhysicsSystem::Init() { + // TODO(Diren): Consider using a non-static collision tag matrix. // Initialise collision tags std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath); - // Link Managers to system - // Register Events for (int i = 0; i < NUM_EVENT_FUNCTIONS; ++i) { diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index ca73df81..ce1f1396 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -27,6 +27,10 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates a system for running and managing the physics simulation of the engine. + */ class SH_API SHPhysicsSystem final : public SHSystem { public: @@ -41,23 +45,27 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] double GetFixedUpdateRate() const noexcept; - [[nodiscard]] double GetFixedDT() const noexcept; + [[nodiscard]] double GetFixedUpdateRate() const noexcept; + [[nodiscard]] double GetFixedDT() const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ void SetFixedUpdateRate(double fixedUpdateRate) noexcept; - void SetFixedDT(double fixedDt) noexcept; + void SetFixedDT(double fixedDt) noexcept; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Member Functions */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * - Initialises the static collision tag matrix. + * - Registers the system to catch specific events. + */ void Init() override; void Exit() override; - void ForceUpdate(); /*---------------------------------------------------------------------------------*/ @@ -104,21 +112,6 @@ namespace SHADE void Execute(double dt) noexcept override; }; - #ifdef SHEDITOR - /** - * @brief - * If the editor is enabled, this routine invokes debug drawing for colliders. - * and collision information. - */ - class SH_API PhysicsDebugDraw final : public SHSystemRoutine - { - public: - PhysicsDebugDraw(); - void Execute(double dt) noexcept override; - }; - - #endif - private: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 73b22fd6..b225a9a4 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -204,10 +204,15 @@ namespace YAML template<> struct convert { + static constexpr const char* DrawColliders = "DrawColliders"; static constexpr const char* Colliders = "Colliders"; + static Node encode(SHColliderComponent& rhs) { Node node, collidersNode; + + node[DrawColliders] = rhs.GetDebugDrawState(); + int const numColliders = static_cast(rhs.GetCollisionShapes()->size()); for (int i = 0; i < numColliders; ++i) { @@ -221,6 +226,9 @@ namespace YAML } static bool decode(Node const& node, SHColliderComponent& rhs) { + if (node[DrawColliders].IsDefined()) + rhs.SetDebugDrawState(node[DrawColliders].as()); + if (node[Colliders].IsDefined()) { int numColliders{}; -- 2.40.1 From 53edffebac0e69feaf190ab2594ed16be07b04fc Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 15 Dec 2022 02:08:25 +0800 Subject: [PATCH 11/84] Added (untested) rotational motion to rigidbodies Also added a temporary solution for debug drawing rotated spheres --- .../Inspector/SHEditorComponentView.hpp | 9 +- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 12 +- .../MiddleEnd/Interface/SHDebugDrawSystem.h | 5 +- .../CollisionShapes/SHCollisionShape.h | 6 + .../SHSphereCollisionShape.cpp | 15 ++ .../CollisionShapes/SHSphereCollisionShape.h | 16 +- .../src/Physics/Dynamics/SHMotionState.cpp | 31 +++ .../src/Physics/Dynamics/SHMotionState.h | 50 ++++- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 23 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 206 +++++++++++++++--- .../src/Physics/Dynamics/SHRigidBody.h | 74 ++++++- .../Interface/SHRigidBodyComponent.cpp | 144 ++++++------ .../Physics/Interface/SHRigidBodyComponent.h | 2 +- .../Routines/SHPhysicsPostUpdateRoutine.cpp | 18 +- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 2 +- .../System/SHPhysicsDebugDrawSystem.cpp | 9 +- .../Physics/System/SHPhysicsDebugDrawSystem.h | 4 +- SHADE_Engine/src/Tools/SHDebugDraw.cpp | 2 +- SHADE_Managed/src/Components/RigidBody.cxx | 6 - SHADE_Managed/src/Components/RigidBody.hxx | 1 - 20 files changed, 468 insertions(+), 167 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index dd531708..2bbc0305 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -286,7 +286,14 @@ namespace SHADE if(ImGui::CollapsingHeader("Debug Information", ImGuiTreeNodeFlags_DefaultOpen))//Dynamic or Kinematic only fields { SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component] {return component->GetPosition(); }, [](SHVec3 const& value) {}, false, "Position", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); - //SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, [component] {return component->GetRotation(); }, [](SHVec3 const& value) {}, false, "Rotation", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); + SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, [component] + { + // Convert it to degrees... + auto rot = component->GetRotation(); + for (size_t i = 0; i < SHVec3::SIZE; ++i) + rot[i] = SHMath::RadiansToDegrees(rot[i]); + return rot; + }, [](SHVec3 const& value) {}, false, "Rotation", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { SHEditorWidgets::DragVec3("Velocity", { "X", "Y", "Z" }, [component] {return component->GetLinearVelocity(); }, [](SHVec3 const& value) {}, false, "Linear Velocity", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index 0bfa89a2..215c7fdb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -203,9 +203,9 @@ namespace SHADE drawCube(points, color, pos, size); } - void SHDebugDrawSystem::DrawSphere(const SHVec4& color, const SHVec3& pos, double radius) + void SHDebugDrawSystem::DrawSphere(const SHVec4& color, const SHVec3& pos, const SHVec3& rot, double radius) { - drawSphere(points, color, pos, radius); + drawSphere(points, color, pos, rot, radius); } /*---------------------------------------------------------------------------------*/ @@ -238,7 +238,7 @@ namespace SHADE void SHDebugDrawSystem::DrawPersistentSphere(const SHVec4& color, const SHVec3& pos, double radius) { - drawSphere(persistentPoints, color, pos, radius); + drawSphere(persistentPoints, color, pos, SHVec3::Zero, radius); } void SHDebugDrawSystem::ClearPersistentDraws() @@ -315,7 +315,7 @@ namespace SHADE ); } - void SHDebugDrawSystem::drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, double radius) + void SHDebugDrawSystem::drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& rot, double radius) { //if (spherePoints.empty()) { @@ -324,7 +324,9 @@ namespace SHADE static const SHMeshData SPHERE = SHPrimitiveGenerator::Sphere(); for (const auto& idx : SPHERE.Indices) { - spherePoints.emplace_back(SPHERE.VertexPositions[idx] * radius + pos); + SHVec3 SCALE { static_cast(radius) }; + const SHMatrix TRS = SHMatrix::Transform(pos, rot, { static_cast(radius) }); + spherePoints.emplace_back(SHVec3::Transform(SPHERE.VertexPositions[idx], TRS)); } } drawLineSet(storage, color, spherePoints.begin(), spherePoints.end()); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h index 20ddcd42..f974ed9d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h @@ -123,8 +123,9 @@ namespace SHADE /// /// Colour of the sphere. /// Position where the sphere wil be centered at. + /// Rotation of the sphere. /// Size of the rendered sphere. - void DrawSphere(const SHVec4& color, const SHVec3& pos, double radius); + void DrawSphere(const SHVec4& color, const SHVec3& pos, const SHVec3& rot, double radius); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ @@ -246,7 +247,7 @@ namespace SHADE template void drawPoly(std::vector& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd); void drawCube(std::vector& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& size); - void drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, double radius); + void drawSphere(std::vector& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& rot, double radius); }; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index c05baddd..6a08f940 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -111,6 +111,12 @@ namespace SHADE void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + protected: /*---------------------------------------------------------------------------------*/ /* Data Members */ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index 3f79b381..40671a96 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -13,6 +13,9 @@ // Primary Header #include "SHSphereCollisionShape.h" +// Project Headers +#include "Math/SHMatrix.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -179,5 +182,17 @@ namespace SHADE return SHSphere::Raycast(ray); } + SHMatrix SHSphereCollisionShape::GetInertiaTensor(float mass) const noexcept + { + static constexpr float TWO_OVER_FIVE = 2.0f / 5.0f; + + const float DIAGONAL = TWO_OVER_FIVE * mass * (Radius * Radius); + + SHMatrix result; + result.m[0][0] = result.m[1][1] = result.m[2][2] = DIAGONAL; + return result; + } + + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 0a8c0321..72ea05f5 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -96,7 +96,7 @@ namespace SHADE * @return * True if the point is inside the sphere. */ - bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; /** * @brief @@ -107,9 +107,19 @@ namespace SHADE * An object holding the results of the raycast.
* See the corresponding header for the contents of the object. */ - SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; - // TODO: Compute Moment of Inertia + /** + * @brief + * Computes the inertia tensor of the sphere. + * @param mass + * The mass of the sphere. + * @return + * The inertia tensor of the sphere. + */ + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; + + private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp index 91b5a688..cc014050 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp @@ -80,6 +80,15 @@ namespace SHADE position = newPosition; } + void SHMotionState::ForceOrientation(const SHQuaternion& newOrientation) noexcept + { + hasMoved = true; + + prevOrientation = newOrientation; + orientation = newOrientation; + } + + void SHMotionState::IntegratePosition(const SHVec3& velocity, float dt) noexcept { // Velocities are 0 when objects are static or sleeping. We do not want to integrate them here. @@ -91,10 +100,32 @@ namespace SHADE position += velocity * dt; } + void SHMotionState::IntegrateOrientation(const SHVec3& velocity, float dt) noexcept + { + // Velocities are 0 when objects are static or sleeping. We do not want to integrate them here. + // This call should never reach here. + + hasMoved = true; + + prevOrientation = orientation; + + SHQuaternion qv{ velocity.x * dt, velocity.y * dt, velocity.z * dt, 0.0f }; + qv *= orientation; + + orientation += qv * 0.5f; + orientation = SHQuaternion::Normalise(orientation); + } + + SHVec3 SHMotionState::InterpolatePositions(float factor) const noexcept { return SHVec3::ClampedLerp(prevPosition, position, factor); } + SHQuaternion SHMotionState::InterpolateOrientations(float factor) const noexcept + { + return SHQuaternion::ClampedSlerp(prevOrientation, orientation, factor); + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h index 4cff9a8f..778e6a8b 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h @@ -11,8 +11,10 @@ #pragma once // Project Headers +#include "Math/SHQuaternion.h" #include "Math/Vector/SHVec3.h" + namespace SHADE { /*-------------------------------------------------------------------------------------*/ @@ -30,10 +32,13 @@ namespace SHADE /* Data Members */ /*-----------------------------------------------------------------------------------*/ - bool hasMoved; + bool hasMoved; - SHVec3 position; - SHVec3 prevPosition; + SHVec3 position; + SHVec3 prevPosition; + + SHQuaternion orientation; + SHQuaternion prevOrientation; /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -65,17 +70,36 @@ namespace SHADE * @param newPosition * The new position to set. */ - void ForcePosition (const SHVec3& newPosition) noexcept; + void ForcePosition (const SHVec3& newPosition) noexcept; /** * @brief - * Integrates the positions using velocity with respect to time. + * Forcefully sets the orientation. Meant to be used when transform overrides the rigid body + * orientations + * @param newOrientation + * The new orientation to set. + */ + void ForceOrientation (const SHQuaternion& newOrientation) noexcept; + + /** + * @brief + * Integrates the positions using linear velocity with respect to time. * @param velocity - * The velocity to integrate. + * The linear velocity to integrate. * @param dt * The delta time to integrate with respect to. */ - void IntegratePosition (const SHVec3& velocity, float dt) noexcept; + void IntegratePosition (const SHVec3& velocity, float dt) noexcept; + + /** + * @brief + * Integrates the orientation using angular velocity with respect to time. + * @param velocity + * The angular velocity to integrate. + * @param dt + * The delta time to integrate with respect to. + */ + void IntegrateOrientation (const SHVec3& velocity, float dt) noexcept; /** * @brief @@ -85,7 +109,17 @@ namespace SHADE * @returns * The interpolated position meant for rendering. */ - SHVec3 InterpolatePositions (float factor) const noexcept; + SHVec3 InterpolatePositions (float factor) const noexcept; + + /** + * @brief + * Interpolates the orientation between the previous and the last using a given factor. + * @param factor + * The factor to interpolate by. Should be between 0 & 1. + * @returns + * The interpolated orientation meant for rendering. + */ + SHQuaternion InterpolateOrientations (float factor) const noexcept; }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 7422d6ff..b1b94792 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -74,7 +74,10 @@ namespace SHADE void SHPhysicsWorld::Step(float dt) { for (auto* rigidBody : rigidBodies) + { + rigidBody->ComputeWorldData(); integrateForces(*rigidBody, dt); + } for (auto* rigidBody : rigidBodies) integrateVelocities(*rigidBody, dt); @@ -93,10 +96,14 @@ namespace SHADE const SHVec3 LINEAR_ACCELERATION = rigidBody.accumulatedForce * rigidBody.invMass; const SHVec3 GRAVITATIONAL_ACCELERATION = rigidBody.IsGravityEnabled() ? settings.gravity * rigidBody.gravityScale : SHVec3::Zero; - rigidBody.linearVelocity += (LINEAR_ACCELERATION + GRAVITATIONAL_ACCELERATION) * dt; + rigidBody.linearVelocity += (LINEAR_ACCELERATION + GRAVITATIONAL_ACCELERATION) * dt; + + // Integrate torque into angular velocity + rigidBody.angularVelocity += rigidBody.worldInvInertia * (rigidBody.accumulatedTorque * dt); // Apply drag (exponentially applied) - rigidBody.linearVelocity *= 1.0f / (1.0f + dt * rigidBody.linearDrag); + rigidBody.linearVelocity *= 1.0f / (1.0f + dt * rigidBody.linearDrag); + rigidBody.angularVelocity *= 1.0f / (1.0f + dt * rigidBody.angularDrag); } void SHPhysicsWorld::integrateVelocities(SHRigidBody& rigidBody, float dt) const noexcept @@ -111,7 +118,13 @@ namespace SHADE , rigidBody.GetFreezePositionZ() ? 0.0f : rigidBody.linearVelocity.z }; - // TODO: Enforce angular constraints + // Enforce angular constraints + rigidBody.angularVelocity = SHVec3 + { + rigidBody.GetFreezeRotationX() ? 0.0f : rigidBody.angularVelocity.x + , rigidBody.GetFreezeRotationY() ? 0.0f : rigidBody.angularVelocity.y + , rigidBody.GetFreezeRotationZ() ? 0.0f : rigidBody.angularVelocity.z + }; }; // Always reset movement flag @@ -129,13 +142,13 @@ namespace SHADE ENFORCE_CONSTRAINED_VELOCITIES(rigidBody); rigidBody.motionState.IntegratePosition(rigidBody.linearVelocity, dt); - // TODO: Integrate orientations + rigidBody.motionState.IntegrateOrientation(rigidBody.angularVelocity, dt); // Sync with collider transforms if a collider is present if (rigidBody.collider) { rigidBody.collider->SetPosition(rigidBody.motionState.position); - // TODO: Sync orientations + rigidBody.collider->SetOrientation(rigidBody.motionState.orientation); rigidBody.collider->RecomputeShapes(); } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index e79a8c91..c9f3b097 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -27,9 +27,10 @@ namespace SHADE : entityID { eid } , collider { nullptr } , bodyType { type } + , gravityScale { 1.0f } , invMass { type == Type::DYNAMIC ? 1.0f : 0.0f } , linearDrag { 0.01f } - , gravityScale { 1.0f } + , angularDrag { 0.01f } , flags { 0U } { // Set default flags @@ -41,14 +42,19 @@ namespace SHADE } SHRigidBody::SHRigidBody(const SHRigidBody& rhs) noexcept - : entityID { rhs.entityID } - , collider { nullptr } - , bodyType { rhs.bodyType } - , invMass { rhs.invMass } - , linearDrag { rhs.linearDrag } - , gravityScale { rhs.gravityScale } - , flags { rhs.flags } - , motionState { rhs.motionState } + : entityID { rhs.entityID } + , collider { nullptr } + , bodyType { rhs.bodyType } + , gravityScale { rhs.gravityScale } + , invMass { rhs.invMass } + , linearDrag { rhs.linearDrag } + , angularDrag { rhs.angularDrag } + , localInvInertia { rhs.localInvInertia } + , worldInvInertia { rhs.worldInvInertia } + , localCentroid { rhs.localCentroid } + , worldCentroid { rhs.worldCentroid } + , flags { rhs.flags } + , motionState { rhs.motionState } { // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. } @@ -57,9 +63,14 @@ namespace SHADE : entityID { rhs.entityID } , collider { nullptr } , bodyType { rhs.bodyType } + , gravityScale { rhs.gravityScale } , invMass { rhs.invMass } , linearDrag { rhs.linearDrag } - , gravityScale { rhs.gravityScale } + , angularDrag { rhs.angularDrag } + , localInvInertia { rhs.localInvInertia } + , worldInvInertia { rhs.worldInvInertia } + , localCentroid { rhs.localCentroid } + , worldCentroid { rhs.worldCentroid } , flags { rhs.flags } , motionState { std::move(rhs.motionState) } { @@ -77,17 +88,24 @@ namespace SHADE return *this; entityID = rhs.entityID; + // Deep copy the collider - *collider = *rhs.collider; - bodyType = rhs.bodyType; - invMass = rhs.invMass; - linearDrag = rhs.linearDrag; - gravityScale = rhs.gravityScale; - flags = rhs.flags; - motionState = rhs.motionState; + *collider = *rhs.collider; + bodyType = rhs.bodyType; + gravityScale = rhs.gravityScale; + invMass = rhs.invMass; + linearDrag = rhs.linearDrag; + angularDrag = rhs.angularDrag; + localInvInertia = rhs.localInvInertia; + worldInvInertia = rhs.worldInvInertia; + localCentroid = rhs.localCentroid; + worldCentroid = rhs.worldCentroid; + flags = rhs.flags; + motionState = rhs.motionState; // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. accumulatedForce = SHVec3::Zero; + accumulatedTorque = SHVec3::Zero; linearVelocity = SHVec3::Zero; angularVelocity = SHVec3::Zero; @@ -97,17 +115,24 @@ namespace SHADE SHRigidBody& SHRigidBody::operator=(SHRigidBody&& rhs) noexcept { entityID = rhs.entityID; + // Deep copy the collider *collider = *rhs.collider; bodyType = rhs.bodyType; + gravityScale = rhs.gravityScale; invMass = rhs.invMass; linearDrag = rhs.linearDrag; - gravityScale = rhs.gravityScale; + angularDrag = rhs.angularDrag; + localInvInertia = rhs.localInvInertia; + worldInvInertia = rhs.worldInvInertia; + localCentroid = rhs.localCentroid; + worldCentroid = rhs.worldCentroid; flags = rhs.flags; motionState = std::move(rhs.motionState); // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. accumulatedForce = SHVec3::Zero; + accumulatedTorque = SHVec3::Zero; linearVelocity = SHVec3::Zero; angularVelocity = SHVec3::Zero; @@ -123,6 +148,11 @@ namespace SHADE return bodyType; } + float SHRigidBody::GetGravityScale() const noexcept + { + return gravityScale; + } + float SHRigidBody::GetMass() const noexcept { return 1.0f/ invMass; @@ -133,16 +163,41 @@ namespace SHADE return linearDrag; } - float SHRigidBody::GetGravityScale() const noexcept + float SHRigidBody::GetAngularDrag() const noexcept { - return gravityScale; + return angularDrag; } - const SHVec3& SHRigidBody::GetAccumulatedForce() const noexcept + const SHMatrix& SHRigidBody::GetLocalInvInertia() const noexcept + { + return localInvInertia; + } + + const SHMatrix& SHRigidBody::GetWorldInvInertia() const noexcept + { + return worldInvInertia; + } + + const SHVec3& SHRigidBody::GetLocalCentroid() const noexcept + { + return localCentroid; + } + + const SHVec3& SHRigidBody::GetWorldCentroid() const noexcept + { + return worldCentroid; + } + + const SHVec3& SHRigidBody::GetForce() const noexcept { return accumulatedForce; } + const SHVec3& SHRigidBody::GetTorque() const noexcept + { + return accumulatedTorque; + } + const SHVec3& SHRigidBody::GetLinearVelocity() const noexcept { return linearVelocity; @@ -226,7 +281,6 @@ namespace SHADE return motionState; } - /*-----------------------------------------------------------------------------------*/ /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -245,6 +299,11 @@ namespace SHADE invMass = newType == Type::DYNAMIC ? 1.0f : 0.0f; } + void SHRigidBody::SetGravityScale(float newGravityScale) noexcept + { + gravityScale = newGravityScale; + } + void SHRigidBody::SetMass(float newMass) noexcept { if (bodyType != Type::DYNAMIC) @@ -261,7 +320,7 @@ namespace SHADE invMass = 1.0f / newMass; - // TODO: Recompute inertia tensor + ComputeMassData(); } void SHRigidBody::SetLinearDrag(float newLinearDrag) noexcept @@ -281,16 +340,45 @@ namespace SHADE linearDrag = newLinearDrag; } - void SHRigidBody::SetGravityScale(float newGravityScale) noexcept + void SHRigidBody::SetAngularDrag(float newAngularDrag) noexcept { - gravityScale = newGravityScale; + if (bodyType == Type::STATIC) + { + SHLOG_WARNING("Cannot set angular drag of a Static Body {}", entityID) + return; + } + + if (newAngularDrag < 0.0f) + { + SHLOG_WARNING("Cannot set drag below 0. Object {}'s angular drag will remain unchanged.", entityID) + return; + } + + angularDrag = newAngularDrag; } void SHRigidBody::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { + if (bodyType == Type::STATIC) + { + SHLOG_WARNING("Cannot set linear velocity of a Static Body {}", entityID) + return; + } + linearVelocity = newLinearVelocity; } + void SHRigidBody::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept + { + if (bodyType == Type::STATIC) + { + SHLOG_WARNING("Cannot set angular velocity of a Static Body {}", entityID) + return; + } + + angularVelocity = newAngularVelocity; + } + void SHRigidBody::SetIsActive(bool isActive) noexcept { static constexpr unsigned int FLAG_POS = 0; @@ -304,7 +392,18 @@ namespace SHADE static constexpr unsigned int FLAG_POS = 1; static constexpr uint16_t VALUE = 1U << FLAG_POS; - isSleeping ? flags |= VALUE : flags &= ~VALUE; + if (isSleeping) + { + flags |= VALUE; + + ClearForces(); + linearVelocity = SHVec3::Zero; + angularVelocity = SHVec3::Zero; + } + else + { + flags &= ~VALUE; + } } void SHRigidBody::SetSleepingEnabled(bool enableSleeping) noexcept @@ -411,6 +510,8 @@ namespace SHADE flags |= VALUE; // Reset angular velocity along X-axis angularVelocity.x = 0.0f; + // Set inertia tensor on the x-axis to 0 + localInvInertia.m[0][0] = worldInvInertia.m[0][0] = 0.0f; } else { @@ -428,6 +529,8 @@ namespace SHADE flags |= VALUE; // Reset angular velocity along Y-axis angularVelocity.y = 0.0f; + // Set inertia tensor on the y-axis to 0 + localInvInertia.m[1][1] = worldInvInertia.m[1][1] = 0.0f; } else { @@ -445,6 +548,8 @@ namespace SHADE flags |= VALUE; // Reset angular velocity along Z-axis angularVelocity.z = 0.0f; + // Set inertia tensor on the z-axis to 0 + localInvInertia.m[2][2] = worldInvInertia.m[2][2] = 0.0f; } else { @@ -461,21 +566,60 @@ namespace SHADE if (bodyType != Type::DYNAMIC) return; - accumulatedForce += force; - // Compute torque when force is offset + accumulatedForce += force; + accumulatedTorque += SHVec3::Cross(pos, force); } void SHRigidBody::AddImpulse(const SHVec3& impulse, const SHVec3& pos) noexcept { if (bodyType != Type::DYNAMIC) - return; + return; - linearVelocity += impulse * invMass; + linearVelocity += impulse * invMass; + angularVelocity += worldInvInertia * SHVec3::Cross(pos, impulse); + } + + void SHRigidBody::AddTorque(const SHVec3& torque) noexcept + { + if (bodyType != Type::DYNAMIC) + return; + + accumulatedTorque += torque; } void SHRigidBody::ClearForces() noexcept { - accumulatedForce = SHVec3::Zero; + accumulatedForce = SHVec3::Zero; + accumulatedTorque = SHVec3::Zero; + } + + void SHRigidBody::ComputeWorldData() noexcept + { + const SHMatrix ROTATION = SHMatrix::Rotate(motionState.orientation); + + // Compute world inertia + worldInvInertia = ROTATION * localInvInertia * SHMatrix::Transpose(ROTATION); + + // Compute world centroid + worldCentroid = (ROTATION * localCentroid) + motionState.position; + } + + void SHRigidBody::ComputeMassData() noexcept + { + // TODO: Compute total inertia and centroid from composited colliders using the Parallel Axis Theorem. + // TODO: If auto mass in enabled, compute total mass based from each collider. + // TODO: If auto mass disabled, compute inertia tensor for each shape using the ratio of its mass / total mass by comparing the volume / total volume. + + if (collider && !collider->GetCollisionShapes().empty()) + { + // HACK: For now, take only the first shape as we are testing with non-composited colliders. We are using the center as the centroid. + const auto* FIRST_SHAPE = collider->GetCollisionShape(0); + localInvInertia = SHMatrix::Inverse(FIRST_SHAPE->GetInertiaTensor(1.0f / invMass)); + } + else + { + localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = invMass; + } } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 1edf5cf6..0d1457d9 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -12,6 +12,7 @@ // Project Headers #include "ECS_Base/Entity/SHEntity.h" +#include "Math/SHMatrix.h" #include "Math/Vector/SHVec3.h" #include "SHMotionState.h" @@ -73,12 +74,20 @@ namespace SHADE [[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]] float GetMass () const noexcept; + [[nodiscard]] float GetLinearDrag () const noexcept; + [[nodiscard]] float GetAngularDrag () const noexcept; + + [[nodiscard]] const SHMatrix& GetLocalInvInertia () const noexcept; + [[nodiscard]] const SHMatrix& GetWorldInvInertia () const noexcept; + + [[nodiscard]] const SHVec3& GetLocalCentroid () const noexcept; + [[nodiscard]] const SHVec3& GetWorldCentroid () const noexcept; + + [[nodiscard]] const SHVec3& GetForce () const noexcept; + [[nodiscard]] const SHVec3& GetTorque () const noexcept; [[nodiscard]] const SHVec3& GetLinearVelocity () const noexcept; [[nodiscard]] const SHVec3& GetAngularVelocity () const noexcept; @@ -111,6 +120,8 @@ namespace SHADE */ void SetType (Type newType) noexcept; + void SetGravityScale (float newGravityScale) noexcept; + /** * @brief * Mass is only modifiable for Dynamic bodies. @@ -127,9 +138,16 @@ namespace SHADE */ void SetLinearDrag (float newLinearDrag) noexcept; + /** + * @brief + * Drag is only modifiable for non-Static bodies. + * @param newAngularDrag + * The new drag to set. Values below 0 will be ignored. + */ + void SetAngularDrag (float newAngularDrag) noexcept; - void SetGravityScale (float newGravityScale) noexcept; void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; + void SetAngularVelocity (const SHVec3& newAngularVelocity)noexcept; // Flags @@ -151,29 +169,55 @@ namespace SHADE /** * @brief - * Adds a force to the body with an offset from it's center of mass. + * Adds a force to the body with an offset from it's center of mass.
+ * Non-dynamic bodies will be ignored. * @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; + 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. + * Adds an impulse to the body with an offset from it's center of mass.
+ * Non-dynamic bodies will be ignored. * @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; + void AddImpulse (const SHVec3& impulse, const SHVec3& pos = SHVec3::Zero) noexcept; + + /** + * @brief + * Adds torque to rotate the body about it's centroid.
+ * Non-dynamic bodies will be ignored. + * @param torque + * The torque to add to the body. + */ + void AddTorque (const SHVec3& torque) noexcept; /** * @brief * Removes all the forces from the body. */ - void ClearForces () noexcept; + void ClearForces () noexcept; + + /** + * @brief + * Computes the centroid and invInertia in world space. + */ + void ComputeWorldData () noexcept; + + /** + * @brief + * Computes the centroid and inertia of the object.
+ * If auto-mass is enabled, computes the mass.
+ * If auto-mass is disabled, the inertia is computed based on the ratio each shape's volume over the total volume. + * + */ + void ComputeMassData () noexcept; private: /*-----------------------------------------------------------------------------------*/ @@ -186,12 +230,20 @@ namespace SHADE Type bodyType; + float gravityScale; + float invMass; float linearDrag; + float angularDrag; - float gravityScale; + SHMatrix localInvInertia; + SHMatrix worldInvInertia; + + SHVec3 localCentroid; + SHVec3 worldCentroid; SHVec3 accumulatedForce; + SHVec3 accumulatedTorque; SHVec3 linearVelocity; SHVec3 angularVelocity; diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index da848f09..1d1c06bf 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -36,18 +36,12 @@ namespace SHADE bool SHRigidBodyComponent::IsGravityEnabled() const noexcept { - if (rigidBody) - return rigidBody->IsGravityEnabled(); - - return false; + return rigidBody ? rigidBody->IsGravityEnabled() : false; } bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept { - if (rigidBody) - return rigidBody->IsSleepingEnabled(); - - return false; + return rigidBody ? rigidBody->IsSleepingEnabled() : false; } bool SHRigidBodyComponent::IsInterpolating() const noexcept @@ -57,131 +51,93 @@ namespace SHADE bool SHRigidBodyComponent::IsSleeping() const noexcept { - if (rigidBody) - return rigidBody->IsSleeping(); - - return false; + return rigidBody ? rigidBody->IsSleeping() : false; } bool SHRigidBodyComponent::GetAutoMass() const noexcept { - if (rigidBody) - return rigidBody->IsAutoMassEnabled(); - - return false; + return rigidBody ? rigidBody->IsAutoMassEnabled() : false; } bool SHRigidBodyComponent::GetFreezePositionX() const noexcept { - if (rigidBody) - return rigidBody->GetFreezePositionX(); - - return false; + return rigidBody ? rigidBody->GetFreezePositionX() : false; } bool SHRigidBodyComponent::GetFreezePositionY() const noexcept { - if (rigidBody) - return rigidBody->GetFreezePositionY(); - - return false; + return rigidBody ? rigidBody->GetFreezePositionY() : false; } bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept { - if (rigidBody) - return rigidBody->GetFreezePositionZ(); - - return false; + return rigidBody ? rigidBody->GetFreezePositionZ() : false; } bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept { - if (rigidBody) - return rigidBody->GetFreezeRotationX(); - - return false; + return rigidBody ? rigidBody->GetFreezeRotationX() : false; } bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept { - if (rigidBody) - return rigidBody->GetFreezeRotationY(); - - return false; + return rigidBody ? rigidBody->GetFreezeRotationY() : false; } bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept { - if (rigidBody) - return rigidBody->GetFreezeRotationZ(); - - return false; + return rigidBody ? rigidBody->GetFreezeRotationZ() : false; } float SHRigidBodyComponent::GetGravityScale() const noexcept { - if (rigidBody) - return rigidBody->GetGravityScale(); - - return 0.0f; + return rigidBody ? rigidBody->GetGravityScale() : 0.0f; } float SHRigidBodyComponent::GetMass() const noexcept { - if (rigidBody) - return rigidBody->GetMass(); - - return -1.0f; + return rigidBody ? rigidBody->GetMass() : -1.0f; } float SHRigidBodyComponent::GetDrag() const noexcept { - if (rigidBody) - return rigidBody->GetLinearDrag(); - - return -1.0f; + return rigidBody ? rigidBody->GetLinearDrag() : -1.0f; } float SHRigidBodyComponent::GetAngularDrag() const noexcept { - return 0.0f; + return rigidBody ? rigidBody->GetAngularDrag() : -1.0f; } SHVec3 SHRigidBodyComponent::GetForce() const noexcept { - if (rigidBody) - return rigidBody->GetAccumulatedForce(); - - return SHVec3::Zero; + return rigidBody ? rigidBody->GetForce() : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetTorque() const noexcept { - return SHVec3::Zero; + return rigidBody ? rigidBody->GetTorque() : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept { - if (rigidBody) - return rigidBody->GetLinearVelocity(); - - return SHVec3::Zero; + return rigidBody ? rigidBody->GetLinearVelocity() : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept { - return SHVec3::Zero; + return rigidBody ? rigidBody->GetAngularVelocity() : SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetPosition() const noexcept { - if (rigidBody) - return rigidBody->GetMotionState().position; - - return SHVec3::Zero; + return rigidBody ? rigidBody->GetMotionState().position : SHVec3::Zero; } + SHVec3 SHRigidBodyComponent::GetRotation() const noexcept + { + return rigidBody ? rigidBody->GetMotionState().orientation.ToEuler() : SHVec3::Zero; + } /*-----------------------------------------------------------------------------------*/ /* Setter Functions Definitions */ @@ -282,7 +238,8 @@ namespace SHADE void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept { - + if (rigidBody) + rigidBody->SetAngularDrag(newAngularDrag); } void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept @@ -293,7 +250,8 @@ namespace SHADE void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept { - + if (rigidBody) + rigidBody->SetAngularVelocity(newAngularVelocity); } /*-----------------------------------------------------------------------------------*/ @@ -308,38 +266,67 @@ namespace SHADE void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept { - + if (rigidBody) + rigidBody->AddForce(force, localPos); } void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept { if (rigidBody) - rigidBody->AddForce(force, worldPos); + { + // Convert world pos into local space of the body + const SHVec3 LOCAL_POS = worldPos - rigidBody->GetWorldCentroid(); + rigidBody->AddForce(force, LOCAL_POS); + } } void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept { - + if (rigidBody) + { + // Rotate force into world space + const SHVec3 FORCE = SHVec3::Rotate(relativeForce, rigidBody->GetMotionState().orientation); + rigidBody->AddForce(FORCE); + } } void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept { - + if (rigidBody) + { + // Rotate force into world space + const SHVec3 FORCE = SHVec3::Rotate(relativeForce, rigidBody->GetMotionState().orientation); + rigidBody->AddForce(FORCE, localPos); + } } void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept { - + if (rigidBody) + { + // Rotate force into world space + const SHVec3 FORCE = SHVec3::Rotate(relativeForce, rigidBody->GetMotionState().orientation); + // Convert world pos into local space of the body + const SHVec3 LOCAL_POS = worldPos - rigidBody->GetWorldCentroid(); + + rigidBody->AddForce(FORCE, LOCAL_POS); + } } void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept { - + if (rigidBody) + rigidBody->AddTorque(torque); } void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept { - + if (rigidBody) + { + // Rotate force into world space + const SHVec3 TORQUE = SHVec3::Rotate(relativeTorque, rigidBody->GetMotionState().orientation); + rigidBody->AddTorque(TORQUE); + } } void SHRigidBodyComponent::ClearForces() const noexcept @@ -348,11 +335,6 @@ namespace SHADE rigidBody->ClearForces(); } - void SHRigidBodyComponent::ClearTorque() const noexcept - { - - } - /*-----------------------------------------------------------------------------------*/ /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index 7d377184..d215c3f8 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -93,6 +93,7 @@ namespace SHADE [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; [[nodiscard]] SHVec3 GetPosition () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ @@ -138,7 +139,6 @@ namespace SHADE void AddRelativeTorque (const SHVec3& relativeTorque) const noexcept; void ClearForces () const noexcept; - void ClearTorque () const noexcept; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 8e7450ce..200642e1 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -62,15 +62,23 @@ namespace SHADE if (!MOTION_STATE) continue; - SHVec3 renderPosition = rigidBodyComponent.IsInterpolating() ? MOTION_STATE.InterpolatePositions(FACTOR) : MOTION_STATE.position; + if (rigidBodyComponent.IsInterpolating()) + { + const SHVec3 RENDER_POSITION = MOTION_STATE.InterpolatePositions(FACTOR); + const SHQuaternion RENDER_ORIENTATION = MOTION_STATE.InterpolateOrientations(FACTOR); + + transformComponent->SetWorldPosition(RENDER_POSITION); + transformComponent->SetWorldOrientation(RENDER_ORIENTATION); + } + else + { + transformComponent->SetWorldPosition(MOTION_STATE.position); + transformComponent->SetWorldOrientation(MOTION_STATE.orientation); + } /* * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. */ - - - transformComponent->SetWorldPosition(renderPosition); - // TODO: SetOrientation } // Collision & Trigger messages diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index c03571db..a26a414d 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -54,7 +54,7 @@ namespace SHADE SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); - // TODO: Force Orientation + motionState.ForceOrientation(TRANSFORM_COMPONENT->GetWorldOrientation()); } if (physicsObject.collider) diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 77241ae9..62654dbb 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -120,7 +120,10 @@ namespace SHADE case SHCollisionShape::Type::SPHERE: { const SHSphereCollisionShape* SPHERE = dynamic_cast(SHAPE); - drawSphere(debugDrawSystem, *SPHERE); + + // Compute rotation of sphere + const SHVec3 ROTATION = collider.GetOrientation().ToEuler() + SPHERE->GetRotationOffset(); + drawSphere(debugDrawSystem, *SPHERE, ROTATION); break; } @@ -137,10 +140,10 @@ namespace SHADE } } - void SHPhysicsDebugDrawSystem::drawSphere(SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere) noexcept + void SHPhysicsDebugDrawSystem::drawSphere(SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere, const SHVec3& rotation) noexcept { const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(sphere.IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)]; - debugDrawSystem->DrawSphere(DRAW_COLOUR, sphere.GetCenter(), sphere.GetWorldRadius()); + debugDrawSystem->DrawSphere(DRAW_COLOUR, sphere.GetCenter(), rotation, sphere.GetWorldRadius()); } void SHPhysicsDebugDrawSystem::drawContact(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index 423ab62a..1eb4e967 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -138,8 +138,8 @@ namespace SHADE SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); - static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; - static void drawSphere (SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere) noexcept; + static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; + static void drawSphere (SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere, const SHVec3& rotation) noexcept; static void drawContact (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept; static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.cpp b/SHADE_Engine/src/Tools/SHDebugDraw.cpp index b8aa8b0e..e8c8af9d 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.cpp +++ b/SHADE_Engine/src/Tools/SHDebugDraw.cpp @@ -68,7 +68,7 @@ namespace SHADE void SHDebugDraw::Sphere(const SHVec4& color, const SHVec3& pos, double radius) { - dbgDrawSys->DrawSphere(color, pos, radius); + dbgDrawSys->DrawSphere(color, pos, SHVec3::Zero, radius); } void SHDebugDraw::PersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt) diff --git a/SHADE_Managed/src/Components/RigidBody.cxx b/SHADE_Managed/src/Components/RigidBody.cxx index 7b3604f2..6237f3a9 100644 --- a/SHADE_Managed/src/Components/RigidBody.cxx +++ b/SHADE_Managed/src/Components/RigidBody.cxx @@ -217,10 +217,4 @@ namespace SHADE { return Convert::ToCLI(GetNativeComponent()->GetTorque()); } - - void RigidBody::ClearTorque() - { - GetNativeComponent()->ClearTorque(); - } - } \ No newline at end of file diff --git a/SHADE_Managed/src/Components/RigidBody.hxx b/SHADE_Managed/src/Components/RigidBody.hxx index 8bfe34aa..8293cca4 100644 --- a/SHADE_Managed/src/Components/RigidBody.hxx +++ b/SHADE_Managed/src/Components/RigidBody.hxx @@ -155,7 +155,6 @@ namespace SHADE void AddRelativeTorque(Vector3 relativeForce); Vector3 GetTorque(); - void ClearTorque(); }; } \ No newline at end of file -- 2.40.1 From 27c7a1739776e2de7a135e145220f42bd11b1a35 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 15 Dec 2022 22:59:55 +0800 Subject: [PATCH 12/84] Fixed computation of global inverse inertia tensor --- SHADE_Engine/src/Physics/Collision/SHCollider.cpp | 7 +++++++ SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index b64bab53..d7ca4b14 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -17,6 +17,7 @@ #include "Events/SHEvent.h" #include "Math/SHMathHelpers.h" #include "Physics/SHPhysicsEvents.h" +#include "Physics/Dynamics/SHRigidBody.h" namespace SHADE @@ -277,6 +278,9 @@ namespace SHADE SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + if (rigidBody) + rigidBody->ComputeMassData(); + return static_cast(shapes.size()); } @@ -316,6 +320,9 @@ namespace SHADE // Broadcast Event for removing a shape SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); + if (rigidBody) + rigidBody->ComputeMassData(); + SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index c9f3b097..00df0640 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -598,7 +598,7 @@ namespace SHADE const SHMatrix ROTATION = SHMatrix::Rotate(motionState.orientation); // Compute world inertia - worldInvInertia = ROTATION * localInvInertia * SHMatrix::Transpose(ROTATION); + worldInvInertia = SHMatrix::Transpose(ROTATION) * localInvInertia * ROTATION; // Compute world centroid worldCentroid = (ROTATION * localCentroid) + motionState.position; -- 2.40.1 From 27760a95c98fa3a0a4e0574377f61af0f9483ca5 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 15 Dec 2022 23:00:15 +0800 Subject: [PATCH 13/84] Tested physics interactions with scripts --- Assets/Scenes/PhysicsSandbox.shade | 12 +- Assets/Scripts/Tests/PhysicsTestObj.cs | 112 ++++++++++++++++++ Assets/Scripts/Tests/PhysicsTestObj.cs.shmeta | 3 + 3 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 Assets/Scripts/Tests/PhysicsTestObj.cs create mode 100644 Assets/Scripts/Tests/PhysicsTestObj.cs.shmeta diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 0005b35e..0952fd3c 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -5,7 +5,7 @@ Components: Transform Component: Translate: {x: 0, y: 1.77475965, 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: @@ -13,8 +13,8 @@ Auto Mass: false Mass: 1 Drag: 1 - Angular Drag: 0 - Use Gravity: true + Angular Drag: 1 + Use Gravity: false Gravity Scale: 1 Interpolate: true Sleeping Enabled: true @@ -37,7 +37,11 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: ~ + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 500 - EID: 1 Name: Default IsActive: true diff --git a/Assets/Scripts/Tests/PhysicsTestObj.cs b/Assets/Scripts/Tests/PhysicsTestObj.cs new file mode 100644 index 00000000..c36537b3 --- /dev/null +++ b/Assets/Scripts/Tests/PhysicsTestObj.cs @@ -0,0 +1,112 @@ +using SHADE; +using System; +using System.Collections.Generic; +using static Item; + + +public class PhysicsTestObj : Script +{ + public RigidBody rb { get; set; } + + // Movement input booleans + public enum Direction + { + UP, + DOWN, + FORWARD, + BACK, + LEFT, + RIGHT + }; + + internal bool[] move = new bool[6]; + internal bool[] rotate = new bool[6]; + + internal Vector3[] moveVec = new Vector3[6] + { + Vector3.Up, + Vector3.Down, + Vector3.Back, + Vector3.Forward, + Vector3.Left, + Vector3.Right + }; + + internal Vector3[] rotateVec = new Vector3[6] + { + Vector3.Right, + Vector3.Left, + Vector3.Forward, + Vector3.Down, + Vector3.Up, + Vector3.Down + }; + + internal Input.KeyCode[] moveInputKeys = new Input.KeyCode[6] + { + Input.KeyCode.Space, + Input.KeyCode.LeftControl, + Input.KeyCode.W, + Input.KeyCode.S, + Input.KeyCode.A, + Input.KeyCode.D + }; + + internal Input.KeyCode[] rotateInputKeys = new Input.KeyCode[6] + { + Input.KeyCode.I, + Input.KeyCode.K, + Input.KeyCode.U, + Input.KeyCode.O, + Input.KeyCode.J, + Input.KeyCode.L + }; + + public float forceAmount = 50.0f; + public float torqueAmount = 500.0f; + + protected override void awake() + { + rb = GetComponent(); + + for (int i = 0; i < 6; ++i) + { + move[i] = false; + rotate[i] = false; + } + } + + protected override void update() + { + for (int i = 0; i < 6; ++i) + { + if (Input.GetKeyDown(moveInputKeys[i])) + move[i] = true; + + //if (Input.GetKeyDown(rotateInputKeys[i])) + // rotate[i] = true; + } + } + + protected override void fixedUpdate() + { + for (int i = 0; i < 6; ++i) + { + bool shouldMove = move[i]; + bool shouldRotate = rotate[i]; + + if (shouldMove) + { + Vector3 offset = new Vector3(0.25f, 0.0f, 0.0f); + rb.AddForceAtLocalPos(moveVec[i] * forceAmount, offset); + move[i] = false; + } + + if (shouldRotate) + { + rb.AddTorque(rotateVec[i] * torqueAmount); + rotate[i] = false; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Tests/PhysicsTestObj.cs.shmeta b/Assets/Scripts/Tests/PhysicsTestObj.cs.shmeta new file mode 100644 index 00000000..8c096651 --- /dev/null +++ b/Assets/Scripts/Tests/PhysicsTestObj.cs.shmeta @@ -0,0 +1,3 @@ +Name: PhysicsTestObj +ID: 159293012 +Type: 9 -- 2.40.1 From 6b8232ae9150bdd25cff47165c8531f5498e3728 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 02:02:20 +0800 Subject: [PATCH 14/84] Fixed bug where intertia tensors were not reset when unlocking axes --- Assets/Scenes/PhysicsSandbox.shade | 2 +- Assets/Scripts/Tests/PhysicsTestObj.cs | 9 ++-- .../src/Physics/Dynamics/SHRigidBody.cpp | 54 ++++++++++++++++--- .../src/Physics/Dynamics/SHRigidBody.h | 10 ++++ .../PhysicsObject/SHPhysicsObject.cpp | 10 ++++ 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 0952fd3c..7381b70c 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -11,7 +11,7 @@ RigidBody Component: Type: Dynamic Auto Mass: false - Mass: 1 + Mass: 10 Drag: 1 Angular Drag: 1 Use Gravity: false diff --git a/Assets/Scripts/Tests/PhysicsTestObj.cs b/Assets/Scripts/Tests/PhysicsTestObj.cs index c36537b3..20437eb3 100644 --- a/Assets/Scripts/Tests/PhysicsTestObj.cs +++ b/Assets/Scripts/Tests/PhysicsTestObj.cs @@ -83,8 +83,8 @@ public class PhysicsTestObj : Script if (Input.GetKeyDown(moveInputKeys[i])) move[i] = true; - //if (Input.GetKeyDown(rotateInputKeys[i])) - // rotate[i] = true; + if (Input.GetKeyDown(rotateInputKeys[i])) + rotate[i] = true; } } @@ -97,8 +97,9 @@ public class PhysicsTestObj : Script if (shouldMove) { - Vector3 offset = new Vector3(0.25f, 0.0f, 0.0f); - rb.AddForceAtLocalPos(moveVec[i] * forceAmount, offset); + //Vector3 offset = new Vector3(0.25f, 0.0f, 0.0f); + //rb.AddForceAtLocalPos(moveVec[i] * forceAmount, offset); + rb.AddForce(moveVec[i] * forceAmount); move[i] = false; } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 00df0640..aa8027c7 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -511,11 +511,12 @@ namespace SHADE // Reset angular velocity along X-axis angularVelocity.x = 0.0f; // Set inertia tensor on the x-axis to 0 - localInvInertia.m[0][0] = worldInvInertia.m[0][0] = 0.0f; + localInvInertia.m[0][0] = 0.0f; } else { flags &= ~VALUE; + computeInertiaTensor(); } } @@ -530,11 +531,12 @@ namespace SHADE // Reset angular velocity along Y-axis angularVelocity.y = 0.0f; // Set inertia tensor on the y-axis to 0 - localInvInertia.m[1][1] = worldInvInertia.m[1][1] = 0.0f; + localInvInertia.m[1][1] = 0.0f; } else { flags &= ~VALUE; + computeInertiaTensor(); } } @@ -549,11 +551,12 @@ namespace SHADE // Reset angular velocity along Z-axis angularVelocity.z = 0.0f; // Set inertia tensor on the z-axis to 0 - localInvInertia.m[2][2] = worldInvInertia.m[2][2] = 0.0f; + localInvInertia.m[2][2] = 0.0f; } else { flags &= ~VALUE; + computeInertiaTensor(); } } @@ -606,20 +609,59 @@ namespace SHADE void SHRigidBody::ComputeMassData() noexcept { - // TODO: Compute total inertia and centroid from composited colliders using the Parallel Axis Theorem. + computeCentroid(); + computeMassAndInertiaTensor(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definition */ + /*-----------------------------------------------------------------------------------*/ + + void SHRigidBody::computeCentroid() noexcept + { + // TODO + } + + void SHRigidBody::computeMass() noexcept + { // TODO: If auto mass in enabled, compute total mass based from each collider. // TODO: If auto mass disabled, compute inertia tensor for each shape using the ratio of its mass / total mass by comparing the volume / total volume. + } - if (collider && !collider->GetCollisionShapes().empty()) + void SHRigidBody::computeInertiaTensor() noexcept + { + // TODO: Compute total inertia from composited colliders using the Parallel Axis Theorem. + + if (!collider || collider->GetCollisionShapes().empty()) + { + localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = invMass; + } + else { // HACK: For now, take only the first shape as we are testing with non-composited colliders. We are using the center as the centroid. const auto* FIRST_SHAPE = collider->GetCollisionShape(0); localInvInertia = SHMatrix::Inverse(FIRST_SHAPE->GetInertiaTensor(1.0f / invMass)); } - else + } + + void SHRigidBody::computeMassAndInertiaTensor() noexcept + { + // TODO: If auto mass in enabled, compute total mass based from each collider. + // TODO: If auto mass disabled, compute inertia tensor for each shape using the ratio of its mass / total mass by comparing the volume / total volume. + + // TODO: Compute total inertia from composited colliders using the Parallel Axis Theorem. + + if (!collider || collider->GetCollisionShapes().empty()) { localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = invMass; } + else + { + // HACK: For now, take only the first shape as we are testing with non-composited colliders. We are using the center as the centroid. + const auto* FIRST_SHAPE = collider->GetCollisionShape(0); + localInvInertia = SHMatrix::Inverse(FIRST_SHAPE->GetInertiaTensor(1.0f / invMass)); + } + } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 0d1457d9..ab30bbcf 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -252,6 +252,16 @@ namespace SHADE uint16_t flags; SHMotionState motionState; + + /*-----------------------------------------------------------------------------------*/ + /* Member Functions */ + /*-----------------------------------------------------------------------------------*/ + + void computeCentroid () noexcept; + void computeMass () noexcept; + void computeInertiaTensor () noexcept; + void computeMassAndInertiaTensor() noexcept; + }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp index ee33016a..56c2ac7b 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -92,8 +92,12 @@ namespace SHADE // Link with collider if it exists if (collider) + { collider->SetRigidBody(rigidBody); + rigidBody->SetCollider(collider); + } + rigidBody->ComputeMassData(); return rigidBody; } @@ -119,7 +123,10 @@ namespace SHADE // Link with rigidBody if it exists if (rigidBody) + { rigidBody->SetCollider(collider); + collider->SetRigidBody(rigidBody); + } return collider; } @@ -131,7 +138,10 @@ namespace SHADE // Unlink with rigid body if (rigidBody) + { rigidBody->SetCollider(nullptr); + rigidBody->ComputeMassData(); + } } /*-----------------------------------------------------------------------------------*/ -- 2.40.1 From ddf2d8bde9b424d0f140b1c1fbf3eb4815a930fc Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 14:38:01 +0800 Subject: [PATCH 15/84] Fixed warnings for subscript operator in vectors and removed react conversions --- SHADE_Engine/src/Math/SHColour.cpp | 8 ++++++++ SHADE_Engine/src/Math/SHQuaternion.cpp | 20 ------------------- SHADE_Engine/src/Math/SHQuaternion.h | 8 -------- SHADE_Engine/src/Math/SHRay.cpp | 12 ------------ SHADE_Engine/src/Math/SHRay.h | 6 ------ SHADE_Engine/src/Math/Vector/SHVec2.cpp | 17 ++++++++-------- SHADE_Engine/src/Math/Vector/SHVec2.h | 6 ------ SHADE_Engine/src/Math/Vector/SHVec3.cpp | 26 ++++++++----------------- SHADE_Engine/src/Math/Vector/SHVec3.h | 7 ------- SHADE_Engine/src/Math/Vector/SHVec4.cpp | 8 ++++++++ 10 files changed, 32 insertions(+), 86 deletions(-) diff --git a/SHADE_Engine/src/Math/SHColour.cpp b/SHADE_Engine/src/Math/SHColour.cpp index fc2f2a08..7c372376 100644 --- a/SHADE_Engine/src/Math/SHColour.cpp +++ b/SHADE_Engine/src/Math/SHColour.cpp @@ -260,6 +260,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } @@ -274,6 +276,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } @@ -288,6 +292,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } @@ -302,6 +308,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp index 8904cb05..021f0a6a 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.cpp +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -44,16 +44,6 @@ namespace SHADE : XMFLOAT4( _x, _y, _z, _w ) {} - SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept - : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) - { - XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler })); - } - - SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept - : XMFLOAT4( rp3dQuat.x, rp3dQuat.y, rp3dQuat.z, rp3dQuat.w ) - {} - /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -141,16 +131,6 @@ namespace SHADE return XMQuaternionNotEqual(*this, rhs); } - SHQuaternion::operator reactphysics3d::Quaternion() const noexcept - { - return reactphysics3d::Quaternion{ x, y, z, w }; - } - - SHQuaternion::operator reactphysics3d::Vector3() const noexcept - { - return reactphysics3d::Vector3{ ToEuler() }; - } - SHQuaternion::operator XMVECTOR() const noexcept { return XMLoadFloat4(this); diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h index fa5b5d36..93c546ca 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.h +++ b/SHADE_Engine/src/Math/SHQuaternion.h @@ -11,7 +11,6 @@ #pragma once #include -#include #include @@ -52,11 +51,6 @@ namespace SHADE SHQuaternion (const SHVec4& vec4) noexcept; SHQuaternion (float x, float y, float z, float w) noexcept; - // Conversion from other math types - - SHQuaternion (const reactphysics3d::Vector3& rp3dEuler) noexcept; - SHQuaternion (const reactphysics3d::Quaternion& rp3dQuat) noexcept; - /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ @@ -82,8 +76,6 @@ namespace SHADE // Conversion to other math types used by SHADE - operator reactphysics3d::Quaternion () const noexcept; - operator reactphysics3d::Vector3 () const noexcept; operator DirectX::XMVECTOR () const noexcept; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Math/SHRay.cpp b/SHADE_Engine/src/Math/SHRay.cpp index c4931aba..622087c6 100644 --- a/SHADE_Engine/src/Math/SHRay.cpp +++ b/SHADE_Engine/src/Math/SHRay.cpp @@ -30,12 +30,6 @@ namespace SHADE , direction { dir } {} - SHRay::SHRay(const reactphysics3d::Ray rp3dRay) noexcept - : position { rp3dRay.point1 } - , direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) } - {} - - /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -62,12 +56,6 @@ namespace SHADE return XMVector3NotEqual(LHS_POS, RHS_POS) || XMVector3NotEqual(LHS_DIR, RHS_DIR); } - SHRay::operator reactphysics3d::Ray() const noexcept - { - // We use 2km. Temp solution. - return reactphysics3d::Ray{ position, position + (direction * MAX_RAYCAST_DIST) }; - } - SHRaycastResult::operator bool() const noexcept { return hit; diff --git a/SHADE_Engine/src/Math/SHRay.h b/SHADE_Engine/src/Math/SHRay.h index 18efc224..56599018 100644 --- a/SHADE_Engine/src/Math/SHRay.h +++ b/SHADE_Engine/src/Math/SHRay.h @@ -10,10 +10,7 @@ #pragma once -#include - // Project Headers -#include "SH_API.h" #include "Vector/SHVec3.h" namespace SHADE @@ -40,7 +37,6 @@ namespace SHADE SHRay () noexcept; SHRay (const SHVec3& pos, const SHVec3& dir) noexcept; - SHRay (const reactphysics3d::Ray rp3dRay) noexcept; SHRay (const SHRay&) noexcept = default; SHRay (SHRay&& ) noexcept = default; @@ -55,8 +51,6 @@ namespace SHADE [[nodiscard]] bool operator==(const SHRay& rhs) const noexcept; [[nodiscard]] bool operator!=(const SHRay& rhs) const noexcept; - - operator reactphysics3d::Ray() const noexcept; }; struct SH_API SHRaycastResult diff --git a/SHADE_Engine/src/Math/Vector/SHVec2.cpp b/SHADE_Engine/src/Math/Vector/SHVec2.cpp index 9573be01..da0215f4 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec2.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec2.cpp @@ -50,10 +50,6 @@ namespace SHADE : XMFLOAT2( _x, _y ) {} - SHVec2::SHVec2(const reactphysics3d::Vector2& rp3dVec2) noexcept - : XMFLOAT2( rp3dVec2.x, rp3dVec2.y ) - {} - /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -165,6 +161,8 @@ namespace SHADE { case 0: return x; case 1: return y; + // This will never hit + default: return x; } } @@ -177,6 +175,8 @@ namespace SHADE { case 0: return x; case 1: return y; + // This will never hit + default: return x; } } @@ -189,6 +189,8 @@ namespace SHADE { case 0: return x; case 1: return y; + // This will never hit + default: return x; } } @@ -201,14 +203,11 @@ namespace SHADE { case 0: return x; case 1: return y; + // This will never hit + default: return x; } } - SHVec2::operator reactphysics3d::Vector2() const noexcept - { - return reactphysics3d::Vector2{ x, y }; - } - SHVec2 operator* (float lhs, const SHVec2& rhs) noexcept { SHVec2 result; diff --git a/SHADE_Engine/src/Math/Vector/SHVec2.h b/SHADE_Engine/src/Math/Vector/SHVec2.h index e780d3ac..78c1e6e8 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec2.h +++ b/SHADE_Engine/src/Math/Vector/SHVec2.h @@ -11,7 +11,6 @@ #pragma once #include -#include #include #include @@ -59,10 +58,6 @@ namespace SHADE SHVec2 (float n) noexcept; SHVec2 (float x, float y) noexcept; - // Conversion from other math types to SHADE - - SHVec2 (const reactphysics3d::Vector2& rp3dVec2) noexcept; - /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ @@ -73,7 +68,6 @@ namespace SHADE // Conversion to other math types used by SHADE operator DirectX::XMVECTOR () const noexcept; - operator reactphysics3d::Vector2 () const noexcept; SHVec2& operator+= (const SHVec2& rhs) noexcept; SHVec2& operator-= (const SHVec2& rhs) noexcept; diff --git a/SHADE_Engine/src/Math/Vector/SHVec3.cpp b/SHADE_Engine/src/Math/Vector/SHVec3.cpp index 4b77636a..6b042c61 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec3.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec3.cpp @@ -57,14 +57,6 @@ namespace SHADE : XMFLOAT3( _x, _y, _z ) {} - SHVec3::SHVec3(const reactphysics3d::Vector3& rp3dVec3) noexcept - : XMFLOAT3( rp3dVec3.x, rp3dVec3.y, rp3dVec3.z ) - {} - - SHVec3::SHVec3(const reactphysics3d::Quaternion& rp3dVec3) noexcept - : XMFLOAT3( SHQuaternion{rp3dVec3}.ToEuler() ) - {} - /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -179,6 +171,8 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; + // This will never hit + default: return x; } } @@ -192,6 +186,8 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; + // This will never hit + default: return x; } } @@ -205,6 +201,8 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; + // This will never hit + default: return x; } } @@ -218,19 +216,11 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; + // This will never hit + default: return x; } } - SHVec3::operator reactphysics3d::Vector3() const noexcept - { - return reactphysics3d::Vector3{ x, y , z }; - } - - SHVec3::operator reactphysics3d::Quaternion() const noexcept - { - return reactphysics3d::Quaternion::fromEulerAngles(x, y, z); - } - SHVec3 operator* (float lhs, const SHVec3& rhs) noexcept { SHVec3 result; diff --git a/SHADE_Engine/src/Math/Vector/SHVec3.h b/SHADE_Engine/src/Math/Vector/SHVec3.h index de37d6a5..657e167e 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec3.h +++ b/SHADE_Engine/src/Math/Vector/SHVec3.h @@ -11,8 +11,6 @@ #pragma once #include -#include -#include #include #include @@ -69,9 +67,6 @@ namespace SHADE // Conversion from other math types to SHADE - SHVec3 (const reactphysics3d::Vector3& rp3dVec3) noexcept; - SHVec3 (const reactphysics3d::Quaternion& rp3dVec3) noexcept; - /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ @@ -81,8 +76,6 @@ namespace SHADE // Conversion to other math types used by SHADE - operator reactphysics3d::Vector3 () const noexcept; - operator reactphysics3d::Quaternion () const noexcept; operator DirectX::XMVECTOR () const noexcept; SHVec3& operator+= (const SHVec3& rhs) noexcept; diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.cpp b/SHADE_Engine/src/Math/Vector/SHVec4.cpp index c6f01d9e..c164e7f4 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec4.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec4.cpp @@ -164,6 +164,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } @@ -178,6 +180,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } @@ -192,6 +196,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } @@ -206,6 +212,8 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; + // This will never hit + default: return x; } } -- 2.40.1 From 1b91f60c4ae3619feb75833d3e047eb09e5fedca Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 14:38:22 +0800 Subject: [PATCH 16/84] Fixed warning with wrongly declared friends --- SHADE_Engine/src/Physics/Interface/SHColliderComponent.h | 2 +- SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index d62b9b90..d0cc7064 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -30,7 +30,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; - friend class SHPhysicsObject; + friend struct SHPhysicsObject; public: diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h index d215c3f8..1173c1d5 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -31,7 +31,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; - friend class SHPhysicsObject; + friend struct SHPhysicsObject; public: /*---------------------------------------------------------------------------------*/ -- 2.40.1 From 2bd90e7c143ddd7a665c4e5d5f58f07d16203c11 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 14:38:46 +0800 Subject: [PATCH 17/84] Adjusted physics debug draw to fit new debug draw interface --- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 5 +++-- .../System/SHPhysicsDebugDrawSystem.cpp | 19 +++++++++++-------- .../Physics/System/SHPhysicsDebugDrawSystem.h | 4 +--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index a26a414d..88ea8d79 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -36,12 +36,13 @@ namespace SHADE auto* physicsSystem = reinterpret_cast(GetSystem()); // Get all physics objects & sync transforms - for (auto& [entityID, physicsObject] : physicsSystem->physicsObjectManager.GetPhysicsObjects()) + auto& physicsObjects = physicsSystem->physicsObjectManager.GetPhysicsObjects(); + for (auto& [entityID, physicsObject] : physicsObjects) { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) - return; + continue; const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 62654dbb..dda437bc 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -93,6 +93,7 @@ namespace SHADE { const auto& EVENT_DATA = reinterpret_cast*>(onColliderDrawEvent.get())->data; + // Add to the container to draw all colliders if (EVENT_DATA->debugDrawState) { if (collidersToDraw.empty()) @@ -115,15 +116,23 @@ namespace SHADE { for (const auto* SHAPE : collider.GetCollisionShapes()) { + const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(SHAPE->IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)]; + switch (SHAPE->GetType()) { case SHCollisionShape::Type::SPHERE: { const SHSphereCollisionShape* SPHERE = dynamic_cast(SHAPE); - // Compute rotation of sphere + // Compute transforms of sphere + const SHVec3 POSITION = SPHERE->GetCenter(); // Position offset is already computed here const SHVec3 ROTATION = collider.GetOrientation().ToEuler() + SPHERE->GetRotationOffset(); - drawSphere(debugDrawSystem, *SPHERE, ROTATION); + const SHVec3 SCALE { SPHERE->GetWorldRadius() }; + + // Compute TRS for the sphere + const SHMatrix TRS = SHMatrix::Transform(POSITION, ROTATION, SCALE); + + debugDrawSystem->DrawWireSphere(TRS, DRAW_COLOUR, true); break; } @@ -140,12 +149,6 @@ namespace SHADE } } - void SHPhysicsDebugDrawSystem::drawSphere(SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere, const SHVec3& rotation) noexcept - { - const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(sphere.IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)]; - debugDrawSystem->DrawSphere(DRAW_COLOUR, sphere.GetCenter(), rotation, sphere.GetWorldRadius()); - } - void SHPhysicsDebugDrawSystem::drawContact(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept { static const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)]; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index 1eb4e967..79b88d3f 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -138,9 +138,7 @@ namespace SHADE SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); - static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; - static void drawSphere (SHDebugDrawSystem* debugDrawSystem, const SHSphereCollisionShape& sphere, const SHVec3& rotation) noexcept; - + static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; static void drawContact (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept; static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; -- 2.40.1 From a6e1064e64dcc8515a76c445e95f9349d6e9f706 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 15:03:55 +0800 Subject: [PATCH 18/84] Fixed bug where collider offsets were not recomputed --- .../CollisionShapes/SHCollisionShape.cpp | 31 ++++++++ .../CollisionShapes/SHCollisionShape.h | 35 ++++++--- .../CollisionShapes/SHSphereCollisionShape.h | 4 +- .../src/Physics/Collision/SHCollider.cpp | 78 ++++++++++++++----- .../src/Physics/Collision/SHCollider.h | 10 ++- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 15 ++-- 6 files changed, 135 insertions(+), 38 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index 2f4e3819..d0706ed0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -95,6 +95,15 @@ namespace SHADE return flags & FLAG_VALUE; } + bool SHCollisionShape::IsDirty() const noexcept + { + static constexpr int FLAG_POS = 6; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + return flags & FLAG_VALUE; + } + + const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept { return *collisionTag; @@ -116,21 +125,25 @@ namespace SHADE void SHCollisionShape::SetDensity(float density) noexcept { + setDirty(true); material.SetDensity(density); } void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept { + setDirty(true); material = newMaterial; } void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept { + setDirty(true); positionOffset = posOffset; } void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept { + setDirty(true); rotationOffset = rotOffset; } @@ -147,10 +160,28 @@ namespace SHADE collisionTag = newCollisionTag; } + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionShape::ClearDirty() noexcept + { + setDirty(false); + } + /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHCollisionShape::setDirty(bool isDirty) noexcept + { + static constexpr int FLAG_POS = 6; + static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; + + isDirty ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; + } + + } // namespace SHADE RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 6a08f940..90020727 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -91,6 +91,7 @@ namespace SHADE [[nodiscard]] Type GetType () const noexcept; [[nodiscard]] bool IsTrigger () const noexcept; [[nodiscard]] bool IsColliding () const noexcept; + [[nodiscard]] bool IsDirty () const noexcept; [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; @@ -98,24 +99,31 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetFriction (float friction) noexcept; - void SetBounciness (float bounciness) noexcept; - void SetDensity (float density) noexcept; - void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; + void SetFriction (float friction) noexcept; + void SetBounciness (float bounciness) noexcept; + void SetDensity (float density) noexcept; + void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; - void SetPositionOffset (const SHVec3& posOffset) noexcept; - void SetRotationOffset (const SHVec3& rotOffset) noexcept; + void SetPositionOffset (const SHVec3& posOffset) noexcept; + void SetRotationOffset (const SHVec3& rotOffset) noexcept; // Flags - void SetIsTrigger (bool isTrigger) noexcept; + + void SetIsTrigger (bool isTrigger) noexcept; - void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; + void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + /** + * @brief + * Clears the dirty flag of the collider. + */ + void ClearDirty () noexcept; + + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ @@ -129,10 +137,17 @@ namespace SHADE SHVec3 positionOffset; SHVec3 rotationOffset; - uint8_t flags; // 0 0 wasColliding isColliding trigger capsule sphere box + uint8_t flags; // 0 dirty wasColliding isColliding trigger capsule sphere box SHCollisionTag* collisionTag; RTTR_ENABLE() + + private: + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void setDirty (bool isDirty) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 72ea05f5..8276578e 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -37,8 +37,8 @@ namespace SHADE * @brief * Encapsulate a Sphere Collision Shape used for Physics Simulations. */ - class SH_API SHSphereCollisionShape : public SHCollisionShape - , private SHSphere + class SH_API SHSphereCollisionShape final : public SHCollisionShape + , private SHSphere { private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index d7ca4b14..9aedef16 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -30,6 +30,7 @@ namespace SHADE : entityID { eid } , shapeIDCounter { 0 } , debugDraw { false } + , dirty { true } , rigidBody { nullptr } , shapeFactory { nullptr } , transform { worldTransform } @@ -41,6 +42,7 @@ namespace SHADE : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } + , dirty { rhs.dirty } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -58,6 +60,7 @@ namespace SHADE : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } + , dirty { rhs.dirty } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -100,6 +103,7 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; + dirty = rhs.dirty; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; @@ -119,6 +123,7 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; + dirty = rhs.dirty; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; @@ -201,21 +206,25 @@ namespace SHADE void SHCollider::SetTransform(const SHTransform& newTransform) noexcept { + dirty = true; transform = newTransform; } void SHCollider::SetPosition(const SHVec3& newPosition) noexcept { + dirty = true; transform.position = newPosition; } void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept { + dirty = true; transform.orientation = newOrientation; } void SHCollider::SetScale(const SHVec3& newScale) noexcept { + dirty = true; transform.scale = newScale; } @@ -284,6 +293,28 @@ namespace SHADE return static_cast(shapes.size()); } + void SHCollider::Update() + { + // Forcefully recompute everything since the transform was changed + if (dirty) + { + RecomputeShapes(); + dirty = false; + return; + } + + // Recompute any shapes set to dirty + for (auto* shape : shapes) + { + if (shape->IsDirty()) + { + recomputeShape(shape); + shape->ClearDirty(); + } + } + } + + void SHCollider::RemoveCollisionShape(int index) { if (!shapeFactory) @@ -329,25 +360,7 @@ namespace SHADE void SHCollider::RecomputeShapes() noexcept { for (auto* shape : shapes) - { - switch (shape->GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - recomputeSphere(dynamic_cast(shape)); - break; - } - case SHCollisionShape::Type::BOX: - { - break; - } - case SHCollisionShape::Type::CAPSULE: - { - break; - } - default: break; - } - } + recomputeShape(shape); } /*-----------------------------------------------------------------------------------*/ @@ -403,6 +416,33 @@ namespace SHADE ++shapeIDCounter; } + void SHCollider::recomputeShape(SHCollisionShape* shape) noexcept + { + if (!shape) + { + SHLOGV_ERROR_D("Shape missing from Collider {}", entityID) + return; + } + + switch (shape->GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + recomputeSphere(dynamic_cast(shape)); + break; + } + case SHCollisionShape::Type::BOX: + { + break; + } + case SHCollisionShape::Type::CAPSULE: + { + break; + } + default: break; + } + } + void SHCollider::recomputeSphere(SHSphereCollisionShape* sphere) noexcept { // Recompute world radius diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 927c6155..8a183dcc 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -132,6 +132,12 @@ namespace SHADE // TODO: Add Box & Capsule + /** + * @brief + * Recomputes any shapes that were set to dirty. + */ + void Update (); + /** * @brief * Removes a shape from the container. Removal reduces the size of the container. @@ -158,6 +164,7 @@ namespace SHADE uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. bool debugDraw; + bool dirty; SHRigidBody* rigidBody; SHCollisionShapeFactory* shapeFactory; @@ -173,7 +180,8 @@ namespace SHADE void copyShapes (const SHCollider& rhsCollider); void copyShape (const SHCollisionShape* rhsShape); - void recomputeSphere (SHSphereCollisionShape* sphere) noexcept; + void recomputeShape (SHCollisionShape* shape) noexcept; + void recomputeSphere (SHSphereCollisionShape* sphere) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 88ea8d79..0094153e 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -41,7 +41,7 @@ namespace SHADE { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); - if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) + if (!TRANSFORM_COMPONENT) continue; const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); @@ -50,7 +50,7 @@ namespace SHADE // We assume that all engine components and physics object components have been successfully linked - if (physicsObject.rigidBody) + if (physicsObject.rigidBody && TRANSFORM_COMPONENT->HasChanged()) { SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); @@ -60,11 +60,14 @@ namespace SHADE if (physicsObject.collider) { - physicsObject.collider->SetPosition(WORLD_POS); - physicsObject.collider->SetOrientation(WORLD_ROT); - physicsObject.collider->SetScale(WORLD_SCL); + if (TRANSFORM_COMPONENT->HasChanged()) + { + physicsObject.collider->SetPosition(WORLD_POS); + physicsObject.collider->SetOrientation(WORLD_ROT); + physicsObject.collider->SetScale(WORLD_SCL); + } - physicsObject.collider->RecomputeShapes(); + physicsObject.collider->Update(); } } } -- 2.40.1 From 6a20e93704b2eda4d680f913cb6d430d87081e1b Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 18:34:29 +0800 Subject: [PATCH 19/84] Refactored colliders to use a parent-child transform logic --- .../CollisionShapes/SHCollisionShape.cpp | 56 ++++-------- .../CollisionShapes/SHCollisionShape.h | 30 +++---- .../SHSphereCollisionShape.cpp | 37 +++++++- .../CollisionShapes/SHSphereCollisionShape.h | 14 ++- .../src/Physics/Collision/SHCollider.cpp | 85 ++----------------- .../src/Physics/Collision/SHCollider.h | 10 --- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 15 ++-- .../System/SHPhysicsDebugDrawSystem.cpp | 12 +-- 8 files changed, 82 insertions(+), 177 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index d0706ed0..5dd17d35 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -25,9 +25,10 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHCollisionShape::SHCollisionShape(SHCollisionShapeID id, Type colliderType) - : id { id } - , flags { 0 } - , collisionTag { SHCollisionTagMatrix::GetTag(0) } + : id { id } + , flags { 0 } + , parentTransform { nullptr } + , collisionTag { SHCollisionTagMatrix::GetTag(0) } { flags |= 1U << SHUtilities::ConvertEnum(colliderType); } @@ -58,7 +59,7 @@ namespace SHADE const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept { - return positionOffset; + return transform.position; } const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept @@ -95,15 +96,6 @@ namespace SHADE return flags & FLAG_VALUE; } - bool SHCollisionShape::IsDirty() const noexcept - { - static constexpr int FLAG_POS = 6; - static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; - - return flags & FLAG_VALUE; - } - - const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept { return *collisionTag; @@ -125,26 +117,32 @@ namespace SHADE void SHCollisionShape::SetDensity(float density) noexcept { - setDirty(true); material.SetDensity(density); } void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept { - setDirty(true); material = newMaterial; } + void SHCollisionShape::SetParentTransform(SHTransform& parentTF) noexcept + { + parentTransform = &parentTF; + } + void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept { - setDirty(true); - positionOffset = posOffset; + transform.position = posOffset; + + ComputeTransforms(); } void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept { - setDirty(true); rotationOffset = rotOffset; + transform.orientation = SHQuaternion::FromEuler(rotationOffset); + + ComputeTransforms(); } void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept @@ -160,28 +158,6 @@ namespace SHADE collisionTag = newCollisionTag; } - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::ClearDirty() noexcept - { - setDirty(false); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::setDirty(bool isDirty) noexcept - { - static constexpr int FLAG_POS = 6; - static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; - - isDirty ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - } - - } // namespace SHADE RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 90020727..3c08e21a 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -14,11 +14,10 @@ // Project Headers #include "ECS_Base/Entity/SHEntity.h" -#include "Math/Geometry/SHShape.h" -#include "Math/SHQuaternion.h" #include "Physics/Collision/CollisionTags/SHCollisionTags.h" #include "Physics/Collision/SHPhysicsMaterial.h" #include "SHCollisionShapeID.h" +#include "Math/Transform/SHTransform.h" namespace SHADE { @@ -91,7 +90,6 @@ namespace SHADE [[nodiscard]] Type GetType () const noexcept; [[nodiscard]] bool IsTrigger () const noexcept; [[nodiscard]] bool IsColliding () const noexcept; - [[nodiscard]] bool IsDirty () const noexcept; [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; @@ -104,6 +102,8 @@ namespace SHADE void SetDensity (float density) noexcept; void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; + void SetParentTransform (SHTransform& parentTF) noexcept; + void SetPositionOffset (const SHVec3& posOffset) noexcept; void SetRotationOffset (const SHVec3& rotOffset) noexcept; @@ -117,13 +117,9 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Clears the dirty flag of the collider. - */ - void ClearDirty () noexcept; - - [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + virtual void ComputeTransforms () noexcept = 0; + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ @@ -134,20 +130,16 @@ namespace SHADE SHPhysicsMaterial material; - SHVec3 positionOffset; + SHTransform* parentTransform; + SHTransform transform; + + // Needed for conversion to euler angles SHVec3 rotationOffset; - uint8_t flags; // 0 dirty wasColliding isColliding trigger capsule sphere box + uint8_t flags; // 0 0 wasColliding isColliding trigger capsule sphere box SHCollisionTag* collisionTag; RTTR_ENABLE() - - private: - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - void setDirty (bool isDirty) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index 40671a96..e4bf68c3 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -14,6 +14,7 @@ #include "SHSphereCollisionShape.h" // Project Headers +#include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" namespace SHADE @@ -37,7 +38,8 @@ namespace SHADE { material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -52,7 +54,8 @@ namespace SHADE { material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -72,7 +75,8 @@ namespace SHADE id = rhs.id; material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -97,7 +101,8 @@ namespace SHADE id = rhs.id; material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -172,6 +177,18 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHSphereCollisionShape::ComputeTransforms() noexcept + { + const float SPHERE_SCALE = std::fabs(SHMath::Max({ parentTransform->scale.x, parentTransform->scale.y, parentTransform->scale.z })); + SetScale(SPHERE_SCALE); + + // Recompute center + const SHQuaternion FINAL_ROT = parentTransform->orientation * transform.orientation; + const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(parentTransform->position); + + Center = SHVec3::Transform(transform.position, TRS); + } + bool SHSphereCollisionShape::TestPoint(const SHVec3& point) const noexcept { return SHSphere::TestPoint(point); @@ -193,6 +210,18 @@ namespace SHADE return result; } + SHMatrix SHSphereCollisionShape::ComputeWorldTransform() const noexcept + { + const SHQuaternion ROTATION = parentTransform->orientation * transform.orientation; + const SHVec3 SCALE{ Radius }; + + return SHMatrix::Transform + ( + Center + , ROTATION + , SCALE +); + } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 8276578e..798c70b6 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -88,6 +88,12 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Recomputes the transform of this sphere. + */ + void ComputeTransforms () noexcept override; + /** * @brief * Tests if a point is inside the sphere. @@ -96,7 +102,7 @@ namespace SHADE * @return * True if the point is inside the sphere. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; /** * @brief @@ -107,7 +113,7 @@ namespace SHADE * An object holding the results of the raycast.
* See the corresponding header for the contents of the object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; /** * @brief @@ -117,9 +123,9 @@ namespace SHADE * @return * The inertia tensor of the sphere. */ - [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; - + [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 9aedef16..a6527e48 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -30,19 +30,15 @@ namespace SHADE : entityID { eid } , shapeIDCounter { 0 } , debugDraw { false } - , dirty { true } , rigidBody { nullptr } , shapeFactory { nullptr } , transform { worldTransform } - { - - } + {} SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } - , dirty { rhs.dirty } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -60,7 +56,6 @@ namespace SHADE : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } - , dirty { rhs.dirty } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -103,7 +98,6 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; - dirty = rhs.dirty; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; @@ -123,7 +117,6 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; - dirty = rhs.dirty; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; @@ -206,25 +199,21 @@ namespace SHADE void SHCollider::SetTransform(const SHTransform& newTransform) noexcept { - dirty = true; transform = newTransform; } void SHCollider::SetPosition(const SHVec3& newPosition) noexcept { - dirty = true; transform.position = newPosition; } void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept { - dirty = true; transform.orientation = newOrientation; } void SHCollider::SetScale(const SHVec3& newScale) noexcept { - dirty = true; transform.scale = newScale; } @@ -272,8 +261,9 @@ namespace SHADE ++shapeIDCounter; // Set offsets - sphere->positionOffset = posOffset; - sphere->rotationOffset = rotOffset; + sphere->SetParentTransform(transform); + sphere->SetPositionOffset(posOffset); + sphere->SetRotationOffset(rotOffset); shapes.emplace_back(sphere); @@ -293,28 +283,6 @@ namespace SHADE return static_cast(shapes.size()); } - void SHCollider::Update() - { - // Forcefully recompute everything since the transform was changed - if (dirty) - { - RecomputeShapes(); - dirty = false; - return; - } - - // Recompute any shapes set to dirty - for (auto* shape : shapes) - { - if (shape->IsDirty()) - { - recomputeShape(shape); - shape->ClearDirty(); - } - } - } - - void SHCollider::RemoveCollisionShape(int index) { if (!shapeFactory) @@ -360,7 +328,7 @@ namespace SHADE void SHCollider::RecomputeShapes() noexcept { for (auto* shape : shapes) - recomputeShape(shape); + shape->ComputeTransforms(); } /*-----------------------------------------------------------------------------------*/ @@ -416,47 +384,4 @@ namespace SHADE ++shapeIDCounter; } - void SHCollider::recomputeShape(SHCollisionShape* shape) noexcept - { - if (!shape) - { - SHLOGV_ERROR_D("Shape missing from Collider {}", entityID) - return; - } - - switch (shape->GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - recomputeSphere(dynamic_cast(shape)); - break; - } - case SHCollisionShape::Type::BOX: - { - break; - } - case SHCollisionShape::Type::CAPSULE: - { - break; - } - default: break; - } - } - - void SHCollider::recomputeSphere(SHSphereCollisionShape* sphere) noexcept - { - // Recompute world radius - const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z })); - sphere->SetScale(SPHERE_SCALE); - - // Recompute center - const SHQuaternion FINAL_ROT = transform.orientation * SHQuaternion::FromEuler(sphere->rotationOffset); - const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(transform.position); - - const SHVec3 NEW_CENTER = SHVec3::Transform(sphere->positionOffset, TRS); - - sphere->SetCenter(NEW_CENTER); - } - - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 8a183dcc..566bae3e 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -132,12 +132,6 @@ namespace SHADE // TODO: Add Box & Capsule - /** - * @brief - * Recomputes any shapes that were set to dirty. - */ - void Update (); - /** * @brief * Removes a shape from the container. Removal reduces the size of the container. @@ -164,7 +158,6 @@ namespace SHADE uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. bool debugDraw; - bool dirty; SHRigidBody* rigidBody; SHCollisionShapeFactory* shapeFactory; @@ -179,9 +172,6 @@ namespace SHADE void copyShapes (const SHCollider& rhsCollider); void copyShape (const SHCollisionShape* rhsShape); - - void recomputeShape (SHCollisionShape* shape) noexcept; - void recomputeSphere (SHSphereCollisionShape* sphere) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 0094153e..88ea8d79 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -41,7 +41,7 @@ namespace SHADE { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); - if (!TRANSFORM_COMPONENT) + if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) continue; const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); @@ -50,7 +50,7 @@ namespace SHADE // We assume that all engine components and physics object components have been successfully linked - if (physicsObject.rigidBody && TRANSFORM_COMPONENT->HasChanged()) + if (physicsObject.rigidBody) { SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); @@ -60,14 +60,11 @@ namespace SHADE if (physicsObject.collider) { - if (TRANSFORM_COMPONENT->HasChanged()) - { - physicsObject.collider->SetPosition(WORLD_POS); - physicsObject.collider->SetOrientation(WORLD_ROT); - physicsObject.collider->SetScale(WORLD_SCL); - } + physicsObject.collider->SetPosition(WORLD_POS); + physicsObject.collider->SetOrientation(WORLD_ROT); + physicsObject.collider->SetScale(WORLD_SCL); - physicsObject.collider->Update(); + physicsObject.collider->RecomputeShapes(); } } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index dda437bc..958ac61a 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -122,17 +122,7 @@ namespace SHADE { case SHCollisionShape::Type::SPHERE: { - const SHSphereCollisionShape* SPHERE = dynamic_cast(SHAPE); - - // Compute transforms of sphere - const SHVec3 POSITION = SPHERE->GetCenter(); // Position offset is already computed here - const SHVec3 ROTATION = collider.GetOrientation().ToEuler() + SPHERE->GetRotationOffset(); - const SHVec3 SCALE { SPHERE->GetWorldRadius() }; - - // Compute TRS for the sphere - const SHMatrix TRS = SHMatrix::Transform(POSITION, ROTATION, SCALE); - - debugDrawSystem->DrawWireSphere(TRS, DRAW_COLOUR, true); + debugDrawSystem->DrawWireSphere(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true); break; } -- 2.40.1 From 24b13ed6e42815573900870a65906a61afa975d3 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 18:34:29 +0800 Subject: [PATCH 20/84] Refactored colliders to use parent-child transform logic --- .../CollisionShapes/SHCollisionShape.cpp | 56 ++++-------- .../CollisionShapes/SHCollisionShape.h | 30 +++---- .../SHSphereCollisionShape.cpp | 37 +++++++- .../CollisionShapes/SHSphereCollisionShape.h | 14 ++- .../src/Physics/Collision/SHCollider.cpp | 85 ++----------------- .../src/Physics/Collision/SHCollider.h | 10 --- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 15 ++-- .../System/SHPhysicsDebugDrawSystem.cpp | 12 +-- 8 files changed, 82 insertions(+), 177 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index d0706ed0..5dd17d35 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -25,9 +25,10 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHCollisionShape::SHCollisionShape(SHCollisionShapeID id, Type colliderType) - : id { id } - , flags { 0 } - , collisionTag { SHCollisionTagMatrix::GetTag(0) } + : id { id } + , flags { 0 } + , parentTransform { nullptr } + , collisionTag { SHCollisionTagMatrix::GetTag(0) } { flags |= 1U << SHUtilities::ConvertEnum(colliderType); } @@ -58,7 +59,7 @@ namespace SHADE const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept { - return positionOffset; + return transform.position; } const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept @@ -95,15 +96,6 @@ namespace SHADE return flags & FLAG_VALUE; } - bool SHCollisionShape::IsDirty() const noexcept - { - static constexpr int FLAG_POS = 6; - static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; - - return flags & FLAG_VALUE; - } - - const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept { return *collisionTag; @@ -125,26 +117,32 @@ namespace SHADE void SHCollisionShape::SetDensity(float density) noexcept { - setDirty(true); material.SetDensity(density); } void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept { - setDirty(true); material = newMaterial; } + void SHCollisionShape::SetParentTransform(SHTransform& parentTF) noexcept + { + parentTransform = &parentTF; + } + void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept { - setDirty(true); - positionOffset = posOffset; + transform.position = posOffset; + + ComputeTransforms(); } void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept { - setDirty(true); rotationOffset = rotOffset; + transform.orientation = SHQuaternion::FromEuler(rotationOffset); + + ComputeTransforms(); } void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept @@ -160,28 +158,6 @@ namespace SHADE collisionTag = newCollisionTag; } - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::ClearDirty() noexcept - { - setDirty(false); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::setDirty(bool isDirty) noexcept - { - static constexpr int FLAG_POS = 6; - static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS; - - isDirty ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; - } - - } // namespace SHADE RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 90020727..3c08e21a 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -14,11 +14,10 @@ // Project Headers #include "ECS_Base/Entity/SHEntity.h" -#include "Math/Geometry/SHShape.h" -#include "Math/SHQuaternion.h" #include "Physics/Collision/CollisionTags/SHCollisionTags.h" #include "Physics/Collision/SHPhysicsMaterial.h" #include "SHCollisionShapeID.h" +#include "Math/Transform/SHTransform.h" namespace SHADE { @@ -91,7 +90,6 @@ namespace SHADE [[nodiscard]] Type GetType () const noexcept; [[nodiscard]] bool IsTrigger () const noexcept; [[nodiscard]] bool IsColliding () const noexcept; - [[nodiscard]] bool IsDirty () const noexcept; [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; @@ -104,6 +102,8 @@ namespace SHADE void SetDensity (float density) noexcept; void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; + void SetParentTransform (SHTransform& parentTF) noexcept; + void SetPositionOffset (const SHVec3& posOffset) noexcept; void SetRotationOffset (const SHVec3& rotOffset) noexcept; @@ -117,13 +117,9 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Clears the dirty flag of the collider. - */ - void ClearDirty () noexcept; - - [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + virtual void ComputeTransforms () noexcept = 0; + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ @@ -134,20 +130,16 @@ namespace SHADE SHPhysicsMaterial material; - SHVec3 positionOffset; + SHTransform* parentTransform; + SHTransform transform; + + // Needed for conversion to euler angles SHVec3 rotationOffset; - uint8_t flags; // 0 dirty wasColliding isColliding trigger capsule sphere box + uint8_t flags; // 0 0 wasColliding isColliding trigger capsule sphere box SHCollisionTag* collisionTag; RTTR_ENABLE() - - private: - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - void setDirty (bool isDirty) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index 40671a96..e4bf68c3 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -14,6 +14,7 @@ #include "SHSphereCollisionShape.h" // Project Headers +#include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" namespace SHADE @@ -37,7 +38,8 @@ namespace SHADE { material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -52,7 +54,8 @@ namespace SHADE { material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -72,7 +75,8 @@ namespace SHADE id = rhs.id; material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -97,7 +101,8 @@ namespace SHADE id = rhs.id; material = rhs.material; - positionOffset = rhs.positionOffset; + parentTransform = rhs.parentTransform; + 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. @@ -172,6 +177,18 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHSphereCollisionShape::ComputeTransforms() noexcept + { + const float SPHERE_SCALE = std::fabs(SHMath::Max({ parentTransform->scale.x, parentTransform->scale.y, parentTransform->scale.z })); + SetScale(SPHERE_SCALE); + + // Recompute center + const SHQuaternion FINAL_ROT = parentTransform->orientation * transform.orientation; + const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(parentTransform->position); + + Center = SHVec3::Transform(transform.position, TRS); + } + bool SHSphereCollisionShape::TestPoint(const SHVec3& point) const noexcept { return SHSphere::TestPoint(point); @@ -193,6 +210,18 @@ namespace SHADE return result; } + SHMatrix SHSphereCollisionShape::ComputeWorldTransform() const noexcept + { + const SHQuaternion ROTATION = parentTransform->orientation * transform.orientation; + const SHVec3 SCALE{ Radius }; + + return SHMatrix::Transform + ( + Center + , ROTATION + , SCALE +); + } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 8276578e..798c70b6 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -88,6 +88,12 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Recomputes the transform of this sphere. + */ + void ComputeTransforms () noexcept override; + /** * @brief * Tests if a point is inside the sphere. @@ -96,7 +102,7 @@ namespace SHADE * @return * True if the point is inside the sphere. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; /** * @brief @@ -107,7 +113,7 @@ namespace SHADE * An object holding the results of the raycast.
* See the corresponding header for the contents of the object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; /** * @brief @@ -117,9 +123,9 @@ namespace SHADE * @return * The inertia tensor of the sphere. */ - [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; - + [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 9aedef16..a6527e48 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -30,19 +30,15 @@ namespace SHADE : entityID { eid } , shapeIDCounter { 0 } , debugDraw { false } - , dirty { true } , rigidBody { nullptr } , shapeFactory { nullptr } , transform { worldTransform } - { - - } + {} SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } - , dirty { rhs.dirty } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -60,7 +56,6 @@ namespace SHADE : entityID { rhs.entityID } , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } - , dirty { rhs.dirty } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } , transform { rhs.transform } @@ -103,7 +98,6 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; - dirty = rhs.dirty; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; @@ -123,7 +117,6 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; - dirty = rhs.dirty; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; transform = rhs.transform; @@ -206,25 +199,21 @@ namespace SHADE void SHCollider::SetTransform(const SHTransform& newTransform) noexcept { - dirty = true; transform = newTransform; } void SHCollider::SetPosition(const SHVec3& newPosition) noexcept { - dirty = true; transform.position = newPosition; } void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept { - dirty = true; transform.orientation = newOrientation; } void SHCollider::SetScale(const SHVec3& newScale) noexcept { - dirty = true; transform.scale = newScale; } @@ -272,8 +261,9 @@ namespace SHADE ++shapeIDCounter; // Set offsets - sphere->positionOffset = posOffset; - sphere->rotationOffset = rotOffset; + sphere->SetParentTransform(transform); + sphere->SetPositionOffset(posOffset); + sphere->SetRotationOffset(rotOffset); shapes.emplace_back(sphere); @@ -293,28 +283,6 @@ namespace SHADE return static_cast(shapes.size()); } - void SHCollider::Update() - { - // Forcefully recompute everything since the transform was changed - if (dirty) - { - RecomputeShapes(); - dirty = false; - return; - } - - // Recompute any shapes set to dirty - for (auto* shape : shapes) - { - if (shape->IsDirty()) - { - recomputeShape(shape); - shape->ClearDirty(); - } - } - } - - void SHCollider::RemoveCollisionShape(int index) { if (!shapeFactory) @@ -360,7 +328,7 @@ namespace SHADE void SHCollider::RecomputeShapes() noexcept { for (auto* shape : shapes) - recomputeShape(shape); + shape->ComputeTransforms(); } /*-----------------------------------------------------------------------------------*/ @@ -416,47 +384,4 @@ namespace SHADE ++shapeIDCounter; } - void SHCollider::recomputeShape(SHCollisionShape* shape) noexcept - { - if (!shape) - { - SHLOGV_ERROR_D("Shape missing from Collider {}", entityID) - return; - } - - switch (shape->GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - recomputeSphere(dynamic_cast(shape)); - break; - } - case SHCollisionShape::Type::BOX: - { - break; - } - case SHCollisionShape::Type::CAPSULE: - { - break; - } - default: break; - } - } - - void SHCollider::recomputeSphere(SHSphereCollisionShape* sphere) noexcept - { - // Recompute world radius - const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z })); - sphere->SetScale(SPHERE_SCALE); - - // Recompute center - const SHQuaternion FINAL_ROT = transform.orientation * SHQuaternion::FromEuler(sphere->rotationOffset); - const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(transform.position); - - const SHVec3 NEW_CENTER = SHVec3::Transform(sphere->positionOffset, TRS); - - sphere->SetCenter(NEW_CENTER); - } - - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 8a183dcc..566bae3e 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -132,12 +132,6 @@ namespace SHADE // TODO: Add Box & Capsule - /** - * @brief - * Recomputes any shapes that were set to dirty. - */ - void Update (); - /** * @brief * Removes a shape from the container. Removal reduces the size of the container. @@ -164,7 +158,6 @@ namespace SHADE uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. bool debugDraw; - bool dirty; SHRigidBody* rigidBody; SHCollisionShapeFactory* shapeFactory; @@ -179,9 +172,6 @@ namespace SHADE void copyShapes (const SHCollider& rhsCollider); void copyShape (const SHCollisionShape* rhsShape); - - void recomputeShape (SHCollisionShape* shape) noexcept; - void recomputeSphere (SHSphereCollisionShape* sphere) noexcept; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 0094153e..88ea8d79 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -41,7 +41,7 @@ namespace SHADE { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); - if (!TRANSFORM_COMPONENT) + if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) continue; const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); @@ -50,7 +50,7 @@ namespace SHADE // We assume that all engine components and physics object components have been successfully linked - if (physicsObject.rigidBody && TRANSFORM_COMPONENT->HasChanged()) + if (physicsObject.rigidBody) { SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); @@ -60,14 +60,11 @@ namespace SHADE if (physicsObject.collider) { - if (TRANSFORM_COMPONENT->HasChanged()) - { - physicsObject.collider->SetPosition(WORLD_POS); - physicsObject.collider->SetOrientation(WORLD_ROT); - physicsObject.collider->SetScale(WORLD_SCL); - } + physicsObject.collider->SetPosition(WORLD_POS); + physicsObject.collider->SetOrientation(WORLD_ROT); + physicsObject.collider->SetScale(WORLD_SCL); - physicsObject.collider->Update(); + physicsObject.collider->RecomputeShapes(); } } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index dda437bc..958ac61a 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -122,17 +122,7 @@ namespace SHADE { case SHCollisionShape::Type::SPHERE: { - const SHSphereCollisionShape* SPHERE = dynamic_cast(SHAPE); - - // Compute transforms of sphere - const SHVec3 POSITION = SPHERE->GetCenter(); // Position offset is already computed here - const SHVec3 ROTATION = collider.GetOrientation().ToEuler() + SPHERE->GetRotationOffset(); - const SHVec3 SCALE { SPHERE->GetWorldRadius() }; - - // Compute TRS for the sphere - const SHMatrix TRS = SHMatrix::Transform(POSITION, ROTATION, SCALE); - - debugDrawSystem->DrawWireSphere(TRS, DRAW_COLOUR, true); + debugDrawSystem->DrawWireSphere(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true); break; } -- 2.40.1 From cf9d4ef04bf518a3a370ad6312dbbdbe352a5f42 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 19 Dec 2022 16:56:34 +0800 Subject: [PATCH 21/84] Implemented backbone for collision detection with broadphase --- Assets/Scenes/PhysicsSandbox.shade | 42 +- SHADE_Engine/src/Math/Geometry/SHBox.h | 2 +- .../Broadphase/SHDynamicAABBTree.cpp | 607 ++++++++++++++++++ .../Collision/Broadphase/SHDynamicAABBTree.h | 150 +++++ .../CollisionShapes/SHCollisionShape.h | 6 +- .../CollisionShapes/SHCollisionShapeID.h | 14 +- .../CollisionShapes/SHCollisionShapeID.hpp | 20 +- .../SHSphereCollisionShape.cpp | 7 +- .../CollisionShapes/SHSphereCollisionShape.h | 3 + .../Collision/Contacts/SHCollisionEvents.h | 60 ++ .../Collision/Contacts/SHCollisionID.cpp | 152 +++++ .../Collision/Contacts/SHCollisionID.h | 121 ++++ .../Physics/Collision/Contacts/SHContact.h | 70 ++ .../Physics/Collision/Contacts/SHManifold.h | 46 ++ .../Collision/Narrowphase/SHCollision.h | 52 ++ .../Narrowphase/SHCollisionDispatch.cpp | 95 +++ .../Narrowphase/SHCollisionDispatch.h | 87 +++ .../Narrowphase/SHSphereVsSphere.cpp | 78 +++ .../src/Physics/Collision/SHCollider.cpp | 56 +- .../src/Physics/Collision/SHCollider.h | 4 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 373 ++++++++++- .../src/Physics/Dynamics/SHPhysicsWorld.h | 74 ++- 22 files changed, 2064 insertions(+), 55 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h create mode 100644 SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h create mode 100644 SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h create mode 100644 SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h create mode 100644 SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 7381b70c..8817b62e 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 1.77475965, z: 0} + Translate: {x: 0, y: 3, z: 0} Rotate: {x: 0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -58,4 +58,44 @@ Far: 10000 Perspective: true IsActive: true + Scripts: ~ +- EID: 2 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 1, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: true + Colliders: + - Is Trigger: false + Type: Sphere + Radius: 1 + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h index a0ca9458..63383c00 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.h +++ b/SHADE_Engine/src/Math/Geometry/SHBox.h @@ -77,7 +77,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; [[nodiscard]] bool Contains (const SHBox& rhs) const noexcept; [[nodiscard]] float Volume () const noexcept; diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp new file mode 100644 index 00000000..db30222b --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -0,0 +1,607 @@ +/**************************************************************************************** + * \file SHDynamicAABBTree.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Dynamic AABB Tree for broadphase collision detection. + * + * \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 + +#include + +// Primary Header +#include "SHDynamicAABBTree.h" + +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHAABBTree::SHAABBTree() noexcept + : root { NULL_NODE } + , nodes { nullptr } + , nodeCount { 0 } + , capacity { 1024 } + , freeList { NULL_NODE } + { + // Build initial tree + nodes = new Node[1024]; + + addToFreeList(0); + } + + SHAABBTree::~SHAABBTree() noexcept + { + delete[] nodes; + } + + SHAABBTree::Node::Node() noexcept + : id { MAX_EID, std::numeric_limits::max() } + , parent { NULL_NODE } + , left { NULL_NODE } + , right { NULL_NODE } + , height { NULL_NODE } + {} + + SHAABBTree::Node::Node(const Node& rhs) noexcept + : AABB { rhs.AABB } + , id { rhs.id } + , next { rhs.next } + , left { rhs.left } + , right { rhs.right } + , height { rhs.height } + {} + + SHAABBTree::Node::Node(Node&& rhs) noexcept + : AABB { rhs.AABB } + , id { rhs.id } + , next { rhs.next } + , left { rhs.left } + , right { rhs.right } + , height { rhs.height } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHAABBTree::Node& SHAABBTree::Node::operator=(const Node& rhs) noexcept + { + if (this == &rhs) + return *this; + + AABB = rhs.AABB; + id = rhs.id; + parent = rhs.parent; + next = rhs.next; + left = rhs.left; + right = rhs.right; + height = rhs.height; + + return *this; + } + + SHAABBTree::Node& SHAABBTree::Node::operator=(Node&& rhs) noexcept + { + AABB = std::move(rhs.AABB); + id = std::move(rhs.id); + parent = rhs.parent; + next = rhs.next; + left = rhs.left; + right = rhs.right; + height = rhs.height; + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const std::vector& SHAABBTree::GetAABBs() const noexcept + { + static std::vector aabbs; + static std::stack nodeIndices; + + aabbs.clear(); + + nodeIndices.push(root); + while (!nodeIndices.empty()) + { + // Pop the top node + const int INDEX = nodeIndices.top(); + nodeIndices.pop(); + + // Skip null nodes + if (INDEX == NULL_NODE) + continue; + + const Node& CURRENT_NODE = nodes[INDEX]; + + aabbs.emplace_back(CURRENT_NODE.AABB); + + if (!isLeaf(INDEX)) + { + nodeIndices.push(CURRENT_NODE.left); + nodeIndices.push(CURRENT_NODE.right); + } + } + + return aabbs; + } + + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHAABBTree::Insert(SHCollisionShapeID id, const SHBox& AABB) + { + const int32_t NEW_INDEX = allocateNode(); + + if (!nodeMap.emplace(id, NEW_INDEX).second) + { + // Attempted to add a duplicate node + freeNode(NEW_INDEX); + return; + } + + Node& newNode = nodes[NEW_INDEX]; + newNode.AABB = AABB; + newNode.id = id; + newNode.height = 0; + + // Fatten the AABB + const SHVec3 EXTENSION{ AABB_EXTENSION }; + + const SHVec3 newMin = newNode.AABB.GetMin() - EXTENSION; + const SHVec3 newMax = newNode.AABB.GetMax() + EXTENSION; + + newNode.AABB.SetMin(newMin); + newNode.AABB.SetMax(newMax); + + insertLeaf(NEW_INDEX); + } + + void SHAABBTree::Update(SHCollisionShapeID id, const SHBox& AABB) + { + // Get node index + const int32_t INDEX_TO_UPDATE = nodeMap[id]; + + Node& nodeToUpdate = nodes[INDEX_TO_UPDATE]; + + // If new AABB has not moved enough, skip. + if (nodeToUpdate.AABB.Contains(AABB)) + return; + + removeLeaf(INDEX_TO_UPDATE); + + nodeToUpdate.AABB = AABB; + + // Fatten the AABB + const SHVec3 EXTENSION{ AABB_EXTENSION }; + + const SHVec3 newMin = nodeToUpdate.AABB.GetMin() - EXTENSION; + const SHVec3 newMax = nodeToUpdate.AABB.GetMax() + EXTENSION; + + nodeToUpdate.AABB.SetMin(newMin); + nodeToUpdate.AABB.SetMax(newMax); + + insertLeaf(INDEX_TO_UPDATE); + } + + void SHAABBTree::Remove(SHCollisionShapeID id) noexcept + { + // Get node index + const int32_t INDEX_TO_REMOVE = nodeMap[id]; + + removeLeaf(INDEX_TO_REMOVE); + freeNode(INDEX_TO_REMOVE); + } + + const std::vector& SHAABBTree::Query(SHCollisionShapeID id, const SHBox& AABB) const noexcept + { + static std::vector potentialCollisions; + static std::stack nodeIndices; + + potentialCollisions.clear(); + + // We use this to ignore shapes on the same entity + const EntityID EID = id.GetEntityID(); + + nodeIndices.push(root); + while (!nodeIndices.empty()) + { + const int32_t INDEX = nodeIndices.top(); + nodeIndices.pop(); + + if (INDEX == NULL_NODE) + continue; + + const Node& NODE = nodes[INDEX]; + if (!SHBox::Intersect(AABB, NODE.AABB)) + continue; + + // Avoid checking against shapes of the same composite collider (and itself) + if (isLeaf(INDEX) && NODE.id.GetEntityID() != EID) + { + potentialCollisions.emplace_back(NODE.id); + } + else + { + nodeIndices.push(NODE.left); + nodeIndices.push(NODE.right); + } + } + + return potentialCollisions; + } + + const std::vector& SHAABBTree::Query(const SHRay& ray, float distance) const noexcept + { + static std::vector potentialHits; + + potentialHits.clear(); + + return potentialHits; + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHAABBTree::isLeaf(int32_t index) const noexcept + { + const Node& NODE = nodes[index]; + return NODE.left == NULL_NODE && NODE.right == NULL_NODE; + } + + int32_t SHAABBTree::allocateNode() + { + if (freeList == NULL_NODE) + { + // No more free nodes available, so we need to resize the tree for more nodes + capacity *= 2; + + Node* newNodes = new Node[capacity]; + + // Copy all the nodes manually. I do this instead of memcpy to guarantee it copies properly. + for (int32_t i = 0; i < nodeCount; ++i) + { + newNodes[i].AABB = nodes[i].AABB; + newNodes[i].id = nodes[i].id; + newNodes[i].parent = nodes[i].parent; + newNodes[i].left = nodes[i].left; + newNodes[i].right = nodes[i].right; + newNodes[i].height = nodes[i].height; + } + + delete[] nodes; + nodes = newNodes; + + addToFreeList(nodeCount); + } + + const int32_t FREE_NODE = freeList; + freeList = nodes[FREE_NODE].next; + + // Set node to default + Node& newNode = nodes[FREE_NODE]; + newNode.parent = NULL_NODE; + newNode.left = NULL_NODE; + newNode.right = NULL_NODE; + newNode.height = NULL_NODE; + + ++nodeCount; + return FREE_NODE; + } + + void SHAABBTree::freeNode(int32_t index) noexcept + { + SHASSERT(index >= 0 && index < capacity, "Trying to free an invalid AABB Tree node!") + + nodes[index].next = NULL_NODE; + nodes[index].height = NULL_NODE; + + // Put it back on the free list + freeList = index; + + --nodeCount; + } + + void SHAABBTree::insertLeaf(int32_t index) + { + // If there is no root, the first insert must make the root + if (root == NULL_NODE) + { + root = index; + nodes[root].parent = NULL_NODE; + return; + } + + // Find best sibling for new leaf + // Utilise Surface Area Heuristic + const SHBox& LEAF_AABB = nodes[index].AABB; + + uint32_t searchIndex = root; + while (!isLeaf(searchIndex)) + { + const SHBox COMBINED_AABB = SHBox::Combine(LEAF_AABB, nodes[searchIndex].AABB); + const float COMBINED_AREA = COMBINED_AABB.SurfaceArea(); + + const float INHERITED_COST = 2.0f * (COMBINED_AREA - nodes[searchIndex].AABB.SurfaceArea()); + + const int32_t LEFT_INDEX = nodes[searchIndex].left; + const int32_t RIGHT_INDEX = nodes[searchIndex].right; + + float leftCost = 0.0f; + float rightCost = 0.0f; + + const float LEFT_COMBINED_AREA = SHBox::Combine(LEAF_AABB, nodes[LEFT_INDEX].AABB).SurfaceArea(); + const float RIGHT_COMBINED_AREA = SHBox::Combine(LEAF_AABB, nodes[RIGHT_INDEX].AABB).SurfaceArea(); + + // Compute cost for descending into the left + if (isLeaf(LEFT_INDEX)) + leftCost = LEFT_COMBINED_AREA + INHERITED_COST; + else + leftCost = LEFT_COMBINED_AREA - nodes[LEFT_INDEX].AABB.SurfaceArea() + INHERITED_COST; + + // Compute cost for descending into the right + if (isLeaf(RIGHT_INDEX)) + rightCost = RIGHT_COMBINED_AREA + INHERITED_COST; + else + rightCost = RIGHT_COMBINED_AREA - nodes[RIGHT_INDEX].AABB.SurfaceArea() + INHERITED_COST; + + // Early out + const float BRANCH_COST = 2.0f * COMBINED_AREA; + if (BRANCH_COST < leftCost && BRANCH_COST < rightCost) + break; + + // Traverse + searchIndex = leftCost < rightCost ? LEFT_INDEX : RIGHT_INDEX; + } + + const int32_t BEST_SIBLING = searchIndex; + + // Create a new parent for the leaf + const int32_t OLD_PARENT = nodes[BEST_SIBLING].parent; + const int32_t NEW_PARENT = allocateNode(); + + Node& newParent = nodes[NEW_PARENT]; + newParent.parent = OLD_PARENT; + newParent.id = SHCollisionShapeID{ MAX_EID, std::numeric_limits::max() }; + newParent.AABB = SHBox::Combine(LEAF_AABB, nodes[BEST_SIBLING].AABB); + newParent.height = nodes[BEST_SIBLING].height + 1; + + newParent.left = BEST_SIBLING; + newParent.right = index; + + nodes[BEST_SIBLING].parent = NEW_PARENT; + nodes[index].parent = NEW_PARENT; + + // If sibling was the root + if (OLD_PARENT == NULL_NODE) + root = NEW_PARENT; + else + (nodes[OLD_PARENT].left == BEST_SIBLING ? nodes[OLD_PARENT].left : nodes[OLD_PARENT].right) = NEW_PARENT; + + syncHierarchy(NEW_PARENT); + } + + void SHAABBTree::removeLeaf(int32_t index) + { + if (index == root) + { + root = NULL_NODE; + return; + } + + const int32_t PARENT = nodes[index].parent; + const int32_t GRANDPARENT = nodes[PARENT].parent; + const int32_t SIBLING = nodes[PARENT].left == index ? nodes[PARENT].right : nodes[PARENT].left; + + if (GRANDPARENT != NULL_NODE) + { + // Replace parent with sibling + (nodes[GRANDPARENT].left == PARENT ? nodes[GRANDPARENT].left : nodes[GRANDPARENT].right) = SIBLING; + nodes[SIBLING].parent = GRANDPARENT; + } + else + { + // Parent was root + root = SIBLING; + nodes[SIBLING].parent = NULL_NODE; + } + + freeNode(PARENT); + syncHierarchy(GRANDPARENT); + } + + void SHAABBTree::syncHierarchy(int32_t index) + { + while (index != NULL_NODE) + { + index = balance(index); + + const int32_t LEFT_INDEX = nodes[index].left; + const Node& LEFT_NODE = nodes[LEFT_INDEX]; + + const int32_t RIGHT_INDEX = nodes[index].right; + const Node& RIGHT_NODE = nodes[RIGHT_INDEX]; + + nodes[index].height = 1 + SHMath::Max(LEFT_NODE.height, RIGHT_NODE.height); + nodes[index].AABB = SHBox::Combine(LEFT_NODE.AABB, RIGHT_NODE.AABB); + + // Sync up to the root + index = nodes[index].parent; + } + } + + int32_t SHAABBTree::balance(int32_t index) + { + if (isLeaf(index) || nodes[index].height == 1) + return index; + + Node& nodeA = nodes[index]; + + const int32_t LEFT = nodeA.left; + const int32_t RIGHT = nodeA.right; + + const int32_t DIFF = nodes[RIGHT].height - nodes[LEFT].height; + + if (DIFF > 1) + return rotateLeft(index); + + if (DIFF < -1) + return rotateRight(index); + + return index; + } + + int32_t SHAABBTree::rotateLeft(int32_t index) + { + /**************************** + A C + / \ / \ + B C --> A F/G + / \ / \ + F G B G/F + ****************************/ + + // Promote C + + Node& nodeA = nodes[index]; + + const int32_t B = nodeA.left; + const int32_t C = nodeA.right; + + Node& nodeB = nodes[B]; + Node& nodeC = nodes[C]; + + const int32_t F = nodeC.left; + const int32_t G = nodeC.right; + + Node& nodeF = nodes[F]; + Node& nodeG = nodes[G]; + + if (nodeA.parent != NULL_NODE) + (nodes[nodeA.parent].left == index ? nodes[nodeA.parent].left : nodes[nodeA.parent].right) = C; + else + root = C; + + nodeC.left = index; + nodeC.parent = nodeA.parent; + nodeA.parent = C; + + if (nodeF.height > nodeG.height) + { + nodeC.right = F; + nodeA.right = G; + nodeG.parent = index; + + nodeA.AABB = SHBox::Combine(nodeB.AABB, nodeG.AABB); + nodeC.AABB = SHBox::Combine(nodeA.AABB, nodeF.AABB); + + nodeA.height = 1 + SHMath::Max(nodeB.height, nodeG.height); + nodeC.height = 1 + SHMath::Max(nodeA.height, nodeF.height); + } + else + { + nodeC.right = G; + nodeA.right = F; + nodeF.parent = index; + + nodeA.AABB = SHBox::Combine(nodeB.AABB, nodeF.AABB); + nodeC.AABB = SHBox::Combine(nodeA.AABB, nodeG.AABB); + + nodeA.height = 1 + SHMath::Max(nodeB.height, nodeF.height); + nodeC.height = 1 + SHMath::Max(nodeA.height, nodeG.height); + } + + return C; + } + + int32_t SHAABBTree::rotateRight(int32_t index) + { + /************************* + A B + / \ / \ + B C --> D/E A + / \ / \ + D E E/D C + *************************/ + + // Promote B + + Node& nodeA = nodes[index]; + + const int32_t B = nodeA.left; + const int32_t C = nodeA.right; + + Node& nodeB = nodes[B]; + Node& nodeC = nodes[C]; + + const int32_t D = nodeB.left; + const int32_t E = nodeB.right; + + Node& nodeD = nodes[D]; + Node& nodeE = nodes[E]; + + if (nodeA.parent != NULL_NODE) + (nodes[nodeA.parent].left == index ? nodes[nodeA.parent].left : nodes[nodeA.parent].right) = B; + else + root = B; + + nodeB.right = index; + nodeB.parent = nodeA.parent; + nodeA.parent = B; + + if (nodeD.height > nodeE.height) + { + nodeB.left = D; + nodeA.left = E; + nodeE.parent = index; + + nodeA.AABB = SHBox::Combine(nodeC.AABB, nodeE.AABB); + nodeB.AABB = SHBox::Combine(nodeA.AABB, nodeD.AABB); + + nodeA.height = 1 + SHMath::Max(nodeC.height, nodeE.height); + nodeB.height = 1 + SHMath::Max(nodeA.height, nodeD.height); + } + else + { + nodeB.left = E; + nodeA.left = D; + nodeD.parent = index; + + nodeA.AABB = SHBox::Combine(nodeC.AABB, nodeD.AABB); + nodeB.AABB = SHBox::Combine(nodeA.AABB, nodeE.AABB); + + nodeA.height = 1 + SHMath::Max(nodeC.height, nodeD.height); + nodeB.height = 1 + SHMath::Max(nodeA.height, nodeE.height); + } + + return B; + } + + void SHAABBTree::addToFreeList(int32_t index) noexcept + { + for (int32_t i = index; i < capacity; ++i) + { + nodes[i].next = i + 1; + nodes[i].height = NULL_NODE; + } + + nodes[capacity - 1].next = NULL_NODE; + nodes[capacity - 1].height = NULL_NODE; + + freeList = index; + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h new file mode 100644 index 00000000..973631a1 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h @@ -0,0 +1,150 @@ +/**************************************************************************************** + * \file SHDynamicAABBTree.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Dynamic AABB Tree for broadphase collision detection. + * + * \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 + +// Project Headers +#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a dynamic AABB Tree for collision detection. + */ + class SH_API SHAABBTree + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr int NULL_NODE = -1; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHAABBTree () noexcept; + ~SHAABBTree () noexcept; + + SHAABBTree(const SHAABBTree& other) = delete; + SHAABBTree(SHAABBTree&& other) noexcept = delete; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHAABBTree& operator=(const SHAABBTree& other) = delete; + SHAABBTree& operator=(SHAABBTree&& other) noexcept = delete; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const std::vector& GetAABBs () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void Insert (SHCollisionShapeID id, const SHBox& AABB); + void Update (SHCollisionShapeID id, const SHBox& AABB); + void Remove (SHCollisionShapeID id) noexcept; + + [[nodiscard]] const std::vector& Query(SHCollisionShapeID id, const SHBox& AABB) const noexcept; + [[nodiscard]] const std::vector& Query(const SHRay& ray, float distance) const noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct Node + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + Node () noexcept; + Node (const Node& rhs) noexcept; + Node (Node&& rhs) noexcept; + + ~Node () noexcept = default; + + /*-------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*-------------------------------------------------------------------------------*/ + + Node& operator=(const Node& rhs) noexcept; + Node& operator=(Node&& rhs) noexcept; + + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + SHBox AABB; + SHCollisionShapeID id; // Used to lookup the collision shape & entity for culling against itself + + union + { + int32_t parent; + int32_t next; + }; + + + int32_t left; + int32_t right; + int32_t height; // Leaves have a height of 0. Free nodes have a height of -1 + }; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr float AABB_EXTENSION = 0.2f; + + // For quick access + std::unordered_map nodeMap; + + int32_t root; + Node* nodes; // Dynamically allocated array of nodes. I use dynamic allocation as in the past, using a vector causes weird issues. + int32_t nodeCount; + int32_t capacity; // Used for resizing the tree. + int32_t freeList; // Stores the next available node on the free list. + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + bool isLeaf (int32_t index) const noexcept; + + int32_t allocateNode (); + void freeNode (int32_t index) noexcept; + + void insertLeaf (int32_t index); + void removeLeaf (int32_t index); + void syncHierarchy (int32_t index); + int32_t balance (int32_t index); + int32_t rotateLeft (int32_t index); + int32_t rotateRight (int32_t index); + + void addToFreeList (int32_t index) noexcept; + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 3c08e21a..dad59881 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -17,6 +17,7 @@ #include "Physics/Collision/CollisionTags/SHCollisionTags.h" #include "Physics/Collision/SHPhysicsMaterial.h" #include "SHCollisionShapeID.h" +#include "Math/Geometry/SHBox.h" #include "Math/Transform/SHTransform.h" namespace SHADE @@ -33,8 +34,10 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ + friend class SHCollider; friend class SHColliderComponent; friend class SHCollisionShapeFactory; + friend class SHPhysicsWorld; public: /*---------------------------------------------------------------------------------*/ @@ -120,6 +123,7 @@ namespace SHADE virtual void ComputeTransforms () noexcept = 0; [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; + [[nodiscard]] virtual SHBox ComputeAABB () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ @@ -136,7 +140,7 @@ namespace SHADE // Needed for conversion to euler angles SHVec3 rotationOffset; - uint8_t flags; // 0 0 wasColliding isColliding trigger capsule sphere box + uint8_t flags; // 0 0 0 isColliding trigger capsule sphere box SHCollisionTag* collisionTag; RTTR_ENABLE() diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h index a0f78177..09f712d1 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h @@ -10,6 +10,7 @@ #pragma once +// Project Headers #include "ECS_Base/Entity/SHEntity.h" namespace SHADE @@ -55,11 +56,14 @@ namespace SHADE SHCollisionShapeID& operator=(const SHCollisionShapeID& rhs) noexcept; SHCollisionShapeID& operator=(SHCollisionShapeID&& rhs) noexcept; + bool operator==(const SHCollisionShapeID& rhs) const; + /*---------------------------------------------------------------------------------*/ - /* Member Functions */ + /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - bool operator==(const SHCollisionShapeID& rhs) const; + [[nodiscard]] EntityID GetEntityID () const noexcept; + [[nodiscard]] uint32_t GetShapeIndex () const noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -69,8 +73,8 @@ namespace SHADE struct IDs { public: - EntityID entityID = MAX_EID; - uint32_t shapeID = std::numeric_limits::max(); + EntityID entityID = MAX_EID; + uint32_t shapeIndex = std::numeric_limits::max(); }; @@ -84,7 +88,7 @@ namespace SHADE /** * @brief - * Encapsulates a functor to hash a CollisionShapeKey + * Encapsulates a functor to hash a CollisionShapeID */ struct SHCollisionShapeIDHash { diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp index 234b2f6f..bb9ccb1f 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp @@ -25,11 +25,11 @@ namespace SHADE {} inline SHCollisionShapeID::SHCollisionShapeID(const SHCollisionShapeID& rhs) noexcept - : ids { rhs.ids.entityID, rhs.ids.shapeID } + : ids { rhs.ids.entityID, rhs.ids.shapeIndex } {} inline SHCollisionShapeID::SHCollisionShapeID(SHCollisionShapeID&& rhs) noexcept - : ids { rhs.ids.entityID, rhs.ids.shapeID } + : ids { rhs.ids.entityID, rhs.ids.shapeIndex } {} @@ -61,6 +61,20 @@ namespace SHADE inline std::size_t SHCollisionShapeIDHash::operator()(const SHCollisionShapeID& id) const { - return std::hash()(id.value); + return std::hash{}(id.value); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + inline EntityID SHCollisionShapeID::GetEntityID() const noexcept + { + return ids.entityID; + } + + inline uint32_t SHCollisionShapeID::GetShapeIndex() const noexcept + { + return ids.shapeIndex; } } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index e4bf68c3..a871a5eb 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -220,7 +220,12 @@ namespace SHADE Center , ROTATION , SCALE -); + ); + } + + SHBox SHSphereCollisionShape::ComputeAABB() const noexcept + { + return SHBox{ Center, SHVec3{ Radius } }; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 798c70b6..1325fc56 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -46,6 +46,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHCollider; + friend class SHCollision; friend class SHCompositeCollider; friend class SHCollisionShapeFactory; @@ -127,6 +128,8 @@ namespace SHADE [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; + [[nodiscard]] SHBox ComputeAABB () const noexcept override; + private: /*---------------------------------------------------------------------------------*/ /* Data Members */ diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h new file mode 100644 index 00000000..7abb397b --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h @@ -0,0 +1,60 @@ +/**************************************************************************************** + * \file SHCollisionID.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for Collision Information for Collision & Triggers. + * + * \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 "SHCollisionID.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + enum class SHCollisionState + { + ENTER + , STAY + , EXIT + + , TOTAL + , INVALID = -1 + }; + + /** + * @brief + * Encapsulates the event for an intersection between two collision shapes that do not + * have physical resolution. + */ + struct SH_API SHTriggerEvent + { + public: + SHCollisionID info; + SHCollisionState state; + }; + + /** + * @brief + * Encapsulates the event for an intersection between two collision shapes that do + * have physical resolution. + */ + struct SH_API SHCollisionEvent + { + public: + static constexpr int MAX_NUM_CONTACTS = 4; + + SHCollisionID info; + SHCollisionState state; + SHVec3 normal; + SHVec3 contactPoints[MAX_NUM_CONTACTS]; + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp new file mode 100644 index 00000000..fae14aca --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp @@ -0,0 +1,152 @@ +/**************************************************************************************** + * \file SHCollisionInfo.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for Collision Info. + * + * \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 + +// Primary Header +#include "SHCollisionID.h" + +// Project Headers +#include "Physics/Collision/SHCollider.h" +#include "Physics/Interface/SHColliderComponent.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionID::SHCollisionID() noexcept + { + ids[ENTITY_A] = MAX_EID; + ids[ENTITY_B] = MAX_EID; + ids[SHAPE_INDEX_A] = std::numeric_limits::max(); + ids[SHAPE_INDEX_B] = std::numeric_limits::max(); + } + + SHCollisionID::SHCollisionID(const SHCollisionID& rhs) noexcept + { + value[0] = rhs.value[0]; + value[1] = rhs.value[1]; + } + + SHCollisionID::SHCollisionID(SHCollisionID&& rhs) noexcept + { + value[0] = rhs.value[0]; + value[1] = rhs.value[1]; + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollisionID& SHCollisionID::operator=(const SHCollisionID& rhs) noexcept + { + if (this == &rhs) + return *this; + + value[0] = rhs.value[0]; + value[1] = rhs.value[1]; + + return *this; + } + + SHCollisionID& SHCollisionID::operator=(SHCollisionID&& rhs) noexcept + { + value[0] = rhs.value[0]; + value[1] = rhs.value[1]; + + return *this; + } + + bool SHCollisionID::operator==(const SHCollisionID& rhs) const + { + // When checking for equal, check both ways. + // Exact Match (A, idxA, B, idxB) + const bool EXACT_MATCH = value[0] == rhs.value[0] && value[1] == rhs.value[1]; + + // Flipped Match: (B, idxB, A, idxA) + const bool FLIPPED_MATCH = value[0] == rhs.value[1] && value[1] == rhs.value[0]; + + return EXACT_MATCH || FLIPPED_MATCH; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + EntityID SHCollisionID::GetEntityA() const noexcept + { + return ids[ENTITY_A]; + } + + EntityID SHCollisionID::GetEntityB() const noexcept + { + return ids[ENTITY_B]; + } + + uint32_t SHCollisionID::GetShapeIndexA() const noexcept + { + return ids[SHAPE_INDEX_A]; + } + + uint32_t SHCollisionID::GetShapeIndexB() const noexcept + { + return ids[SHAPE_INDEX_B]; + } + + const SHRigidBodyComponent* SHCollisionID::GetRigidBodyA() const noexcept + { + return SHComponentManager::GetComponent_s(ids[ENTITY_A]); + } + + const SHRigidBodyComponent* SHCollisionID::GetRigidBodyB() const noexcept + { + return SHComponentManager::GetComponent_s(ids[ENTITY_B]); + } + + const SHCollisionShape* SHCollisionID::GetCollisionShapeA() const noexcept + { + const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_A]); + return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[SHAPE_INDEX_A]); + } + + const SHCollisionShape* SHCollisionID::GetCollisionShapeB() const noexcept + { + const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_B]); + return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[SHAPE_INDEX_B]); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionID::SetEntityA(EntityID entityID) noexcept + { + ids[ENTITY_A] = entityID; + } + + void SHCollisionID::SetEntityB(EntityID entityID) noexcept + { + ids[ENTITY_B] = entityID; + } + + void SHCollisionID::SetCollisionShapeA(uint32_t shapeIndexA) noexcept + { + ids[SHAPE_INDEX_A] = shapeIndexA; + } + + void SHCollisionID::SetCollisionShapeB(uint32_t shapeIndexB) noexcept + { + ids[SHAPE_INDEX_B] = shapeIndexB; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h new file mode 100644 index 00000000..78b28a96 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h @@ -0,0 +1,121 @@ +/**************************************************************************************** + * \file SHCollisionID.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for Collision Information for Collision & Triggers. + * + * \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 "Physics/Interface/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + struct SHCollisionIDHash; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates the information when two colliders intersect and do not have physical + * resolution. + */ + class SH_API SHCollisionID + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend struct SHCollisionIDHash; + + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionID () noexcept; + SHCollisionID (const SHCollisionID& rhs) noexcept; + SHCollisionID (SHCollisionID&& rhs) noexcept; + + ~SHCollisionID () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionID& operator= (const SHCollisionID& rhs) noexcept; + SHCollisionID& operator= (SHCollisionID&& rhs) noexcept; + + bool operator==(const SHCollisionID& rhs) const; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] EntityID GetEntityA () const noexcept; + [[nodiscard]] EntityID GetEntityB () const noexcept; + [[nodiscard]] uint32_t GetShapeIndexA () const noexcept; + [[nodiscard]] uint32_t GetShapeIndexB () const noexcept; + [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept; + [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept; + [[nodiscard]] const SHCollisionShape* GetCollisionShapeA () const noexcept; + [[nodiscard]] const SHCollisionShape* GetCollisionShapeB () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetEntityA (EntityID entityID) noexcept; + void SetEntityB (EntityID entityID) noexcept; + void SetCollisionShapeA (uint32_t shapeIndexA) noexcept; + void SetCollisionShapeB (uint32_t shapeIndexB) noexcept; + + private: + + static constexpr uint32_t ENTITY_A = 0; + static constexpr uint32_t SHAPE_INDEX_A = 1; + static constexpr uint32_t ENTITY_B = 2; + static constexpr uint32_t SHAPE_INDEX_B = 3; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + union + { + uint64_t value[2]; // EntityValue, ShapeIndexValue + uint32_t ids [4]; // EntityA, EntityB, ShapeIndexA, ShapeIndexB + }; + }; + + /** + * @brief + * Encapsulates a functor to hash a CollisionID + */ + struct SHCollisionIDHash + { + public: + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + inline std::size_t operator()(const SHCollisionID& id) const + { + return std::hash{}(std::u32string_view(reinterpret_cast::const_pointer>(id.ids), 4)); + } + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h new file mode 100644 index 00000000..c70f6e39 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -0,0 +1,70 @@ +/**************************************************************************************** + * \file SHManifold.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collision Manifold + * + * \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 "Physics/Dynamics/SHRigidBody.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a value that represents the touching features of a contact. + */ + union SHContactFeatures + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + struct + { + uint8_t incomingIncident; + uint8_t outgoingIncident; + uint8_t incomingReference; + uint8_t outgoingReference; + }; + + uint32_t key = 0; + }; + + /** + * @brief + * Encapsulates a physical collision contact. + */ + struct SH_API SHContact + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr int NUM_TANGENTS = 2; + + float penetration = 0.0f; + float bias = 0.0f; + float normalImpulse = 0.0f; + float normalMass = 0.0f; + float tangentImpulse[NUM_TANGENTS] = { 0.0f }; + float tangentMass[NUM_TANGENTS] = { 0.0f }; + + SHVec3 position; + SHContactFeatures featurePair; + }; +} + +#pragma once diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h new file mode 100644 index 00000000..da6fe233 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h @@ -0,0 +1,46 @@ +/**************************************************************************************** + * \file SHManifold.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collision Manifold + * + * \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 "Physics/Dynamics/SHRigidBody.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" +#include "SHContact.h" +#include "SHCollisionEvents.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + struct SH_API SHManifold + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + // We only need 4 contact points to build a stable manifold. + static constexpr int MAX_NUM_CONTACTS = 4; + + SHCollisionShape* A = nullptr; + SHCollisionShape* B = nullptr; + + SHVec3 normal; + SHVec3 tangents[SHContact::NUM_TANGENTS]; + + SHContact contacts[MAX_NUM_CONTACTS]; + uint32_t numContacts = 0; + SHCollisionState state; + }; + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h new file mode 100644 index 00000000..befb16f6 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -0,0 +1,52 @@ +/**************************************************************************************** + * \file SHCollision.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the Detecting Collisions between two shapes + * + * \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 "Physics/Collision/CollisionShapes/SHCollisionShape.h" +#include "Physics/Collision/Contacts/SHManifold.h" +#include "Physics/Collision/Contacts/SHCollisionID.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates static methods for testing for collision between two shapes. + */ + class SH_API SHCollision + { + public: + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /* Spheres VS X */ + + [[nodiscard]] static bool SphereVsSphere (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool SphereVsSphere (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + + /* Capsule VS X */ + + /* Polygon VS X */ + + private: + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp new file mode 100644 index 00000000..c06e30ae --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp @@ -0,0 +1,95 @@ +/**************************************************************************************** + * \file SHCollisionDispatch.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the static Collision Dispatcher + * + * \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 + +// Primary Header +#include "SHCollisionDispatch.h" + +// Project Header +#include "SHCollision.h" +#include "Tools/Utilities/SHUtilities.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHCollisionDispatcher::ManifoldCollide SHCollisionDispatcher::manifoldCollide[NUM_SHAPES][NUM_SHAPES] + { + // TODO + // vs Sphere / Box / Capsule + + { SHCollision::SphereVsSphere, nullptr, nullptr } // Sphere + , { nullptr, nullptr, nullptr } // Box + , { nullptr, nullptr, nullptr } // Capsule + }; + + const SHCollisionDispatcher::TriggerCollide SHCollisionDispatcher::triggerCollide[NUM_SHAPES][NUM_SHAPES] + { + // TODO + // vs Sphere / Box / Capsule + + { SHCollision::SphereVsSphere, nullptr, nullptr } // Sphere + , { nullptr, nullptr, nullptr } // Box + , { nullptr, nullptr, nullptr } // Capsule + }; + + const bool SHCollisionDispatcher::collisionTable[NUM_TYPES][NUM_TYPES] + { + /* S ST K KT D DT */ + /* S */ { false, false, false, true, true, true } + , /* ST */ { false, false, true, true, true, true } + , /* K */ { false, true, false, true, true, true } + , /* KT */ { true, true, true, true, true, true } + , /* D */ { true, true, true, true, true, true } + , /* DT */ { true, true, true, true, true, true } + }; + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollisionDispatcher::ShouldCollide(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + // Filter through collision table + const int TYPE_A = SHUtilities::ConvertEnum(A.GetType()) + A.IsTrigger() ? TYPE_OFFSET : 0; + const int TYPE_B = SHUtilities::ConvertEnum(B.GetType()) + B.IsTrigger() ? TYPE_OFFSET : 0; + + if (!collisionTable[TYPE_A][TYPE_B]) + return false; + + // Filter through tags + const uint16_t TAG_A = A.GetCollisionTag().GetMask(); + const uint16_t TAG_B = B.GetCollisionTag().GetMask(); + + const uint16_t MATCH = TAG_A & TAG_B; + return MATCH > 0; + } + + bool SHCollisionDispatcher::Collide(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + const int TYPE_A = SHUtilities::ConvertEnum(A.GetType()); + const int TYPE_B = SHUtilities::ConvertEnum(B.GetType()); + + return manifoldCollide[TYPE_A][TYPE_B](manifold, A, B); + } + + bool SHCollisionDispatcher::Collide(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + const int TYPE_A = SHUtilities::ConvertEnum(A.GetType()); + const int TYPE_B = SHUtilities::ConvertEnum(B.GetType()); + + return triggerCollide[TYPE_A][TYPE_B](A, B); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h new file mode 100644 index 00000000..4c132746 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h @@ -0,0 +1,87 @@ +/**************************************************************************************** + * \file SHCollisionDispatch.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the static Collision Dispatcher + * + * \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 "Physics/Collision/Contacts/SHManifold.h" +#include "Physics/Collision/Contacts/SHCollisionID.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates static methods for running narrow-phase collision detection. + */ + class SH_API SHCollisionDispatcher + { + public: + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Filters the collision through the collision table and layer matching. + * @param A + * A Collision Shape. + * @param B + * A Collision Shape. + * @return + * True if both shapes should be tested for collision. + */ + static bool ShouldCollide (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + static bool Collide (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + static bool Collide (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using ManifoldCollide = bool(*)(SHManifold&, const SHCollisionShape& A, const SHCollisionShape& B); + using TriggerCollide = bool(*)(const SHCollisionShape& A, const SHCollisionShape& B); + + enum class Types + { + STATIC + , KINEMATIC + , DYNAMIC + , STATIC_TRIGGER + , KINEMATIC_TRIGGER + , DYNAMIC_TRIGGER + + , COUNT + }; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + // Read the Types enum class, then see where it's used and it'll make sense + static constexpr int TYPE_OFFSET = 3; + + static constexpr int NUM_SHAPES = static_cast(SHCollisionShape::Type::COUNT); + static constexpr int NUM_TYPES = static_cast(Types::COUNT); + + static const ManifoldCollide manifoldCollide [NUM_SHAPES][NUM_SHAPES]; + static const TriggerCollide triggerCollide [NUM_SHAPES][NUM_SHAPES]; + + static const bool collisionTable [NUM_TYPES][NUM_TYPES]; + + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp new file mode 100644 index 00000000..b26a33dd --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp @@ -0,0 +1,78 @@ +/**************************************************************************************** + * \file SHSphereVsSphere.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Detecting Collisions between two spheres + * + * \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 + +// Primary Header +#include "SHCollision.h" + +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); + const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); + + return SHSphere::Intersect(SPHERE_A, SPHERE_B); + } + + bool SHCollision::SphereVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + // Convert to spheres + const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); + const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); + + 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()); + const float COMBINED_RADIUS_SQUARED = COMBINED_RADIUS * COMBINED_RADIUS; + + if (DISTANCE_BETWEEN_CENTERS_SQUARED > COMBINED_RADIUS_SQUARED) + return false; + + // Only populate the manifold if there is a collision + + uint32_t numContacts = 0; + + SHContact contact; + contact.featurePair.key = 0; + + if (SHMath::CompareFloat(DISTANCE_BETWEEN_CENTERS_SQUARED, 0.0f)) + { + manifold.normal = SHVec3::UnitY; + contact.position = SPHERE_A.GetCenter(); + contact.penetration = SPHERE_B.GetWorldRadius(); + + manifold.contacts[numContacts++] = contact; + } + else + { + manifold.normal = SHVec3::Normalise(A_TO_B); + contact.position = SPHERE_B.GetCenter() - (manifold.normal * SPHERE_B.GetWorldRadius()); + contact.penetration = COMBINED_RADIUS - A_TO_B.Length(); + + manifold.contacts[numContacts++] = contact; + } + + manifold.numContacts = numContacts; + + return true; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index a6527e48..24ba26b7 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -14,6 +14,7 @@ #include "SHCollider.h" // Project Headers +#include "Broadphase/SHDynamicAABBTree.h" #include "Events/SHEvent.h" #include "Math/SHMathHelpers.h" #include "Physics/SHPhysicsEvents.h" @@ -28,19 +29,21 @@ namespace SHADE SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept : entityID { eid } - , shapeIDCounter { 0 } , debugDraw { false } + , hasMoved { true } , rigidBody { nullptr } , shapeFactory { nullptr } + , broadphase { nullptr } , transform { worldTransform } {} SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } - , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } + , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } + , broadphase { rhs.broadphase } , transform { rhs.transform } { if (!shapeFactory) @@ -54,10 +57,11 @@ namespace SHADE SHCollider::SHCollider(SHCollider&& rhs) noexcept : entityID { rhs.entityID } - , shapeIDCounter { rhs.shapeIDCounter } , debugDraw { rhs.debugDraw } + , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } , shapeFactory { rhs.shapeFactory } + , broadphase { rhs.broadphase } , transform { rhs.transform } { if (!shapeFactory) @@ -98,8 +102,10 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; + hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; + broadphase = rhs.broadphase; transform = rhs.transform; copyShapes(rhs); @@ -117,8 +123,10 @@ namespace SHADE entityID = rhs.entityID; debugDraw = rhs.debugDraw; + hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; shapeFactory = rhs.shapeFactory; + broadphase = rhs.broadphase; transform = rhs.transform; copyShapes(rhs); @@ -199,21 +207,25 @@ namespace SHADE void SHCollider::SetTransform(const SHTransform& newTransform) noexcept { + hasMoved = true; transform = newTransform; } void SHCollider::SetPosition(const SHVec3& newPosition) noexcept { + hasMoved = true; transform.position = newPosition; } void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept { + hasMoved = true; transform.orientation = newOrientation; } void SHCollider::SetScale(const SHVec3& newScale) noexcept { + hasMoved = true; transform.scale = newScale; } @@ -255,10 +267,10 @@ namespace SHADE , .Scale = SPHERE_SCALE }; - const SHCollisionShapeID NEW_SHAPE_ID{ entityID, shapeIDCounter }; + const uint32_t NEW_INDEX = static_cast(shapes.size()); + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); - ++shapeIDCounter; // Set offsets sphere->SetParentTransform(transform); @@ -267,12 +279,15 @@ namespace SHADE shapes.emplace_back(sphere); + if (broadphase) + broadphase->Insert(NEW_SHAPE_ID, sphere->ComputeAABB()); + // Broadcast Event for adding a shape const SHPhysicsColliderAddedEvent EVENT_DATA { .entityID = entityID , .colliderType = SHCollisionShape::Type::SPHERE - , .colliderIndex = static_cast(shapes.size()) + , .colliderIndex = static_cast(NEW_INDEX) }; SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); @@ -280,7 +295,7 @@ namespace SHADE if (rigidBody) rigidBody->ComputeMassData(); - return static_cast(shapes.size()); + return static_cast(NEW_INDEX); } void SHCollider::RemoveCollisionShape(int index) @@ -296,8 +311,8 @@ namespace SHADE if (index < 0 || index >= NUM_SHAPES) throw std::invalid_argument("Out-of-range index!"); - auto shapeIter = shapes.begin(); - for (int i = 0; i < NUM_SHAPES; ++i, ++shapeIter) + auto shape = shapes.begin(); + for (int i = 0; i < NUM_SHAPES; ++i, ++shape) { if (i == index) break; @@ -306,15 +321,21 @@ namespace SHADE const SHPhysicsColliderRemovedEvent EVENT_DATA { .entityID = entityID - , .colliderType = (*shapeIter)->GetType() + , .colliderType = (*shape)->GetType() , .colliderIndex = index }; - shapeFactory->DestroyShape(*shapeIter); - *shapeIter = nullptr; + // Remove from broadphase + if (broadphase) + broadphase->Remove((*shape)->id); + + shapeFactory->DestroyShape(*shape); + *shape = nullptr; // Remove the shape from the container to prevent accessing a nullptr - shapeIter = shapes.erase(shapeIter); + shape = shapes.erase(shape); + + // Broadcast Event for removing a shape SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); @@ -337,12 +358,8 @@ namespace SHADE void SHCollider::copyShapes(const SHCollider& rhsCollider) { - shapeIDCounter = 0; for (const auto* shape : rhsCollider.shapes) - { copyShape(shape); - ++shapeIDCounter; - } } void SHCollider::copyShape(const SHCollisionShape* rhsShape) @@ -365,7 +382,8 @@ namespace SHADE , .Scale = RHS_SPHERE->scale }; - const SHCollisionShapeID NEW_SHAPE_ID{ entityID, shapeIDCounter }; + const uint32_t NEW_INDEX = static_cast(shapes.size()); + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); *sphere = *RHS_SPHERE; @@ -380,8 +398,6 @@ namespace SHADE } default: break; } - - ++shapeIDCounter; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 566bae3e..89ba5ff2 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -22,6 +22,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ class SHRigidBody; + class SHAABBTree; /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -155,12 +156,13 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ EntityID entityID; - uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. bool debugDraw; + bool hasMoved; SHRigidBody* rigidBody; SHCollisionShapeFactory* shapeFactory; + SHAABBTree* broadphase; SHTransform transform; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index b1b94792..4ff94b7d 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -14,6 +14,8 @@ #include "SHPhysicsWorld.h" // Project Headers +#include "Physics/Collision/Narrowphase/SHCollision.h" +#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h" namespace SHADE @@ -25,13 +27,52 @@ namespace SHADE SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept : settings { worldSettings } { - rigidBodies.clear(); SHLOG_INFO_D("Creating Physics World") } SHPhysicsWorld::~SHPhysicsWorld() noexcept { - rigidBodies.clear(); + + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept + { + static TriggerEvents triggerEvents; + + triggerEvents.clear(); + + for (auto& [id, state] : triggers) + triggerEvents.emplace_back(SHTriggerEvent{ id, state }); + + return triggerEvents; + } + + const SHPhysicsWorld::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept + { + static CollisionEvents collisionEvents; + + collisionEvents.clear(); + + for (auto& [id, manifold] : manifolds) + { + SHCollisionEvent collisionEvent + { + .info = id + , .state = manifold.state + , .normal = manifold.normal + }; + + for (uint32_t i = 0; i < manifold.numContacts; ++i) + collisionEvent.contactPoints[i] = manifold.contacts[i].position; + + collisionEvents.emplace_back(collisionEvent); + } + + return collisionEvents; } /*-----------------------------------------------------------------------------------*/ @@ -40,7 +81,7 @@ namespace SHADE void SHPhysicsWorld::AddRigidBody(SHRigidBody* rigidBody) noexcept { - const bool INSERTED = rigidBodies.emplace(rigidBody).second; + const bool INSERTED = rigidBodies.emplace(rigidBody->entityID, rigidBody).second; if (!INSERTED) { SHLOG_WARNING_D("Attempting to add duplicate rigid body {} to the Physics World!", rigidBody->entityID) @@ -49,37 +90,89 @@ namespace SHADE void SHPhysicsWorld::RemoveRigidBody(SHRigidBody* rigidBody) noexcept { - rigidBodies.erase(rigidBody); + rigidBodies.erase(rigidBody->entityID); - // Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep + // Attempt to remove any invalidated manifolds + if (manifolds.empty()) + return; + + for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) + { + const auto& ID = manifoldPair->first; + + const bool MATCHES_A = ID.GetEntityA() == rigidBody->entityID; + const bool MATCHES_B = ID.GetEntityB() == rigidBody->entityID; + + if (MATCHES_A || MATCHES_B) + manifoldPair = manifolds.erase(manifoldPair); + else + ++manifoldPair; + } + + // TODO: Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep } void SHPhysicsWorld::AddCollider(SHCollider* collider) noexcept { - const bool INSERTED = colliders.emplace(collider).second; + const bool INSERTED = colliders.emplace(collider->entityID, collider).second; if (!INSERTED) { SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID) + return; } + + collider->broadphase = &broadphase; + + // Add all existing shapes to the broadphase + for (const auto* shape : collider->shapes) + broadphase.Insert(shape->id, shape->ComputeAABB()); } void SHPhysicsWorld::RemoveCollider(SHCollider* collider) noexcept { - colliders.erase(collider); + colliders.erase(collider->entityID); - // Get collider's rigid body - // Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep + const uint32_t NUM_SHAPES = static_cast(collider->shapes.size()); + if (NUM_SHAPES == 0) + return; + + for (uint32_t i = 0; i < NUM_SHAPES; ++i) + { + const SHCollisionShape* SHAPE = collider->shapes[i]; + + broadphase.Remove(SHAPE->id); + + if (SHAPE->IsTrigger()) + removeInvalidatedTrigger(collider->entityID, i); + else + removeInvalidatedManifold(collider->entityID, i); + } + + /* + * TODO: + * 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::Step(float dt) { - for (auto* rigidBody : rigidBodies) + // Clear containers of exit state collisions + updateEvents(); + + // TODO: Profile each of these + runBroadphase (); + runNarrowphase(); + + for (auto* rigidBody : rigidBodies | std::views::values) { rigidBody->ComputeWorldData(); integrateForces(*rigidBody, dt); } - for (auto* rigidBody : rigidBodies) + for (auto* rigidBody : rigidBodies | std::views::values) integrateVelocities(*rigidBody, dt); } @@ -158,4 +251,262 @@ namespace SHADE // We clear forces for static bodies as well for redundancy rigidBody.ClearForces(); } + + void SHPhysicsWorld::runBroadphase() noexcept + { + // Update any colliders that have moved + for (auto& collider : colliders | std::views::values) + { + if (!collider->hasMoved) + continue; + + // Clear hasMoved flag here + collider->hasMoved = false; + + // Update moved shapes in broadphase + for (auto* shape : collider->shapes) + broadphase.Update(shape->id, shape->ComputeAABB()); + } + + // Query: Kinematic Triggers, Awake Dynamic Bodies & Dynamic Triggers + for (auto& collider : colliders | std::views::values) + { + // Default static bodies + if (!collider->rigidBody) + continue; + + // Explicit static bodies + const bool IS_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC; + if (IS_STATIC) + continue; + + // All remaining are kinematic or dynamic + // Iterate through shapes: if kinematic / dynamic trigger, else if dynamic & awake + if (collider->rigidBody->GetType() == SHRigidBody::Type::KINEMATIC) + queryKinematic(collider); + + if (collider->rigidBody->GetType() == SHRigidBody::Type::DYNAMIC) + queryDynamic(collider); + } + + } + + void SHPhysicsWorld::queryKinematic(SHCollider* collider) noexcept + { + for (auto* shape : collider->shapes) + { + // For kinematic shapes, we only query triggers against everything else + if (!shape->IsTrigger()) + continue; + + auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); + + // Build narrow-phase pairs + auto* shapeA = shape; + + const EntityID ID_A = shape->id.GetEntityID(); + const uint32_t INDEX_A = shape->id.GetShapeIndex(); + + for (auto& id : potentialCollisions) + { + // Get corresponding shape + const EntityID ID_B = id.GetEntityID(); + const uint32_t INDEX_B = id.GetShapeIndex(); + + auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); + + // Build collision ID + SHCollisionID collisionKey; + collisionKey.SetEntityA(ID_A); + collisionKey.SetEntityB(ID_B); + collisionKey.SetCollisionShapeA(INDEX_A); + collisionKey.SetCollisionShapeB(INDEX_B); + + // Check if it already exists. If it doesn't, put into batch. + auto narrowphasePair = narrowphaseBatch.find(collisionKey); + if (narrowphasePair == narrowphaseBatch.end()) + narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); + } + } + } + + void SHPhysicsWorld::queryDynamic(SHCollider* collider) noexcept + { + for (auto* shape : collider->shapes) + { + auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); + + // Build narrow-phase pairs + auto* shapeA = shape; + + const EntityID ID_A = shape->id.GetEntityID(); + const uint32_t INDEX_A = shape->id.GetShapeIndex(); + + for (auto& id : potentialCollisions) + { + // Get corresponding shape + const EntityID ID_B = id.GetEntityID(); + const uint32_t INDEX_B = id.GetShapeIndex(); + + auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); + + // Build collision ID + SHCollisionID collisionKey; + collisionKey.SetEntityA(ID_A); + collisionKey.SetEntityB(ID_B); + collisionKey.SetCollisionShapeA(INDEX_A); + collisionKey.SetCollisionShapeB(INDEX_B); + + // Check if it already exists. If it doesn't, put into batch. + auto narrowphasePair = narrowphaseBatch.find(collisionKey); + if (narrowphasePair == narrowphaseBatch.end()) + narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); + } + } + } + + void SHPhysicsWorld::runNarrowphase() noexcept + { + for (auto& [id, narrowphasePair] : narrowphaseBatch) + { + const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger(); + const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger(); + + // Check if ID exists in trigger + if (IS_A_TRIGGER || IS_B_TRIGGER) + collideTriggers(id, narrowphasePair); + else + collideManifolds(id, narrowphasePair); + } + } + + void SHPhysicsWorld::collideTriggers(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept + { + const auto* A = narrowphasePair.A; + const auto* B = narrowphasePair.B; + + const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B); + + auto trigger = triggers.find(id); + + // If id not found, emplace new object. + // New object is in the invalid state + if (trigger == triggers.end()) + trigger = triggers.emplace(id, SHCollisionState::INVALID).first; + + SHCollisionState& state = trigger->second; + updateCollisionState(COLLIDING, state); + + // If it was a false positive, remove the manifold immediately. + // Remove using iterator as it is on average faster. + if (state == SHCollisionState::INVALID) + trigger = triggers.erase(trigger); + } + + void SHPhysicsWorld::collideManifolds(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept + { + auto* A = narrowphasePair.A; + auto* B = narrowphasePair.B; + + SHManifold newManifold { .A = A, .B = B }; + const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B); + + auto manifold = manifolds.find(id); + + // If id not found, emplace new manifold + if (manifold == manifolds.end()) + manifold = manifolds.emplace(id, newManifold).first; + else + { + // TODO: Update existing manifolds with new data + } + + SHCollisionState& state = manifold->second.state; + updateCollisionState(COLLIDING, state); + + // If it was a false positive, remove the manifold immediately. + // Remove using iterator as it is on average faster. + if (state == SHCollisionState::INVALID) + manifold = manifolds.erase(manifold); + } + + void SHPhysicsWorld::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept + { + if (isColliding) + state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY; + else + state = SHCollisionState::EXIT; + } + + void SHPhysicsWorld::updateEvents() noexcept + { + // Clear expired or invalid collisions + for (auto manifold = manifolds.begin(); manifold != manifolds.end();) + { + const auto COLLISION_STATE = manifold->second.state; + + const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; + const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; + + if (IS_EXIT || IS_INVALID) + manifold = manifolds.erase(manifold); + else + ++manifold; + } + + // Clear expired or invalid triggers + for (auto trigger = triggers.begin(); trigger != triggers.end();) + { + const auto COLLISION_STATE = trigger->second; + + const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; + const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; + + if (IS_EXIT || IS_INVALID) + trigger = triggers.erase(trigger); + else + ++trigger; + } + } + + void SHPhysicsWorld::removeInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) + { + if (triggers.empty()) + return; + + for (auto invalidatedTrigger = triggers.begin(); invalidatedTrigger != triggers.end();) + { + const auto& ID = invalidatedTrigger->first; + + const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; + const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; + + if (MATCHES_A || MATCHES_B) + invalidatedTrigger = triggers.erase(invalidatedTrigger); + else + ++invalidatedTrigger; + } + } + + void SHPhysicsWorld::removeInvalidatedManifold(EntityID eid, uint32_t shapeIndex) + { + if (manifolds.empty()) + return; + + for (auto invalidatedManifold = manifolds.begin(); invalidatedManifold != manifolds.end();) + { + const auto& ID = invalidatedManifold->first; + + const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; + const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; + + if (MATCHES_A || MATCHES_B) + invalidatedManifold = manifolds.erase(invalidatedManifold); + else + ++invalidatedManifold; + } + } + + + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index 499230dd..f0d2cd5b 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -10,9 +10,12 @@ #pragma once -#include +#include // Project Headers +#include "Physics/Collision/Broadphase/SHDynamicAABBTree.h" +#include "Physics/Collision/Contacts/SHCollisionEvents.h" +#include "Physics/Collision/Contacts/SHManifold.h" #include "Physics/Collision/SHCollider.h" #include "SHRigidBody.h" @@ -44,6 +47,9 @@ namespace SHADE bool sleepingEnabled = true; }; + using TriggerEvents = std::vector; + using CollisionEvents = std::vector; + /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ @@ -54,7 +60,6 @@ namespace SHADE SHPhysicsWorld (const SHPhysicsWorld&) = delete; SHPhysicsWorld (SHPhysicsWorld&&) = delete; - /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ @@ -63,7 +68,14 @@ namespace SHADE SHPhysicsWorld& operator=(SHPhysicsWorld&&) = delete; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + const TriggerEvents& GetTriggerEvents () const noexcept; + const CollisionEvents& GetCollisionEvents () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ /*---------------------------------------------------------------------------------*/ void AddRigidBody (SHRigidBody* rigidBody) noexcept; @@ -79,27 +91,67 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - //! I realise using a set may be dangerous with pointers. An unordered_map may be better, but I don't need the entityIDs so... + struct NarrowphasePair + { + SHCollisionShape* A = nullptr; + SHCollisionShape* B = nullptr; + }; + + // EntityIDs are used to map resolved contraints back to bodies + using RigidBodies = std::unordered_map; + using Colliders = std::unordered_map; + + // Collisions + + using NarrowphaseBatch = std::unordered_map; + using Manifolds = std::unordered_map; + using Triggers = std::unordered_map; - using Colliders = std::unordered_set; - using RigidBodies = std::unordered_set; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - WorldSettings settings; + WorldSettings settings; - Colliders colliders; - RigidBodies rigidBodies; + // Containers + + RigidBodies rigidBodies; + Colliders colliders; + + NarrowphaseBatch narrowphaseBatch; + Manifolds manifolds; + Triggers triggers; + + // World components + + SHAABBTree broadphase; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept; - void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept; + // TODO: Move to island when islands are set up + void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept; + void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept; + + // Broadphase helpers + + void runBroadphase () noexcept; + void queryKinematic (SHCollider* collider) noexcept; + void queryDynamic (SHCollider* collider) noexcept; + + // Narrowphase helpers + + void runNarrowphase () noexcept; + void collideTriggers (const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept; + void collideManifolds (const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept; + void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; + + void updateEvents () noexcept; + void removeInvalidatedTrigger (EntityID eid, uint32_t shapeIndex); + void removeInvalidatedManifold (EntityID eid, uint32_t shapeIndex); }; -- 2.40.1 From 751a16dcc3a64a9f22eae66f11a66d858c766c1a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 20 Dec 2022 02:13:06 +0800 Subject: [PATCH 22/84] Tested collision detection with collision states --- Assets/Scenes/PhysicsSandbox.shade | 10 ++--- .../src/Application/SBApplication.cpp | 7 ++++ SHADE_Engine/src/Math/Geometry/SHBox.cpp | 2 +- .../Broadphase/SHDynamicAABBTree.cpp | 2 +- .../Collision/Broadphase/SHDynamicAABBTree.h | 10 ++++- .../SHSphereCollisionShape.cpp | 2 +- .../CollisionShapes/SHSphereCollisionShape.h | 6 +-- .../Physics/Collision/Contacts/SHManifold.h | 7 ++-- .../Narrowphase/SHSphereVsSphere.cpp | 10 ++--- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 30 ++++++++++++-- .../src/Physics/Dynamics/SHPhysicsWorld.h | 14 ++++++- .../Routines/SHPhysicsDebugDrawRoutine.cpp | 17 +++++++- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 2 + .../src/Physics/System/SHPhysicsSystem.cpp | 40 +++++++++++++------ .../src/Physics/System/SHPhysicsSystem.h | 13 +++--- 15 files changed, 125 insertions(+), 47 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 8817b62e..21840aca 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -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 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index aa5a4f0e..8607702d 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -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()->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBP); + } + SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, SHFrameRateController::GetRawDeltaTime()); editor->PollPicking(); #else diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp index 7261749b..05595fe1 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHBox.cpp @@ -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 diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index db30222b..540d5375 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -107,7 +107,7 @@ namespace SHADE const std::vector& SHAABBTree::GetAABBs() const noexcept { - static std::vector aabbs; + static AABBs aabbs; static std::stack nodeIndices; aabbs.clear(); diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h index 973631a1..f23fd946 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h @@ -28,6 +28,12 @@ namespace SHADE class SH_API SHAABBTree { public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using AABBs = std::vector; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ @@ -55,7 +61,7 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] const std::vector& 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 nodeMap; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index a871a5eb..b1110489 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -125,7 +125,7 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHVec3& SHSphereCollisionShape::GetCenter() const noexcept + SHVec3 SHSphereCollisionShape::GetCenter() const noexcept { return Center; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 1325fc56..eb41f93c 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -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 */ diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h index da6fe233..0534f749 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h @@ -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; + }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp index b26a33dd..8b529241 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp @@ -25,8 +25,8 @@ namespace SHADE bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); - const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); + const SHSphereCollisionShape& SPHERE_A = reinterpret_cast(A); + const SHSphereCollisionShape& SPHERE_B = reinterpret_cast(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(A); - const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); + const SHSphereCollisionShape& SPHERE_A = reinterpret_cast(A); + const SHSphereCollisionShape& SPHERE_B = reinterpret_cast(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()); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 4ff94b7d..ff362d69 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -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 diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index f0d2cd5b..e0e4f796 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -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: diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index 72b2aad5..b43b5b77 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -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(); auto* debugDrawSystem = SHSystemManager::GetSystem(); const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS); @@ -68,6 +68,10 @@ namespace SHADE } } + auto* physicsSystem = SHSystemManager::GetSystem(); + 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); + } } } diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 88ea8d79..178a6120 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -65,6 +65,8 @@ namespace SHADE physicsObject.collider->SetScale(WORLD_SCL); physicsObject.collider->RecomputeShapes(); + + physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider); } } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 20084ebe..975c561b 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -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(); - 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(); + // 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; } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index ce1f1396..f9866ebe 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -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]; -- 2.40.1 From 5def5392a1986250fbb0ddc6d90aa92646fbfad0 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 20 Dec 2022 02:26:31 +0800 Subject: [PATCH 23/84] Cleaned up CollisionKey object --- .../Collision/Contacts/SHCollisionEvents.h | 8 +-- .../{SHCollisionID.cpp => SHCollisionKey.cpp} | 52 ++++++++++++------- .../{SHCollisionID.h => SHCollisionKey.h} | 32 +++++------- .../Collision/Narrowphase/SHCollision.h | 2 +- .../Narrowphase/SHCollisionDispatch.h | 2 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 8 +-- .../src/Physics/Dynamics/SHPhysicsWorld.h | 10 ++-- .../src/Physics/System/SHPhysicsSystem.cpp | 49 ++--------------- .../src/Physics/System/SHPhysicsSystem.h | 13 ----- 9 files changed, 66 insertions(+), 110 deletions(-) rename SHADE_Engine/src/Physics/Collision/Contacts/{SHCollisionID.cpp => SHCollisionKey.cpp} (66%) rename SHADE_Engine/src/Physics/Collision/Contacts/{SHCollisionID.h => SHCollisionKey.h} (83%) diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h index 7abb397b..db55ca50 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHCollisionID.h + * \file SHCollisionKey.h * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Interface for Collision Information for Collision & Triggers. * @@ -11,7 +11,7 @@ #pragma once // Project Headers -#include "SHCollisionID.h" +#include "SHCollisionKey.h" namespace SHADE { @@ -37,7 +37,7 @@ namespace SHADE struct SH_API SHTriggerEvent { public: - SHCollisionID info; + SHCollisionKey info; SHCollisionState state; }; @@ -51,7 +51,7 @@ namespace SHADE public: static constexpr int MAX_NUM_CONTACTS = 4; - SHCollisionID info; + SHCollisionKey info; SHCollisionState state; SHVec3 normal; SHVec3 contactPoints[MAX_NUM_CONTACTS]; diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp similarity index 66% rename from SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp rename to SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp index fae14aca..4bb22697 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.cpp +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHCollisionID.h" +#include "SHCollisionKey.h" // Project Headers #include "Physics/Collision/SHCollider.h" @@ -24,7 +24,7 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollisionID::SHCollisionID() noexcept + SHCollisionKey::SHCollisionKey() noexcept { ids[ENTITY_A] = MAX_EID; ids[ENTITY_B] = MAX_EID; @@ -32,13 +32,13 @@ namespace SHADE ids[SHAPE_INDEX_B] = std::numeric_limits::max(); } - SHCollisionID::SHCollisionID(const SHCollisionID& rhs) noexcept + SHCollisionKey::SHCollisionKey(const SHCollisionKey& rhs) noexcept { value[0] = rhs.value[0]; value[1] = rhs.value[1]; } - SHCollisionID::SHCollisionID(SHCollisionID&& rhs) noexcept + SHCollisionKey::SHCollisionKey(SHCollisionKey&& rhs) noexcept { value[0] = rhs.value[0]; value[1] = rhs.value[1]; @@ -48,7 +48,7 @@ namespace SHADE /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollisionID& SHCollisionID::operator=(const SHCollisionID& rhs) noexcept + SHCollisionKey& SHCollisionKey::operator=(const SHCollisionKey& rhs) noexcept { if (this == &rhs) return *this; @@ -59,7 +59,7 @@ namespace SHADE return *this; } - SHCollisionID& SHCollisionID::operator=(SHCollisionID&& rhs) noexcept + SHCollisionKey& SHCollisionKey::operator=(SHCollisionKey&& rhs) noexcept { value[0] = rhs.value[0]; value[1] = rhs.value[1]; @@ -67,7 +67,7 @@ namespace SHADE return *this; } - bool SHCollisionID::operator==(const SHCollisionID& rhs) const + bool SHCollisionKey::operator==(const SHCollisionKey& rhs) const { // When checking for equal, check both ways. // Exact Match (A, idxA, B, idxB) @@ -83,43 +83,43 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - EntityID SHCollisionID::GetEntityA() const noexcept + EntityID SHCollisionKey::GetEntityA() const noexcept { return ids[ENTITY_A]; } - EntityID SHCollisionID::GetEntityB() const noexcept + EntityID SHCollisionKey::GetEntityB() const noexcept { return ids[ENTITY_B]; } - uint32_t SHCollisionID::GetShapeIndexA() const noexcept + uint32_t SHCollisionKey::GetShapeIndexA() const noexcept { return ids[SHAPE_INDEX_A]; } - uint32_t SHCollisionID::GetShapeIndexB() const noexcept + uint32_t SHCollisionKey::GetShapeIndexB() const noexcept { return ids[SHAPE_INDEX_B]; } - const SHRigidBodyComponent* SHCollisionID::GetRigidBodyA() const noexcept + const SHRigidBodyComponent* SHCollisionKey::GetRigidBodyA() const noexcept { return SHComponentManager::GetComponent_s(ids[ENTITY_A]); } - const SHRigidBodyComponent* SHCollisionID::GetRigidBodyB() const noexcept + const SHRigidBodyComponent* SHCollisionKey::GetRigidBodyB() const noexcept { return SHComponentManager::GetComponent_s(ids[ENTITY_B]); } - const SHCollisionShape* SHCollisionID::GetCollisionShapeA() const noexcept + const SHCollisionShape* SHCollisionKey::GetCollisionShapeA() const noexcept { const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_A]); return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[SHAPE_INDEX_A]); } - const SHCollisionShape* SHCollisionID::GetCollisionShapeB() const noexcept + const SHCollisionShape* SHCollisionKey::GetCollisionShapeB() const noexcept { const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_B]); return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[SHAPE_INDEX_B]); @@ -129,24 +129,38 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollisionID::SetEntityA(EntityID entityID) noexcept + void SHCollisionKey::SetEntityA(EntityID entityID) noexcept { ids[ENTITY_A] = entityID; } - void SHCollisionID::SetEntityB(EntityID entityID) noexcept + void SHCollisionKey::SetEntityB(EntityID entityID) noexcept { ids[ENTITY_B] = entityID; } - void SHCollisionID::SetCollisionShapeA(uint32_t shapeIndexA) noexcept + void SHCollisionKey::SetCollisionShapeA(uint32_t shapeIndexA) noexcept { ids[SHAPE_INDEX_A] = shapeIndexA; } - void SHCollisionID::SetCollisionShapeB(uint32_t shapeIndexB) noexcept + void SHCollisionKey::SetCollisionShapeB(uint32_t shapeIndexB) noexcept { ids[SHAPE_INDEX_B] = shapeIndexB; } + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + std::size_t SHCollisionKeyHash::operator()(const SHCollisionKey& id) const + { + static constexpr int NUM_IDS = ARRAYSIZE(id.ids); + + // Hashable is not a word. Sue me. + auto hashablePtr = reinterpret_cast::const_pointer>(id.ids); + return std::hash{}(std::u32string_view(hashablePtr, NUM_IDS)); + } + + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.h similarity index 83% rename from SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h rename to SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.h index 78b28a96..811f8375 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionID.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.h @@ -21,7 +21,7 @@ namespace SHADE /* Forward Declarations */ /*-----------------------------------------------------------------------------------*/ - struct SHCollisionIDHash; + struct SHCollisionKeyHash; /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -29,37 +29,36 @@ namespace SHADE /** * @brief - * Encapsulates the information when two colliders intersect and do not have physical - * resolution. + * Encapsulates the information when two collision shapes intersect. */ - class SH_API SHCollisionID + class SH_API SHCollisionKey { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend struct SHCollisionIDHash; + friend struct SHCollisionKeyHash; public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionID () noexcept; - SHCollisionID (const SHCollisionID& rhs) noexcept; - SHCollisionID (SHCollisionID&& rhs) noexcept; + SHCollisionKey () noexcept; + SHCollisionKey (const SHCollisionKey& rhs) noexcept; + SHCollisionKey (SHCollisionKey&& rhs) noexcept; - ~SHCollisionID () noexcept = default; + ~SHCollisionKey () noexcept = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHCollisionID& operator= (const SHCollisionID& rhs) noexcept; - SHCollisionID& operator= (SHCollisionID&& rhs) noexcept; + SHCollisionKey& operator= (const SHCollisionKey& rhs) noexcept; + SHCollisionKey& operator= (SHCollisionKey&& rhs) noexcept; - bool operator==(const SHCollisionID& rhs) const; + bool operator==(const SHCollisionKey& rhs) const; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -103,19 +102,16 @@ namespace SHADE /** * @brief - * Encapsulates a functor to hash a CollisionID + * Encapsulates a functor to hash a CollisionKey */ - struct SHCollisionIDHash + struct SHCollisionKeyHash { public: /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ - inline std::size_t operator()(const SHCollisionID& id) const - { - return std::hash{}(std::u32string_view(reinterpret_cast::const_pointer>(id.ids), 4)); - } + std::size_t operator()(const SHCollisionKey& id) const; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index befb16f6..a64c101c 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -13,7 +13,7 @@ // Project Headers #include "Physics/Collision/CollisionShapes/SHCollisionShape.h" #include "Physics/Collision/Contacts/SHManifold.h" -#include "Physics/Collision/Contacts/SHCollisionID.h" +#include "Physics/Collision/Contacts/SHCollisionKey.h" namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h index 4c132746..2dea7f1d 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h @@ -12,7 +12,7 @@ // Project Headers #include "Physics/Collision/Contacts/SHManifold.h" -#include "Physics/Collision/Contacts/SHCollisionID.h" +#include "Physics/Collision/Contacts/SHCollisionKey.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index ff362d69..8d0b69f8 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -326,7 +326,7 @@ namespace SHADE auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); // Build collision ID - SHCollisionID collisionKey; + SHCollisionKey collisionKey; collisionKey.SetEntityA(ID_A); collisionKey.SetEntityB(ID_B); collisionKey.SetCollisionShapeA(INDEX_A); @@ -361,7 +361,7 @@ namespace SHADE auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); // Build collision ID - SHCollisionID collisionKey; + SHCollisionKey collisionKey; collisionKey.SetEntityA(ID_A); collisionKey.SetEntityB(ID_B); collisionKey.SetCollisionShapeA(INDEX_A); @@ -396,7 +396,7 @@ namespace SHADE narrowphaseBatch.clear(); } - void SHPhysicsWorld::collideTriggers(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept + void SHPhysicsWorld::collideTriggers(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept { const auto* A = narrowphasePair.A; const auto* B = narrowphasePair.B; @@ -419,7 +419,7 @@ namespace SHADE trigger = triggers.erase(trigger); } - void SHPhysicsWorld::collideManifolds(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept + void SHPhysicsWorld::collideManifolds(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept { auto* A = narrowphasePair.A; auto* B = narrowphasePair.B; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index e0e4f796..a0743a30 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -113,9 +113,9 @@ namespace SHADE // Collisions - using NarrowphaseBatch = std::unordered_map; - using Manifolds = std::unordered_map; - using Triggers = std::unordered_map; + using NarrowphaseBatch = std::unordered_map; + using Manifolds = std::unordered_map; + using Triggers = std::unordered_map; @@ -155,8 +155,8 @@ namespace SHADE // Narrowphase helpers void runNarrowphase () noexcept; - void collideTriggers (const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept; - void collideManifolds (const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept; + void collideTriggers (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept; + void collideManifolds (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept; void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; void updateEvents () noexcept; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 975c561b..65bbc5d4 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -40,10 +40,6 @@ namespace SHADE eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT }; 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 } SHPhysicsSystem::~SHPhysicsSystem() noexcept @@ -178,6 +174,10 @@ namespace SHADE // Create the physics world physicsWorld = new SHPhysicsWorld; + // Immediately add all existing bodies and colliders to the world. + // Since we recreated the scene and the world, the initial data has been reset and determinism is guaranteed. + // Only if the current scene data changes, then so would the results of the simulation. + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) { if (PHYSICS_OBJECT.rigidBody) @@ -187,26 +187,6 @@ namespace SHADE physicsWorld->AddCollider(PHYSICS_OBJECT.collider); } - //#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(); - // 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; } @@ -262,7 +242,6 @@ namespace SHADE physicsWorld->AddRigidBody(rigidBody); } } - if (IS_COLLIDER) { @@ -323,24 +302,4 @@ namespace SHADE return onComponentRemovedEvent.get()->handle; } -#ifdef SHEDITOR - - SHEventHandle SHPhysicsSystem::onEditorPlay(SHEventPtr onEditorPlayEvent) - { - // Add all physics components to the physics world - for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) - { - // Add rigid body if it exists - if (PHYSICS_OBJECT.rigidBody) - physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); - - if (PHYSICS_OBJECT.collider) - physicsWorld->AddCollider(PHYSICS_OBJECT.collider); - } - - return onEditorPlayEvent.get()->handle; - } - -#endif - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index f9866ebe..fca12498 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -124,11 +124,7 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - //#ifdef SHEDITOR - // static constexpr int NUM_EVENT_FUNCTIONS = 5; - //#else static constexpr int NUM_EVENT_FUNCTIONS = 4; - //#endif // Event function container for cleanly registering to events EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS]; @@ -152,14 +148,5 @@ namespace SHADE SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent); SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent); - - - #ifdef SHEDITOR - - SHEventHandle onEditorPlay (SHEventPtr onEditorPlayEvent); - // We don't need an onEditorStop because on stop exits the scene, which is already handled above. - - #endif - }; } // namespace SHADE \ No newline at end of file -- 2.40.1 From b58b475c04cb0496515e576be9d7f1e057554eb8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 20 Dec 2022 23:10:23 +0800 Subject: [PATCH 24/84] Separated collision detection and added contact manager --- SHADE_Engine/src/Math/SHMathHelpers.h | 12 +- .../Collision/Broadphase/SHDynamicAABBTree.h | 2 +- .../CollisionShapes/SHCollisionShape.h | 2 +- .../src/Physics/Collision/SHCollider.cpp | 34 ++ .../src/Physics/Collision/SHCollider.h | 6 +- .../src/Physics/Collision/SHCollisionInfo.cpp | 100 ----- .../src/Physics/Collision/SHCollisionInfo.h | 102 ----- .../Physics/Collision/SHCollisionSpace.cpp | 223 +++++++++ .../src/Physics/Collision/SHCollisionSpace.h | 131 ++++++ .../src/Physics/Dynamics/SHContactManager.cpp | 173 +++++++ .../src/Physics/Dynamics/SHContactManager.h | 103 +++++ .../src/Physics/Dynamics/SHContactManager.hpp | 61 +++ .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 425 ++---------------- .../src/Physics/Dynamics/SHPhysicsWorld.h | 99 ++-- .../Routines/SHPhysicsDebugDrawRoutine.cpp | 5 +- .../Routines/SHPhysicsPostUpdateRoutine.cpp | 13 +- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 50 ++- .../src/Physics/System/SHPhysicsSystem.cpp | 99 +++- .../src/Physics/System/SHPhysicsSystem.h | 12 +- .../System/SHPhysicsSystemInterface.cpp | 56 +-- .../Physics/System/SHPhysicsSystemInterface.h | 12 +- SHADE_Managed/src/Scripts/ScriptStore.cxx | 25 +- 22 files changed, 1011 insertions(+), 734 deletions(-) delete mode 100644 SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp delete mode 100644 SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h create mode 100644 SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHContactManager.h create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp diff --git a/SHADE_Engine/src/Math/SHMathHelpers.h b/SHADE_Engine/src/Math/SHMathHelpers.h index 427011a6..b053beff 100644 --- a/SHADE_Engine/src/Math/SHMathHelpers.h +++ b/SHADE_Engine/src/Math/SHMathHelpers.h @@ -46,14 +46,16 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /** Standard Epsilon value for comparing Single-Precision Floating-Point values. */ - static constexpr float EPSILON = 0.001f; + static constexpr float EPSILON = 0.001f; /** Single-Precision Floating-Point value of infinity */ - static constexpr float INF = std::numeric_limits::infinity(); + static constexpr float INF = std::numeric_limits::infinity(); - static constexpr float PI = std::numbers::pi_v; - static constexpr float HALF_PI = PI * 0.5f; - static constexpr float TWO_PI = 2.0f * PI; + static constexpr float PI = std::numbers::pi_v; + static constexpr float HALF_PI = PI * 0.5f; + static constexpr float TWO_PI = 2.0f * PI; + + static constexpr float EULER_CONSTANT = std::numbers::egamma_v; /*---------------------------------------------------------------------------------*/ /* Static Function Members */ diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h index f23fd946..420f30e7 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h @@ -122,7 +122,7 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr float AABB_EXTENSION = 0.1f; + static constexpr float AABB_EXTENSION = 0.2f; // For quick access std::unordered_map nodeMap; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index dad59881..6e779eea 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -37,7 +37,7 @@ namespace SHADE friend class SHCollider; friend class SHColliderComponent; friend class SHCollisionShapeFactory; - friend class SHPhysicsWorld; + friend class SHCollisionSpace; public: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 24ba26b7..928945c9 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -29,6 +29,7 @@ namespace SHADE SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept : entityID { eid } + , active { true } , debugDraw { false } , hasMoved { true } , rigidBody { nullptr } @@ -39,6 +40,7 @@ namespace SHADE SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } + , active { rhs.active } , debugDraw { rhs.debugDraw } , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } @@ -57,6 +59,7 @@ namespace SHADE SHCollider::SHCollider(SHCollider&& rhs) noexcept : entityID { rhs.entityID } + , active { rhs.active } , debugDraw { rhs.debugDraw } , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } @@ -101,6 +104,7 @@ namespace SHADE } entityID = rhs.entityID; + active = rhs.active; debugDraw = rhs.debugDraw; hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; @@ -122,6 +126,7 @@ namespace SHADE } entityID = rhs.entityID; + active = rhs.active; debugDraw = rhs.debugDraw; hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; @@ -138,6 +143,16 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + EntityID SHCollider::GetEntityID() const noexcept + { + return entityID; + } + + bool SHCollider::IsActive() const noexcept + { + return active; + } + bool SHCollider::GetDebugDrawState() const noexcept { return debugDraw; @@ -182,6 +197,25 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHCollider::SetIsActive(bool state) noexcept + { + if (active == state) + return; + + active = state; + + if (!broadphase) + return; + + for (auto* shape : shapes) + { + if (active) // Previously inactive + broadphase->Insert(shape->id, shape->ComputeAABB()); + else // Previously active + broadphase->Remove(shape->id); + } + } + void SHCollider::SetDebugDrawState(bool state) noexcept { debugDraw = state; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 89ba5ff2..c31be5eb 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -40,7 +40,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHPhysicsWorld; + friend class SHCollisionSpace; public: /*---------------------------------------------------------------------------------*/ @@ -79,6 +79,8 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + [[nodiscard]] EntityID GetEntityID () const noexcept; + [[nodiscard]] bool IsActive () const noexcept; [[nodiscard]] bool GetDebugDrawState () const noexcept; [[nodiscard]] const SHTransform& GetTransform () const noexcept; @@ -93,6 +95,7 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ + void SetIsActive (bool state) noexcept; void SetDebugDrawState (bool state) noexcept; void SetRigidBody (SHRigidBody* rb) noexcept; @@ -157,6 +160,7 @@ namespace SHADE EntityID entityID; + bool active; bool debugDraw; bool hasMoved; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp deleted file mode 100644 index a28686e0..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionInfo.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for Collision Info. - * - * \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 - -// Primary Header -#include "SHCollisionInfo.h" - -// Project Headers -#include "Physics/Collision/SHCollider.h" -#include "Physics/Interface/SHColliderComponent.h" - - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionInfo::SHCollisionInfo() noexcept - : collisionState { State::INVALID } - { - ids[ENTITY_A] = MAX_EID; - ids[ENTITY_B] = MAX_EID; - ids[COLLIDER_A] = std::numeric_limits::max(); - ids[COLLIDER_B] = std::numeric_limits::max(); - } - - SHCollisionInfo::SHCollisionInfo(EntityID entityA, EntityID entityB) noexcept - : collisionState { State::INVALID } - { - ids[ENTITY_A] = entityA; - ids[ENTITY_B] = entityB; - ids[COLLIDER_A] = std::numeric_limits::max(); - ids[COLLIDER_B] = std::numeric_limits::max(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHCollisionInfo::operator==(const SHCollisionInfo& rhs) const noexcept - { - return value[0] == rhs.value[0] && value[1] == rhs.value[1]; - } - - bool SHCollisionInfo::operator!=(const SHCollisionInfo& rhs) const noexcept - { - return value[0] != rhs.value[0] || value[1] != rhs.value[1]; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - EntityID SHCollisionInfo::GetEntityA() const noexcept - { - return ids[ENTITY_A]; - } - - EntityID SHCollisionInfo::GetEntityB() const noexcept - { - return ids[ENTITY_B]; - } - - const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyA() const noexcept - { - return SHComponentManager::GetComponent_s(ids[ENTITY_A]); - } - - const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyB() const noexcept - { - return SHComponentManager::GetComponent_s(ids[ENTITY_B]); - } - - const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept - { - const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_A]); - return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_A]); - } - - const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept - { - const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_B]); - return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_B]); - } - - SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept - { - return collisionState; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h deleted file mode 100644 index d2dad647..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionInfo.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for Collision Information for Collision & Triggers. - * - * \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 "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" - - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHCollisionInfo - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHCollisionListener; - - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class State - { - ENTER - , STAY - , EXIT - - , TOTAL - , INVALID = -1 - }; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionInfo () noexcept; - SHCollisionInfo (EntityID entityA, EntityID entityB) noexcept; - - - SHCollisionInfo (const SHCollisionInfo& rhs) = default; - SHCollisionInfo (SHCollisionInfo&& rhs) = default; - ~SHCollisionInfo () = default; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - bool operator== (const SHCollisionInfo& rhs) const noexcept; - bool operator!= (const SHCollisionInfo& rhs) const noexcept; - - SHCollisionInfo& operator= (const SHCollisionInfo& rhs) = default; - SHCollisionInfo& operator= (SHCollisionInfo&& rhs) = default; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] EntityID GetEntityA () const noexcept; - [[nodiscard]] EntityID GetEntityB () const noexcept; - [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept; - [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept; - [[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept; - [[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept; - [[nodiscard]] State GetCollisionState () const noexcept; - - private: - - static constexpr uint32_t ENTITY_A = 0; - static constexpr uint32_t ENTITY_B = 1; - static constexpr uint32_t COLLIDER_A = 2; - static constexpr uint32_t COLLIDER_B = 3; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - union - { - uint64_t value[2]; // EntityValue, ColliderIndexValue - uint32_t ids [4]; // EntityA, EntityB, ColliderIndexA, ColliderIndexB - }; - - State collisionState; - }; - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp new file mode 100644 index 00000000..bc76d14a --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -0,0 +1,223 @@ +/**************************************************************************************** + * \file SHCollisionSpace.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Collision Space that handles collision detetction. + * + * \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 + +// Primary Header +#include "SHCollisionSpace.h" + +#include "Narrowphase/SHCollisionDispatch.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHAABBTree::AABBs& SHCollisionSpace::GetBroadphaseAABBs() const noexcept + { + return broadphase.GetAABBs(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionSpace::SetContactManager(SHContactManager* _contactManager) noexcept + { + contactManager = _contactManager; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionSpace::AddCollider(SHCollider* collider) noexcept + { + const bool INSERTED = colliders.emplace(collider->entityID, collider).second; + if (!INSERTED) + { + SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID) + return; + } + + collider->broadphase = &broadphase; + + // Add all existing shapes to the broadphase + for (const auto* shape : collider->shapes) + broadphase.Insert(shape->id, shape->ComputeAABB()); + } + + void SHCollisionSpace::RemoveCollider(SHCollider* collider) noexcept + { + colliders.erase(collider->entityID); + + const uint32_t NUM_SHAPES = static_cast(collider->shapes.size()); + if (NUM_SHAPES == 0) + return; + + for (uint32_t i = 0; i < NUM_SHAPES; ++i) + broadphase.Remove(collider->shapes[i]->id); + + if (contactManager) + { + contactManager->RemoveInvalidatedTrigger(collider->entityID); + contactManager->RemoveInvalidatedManifold(collider->entityID); + } + + /* + * TODO: + * 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 SHCollisionSpace::UpdateBroadphase() noexcept + { + // Update any colliders that have moved + for (auto& collider : colliders | std::views::values) + { + const bool IS_ACTIVE = collider->active; + const bool HAS_MOVED = collider->hasMoved; + + if (!IS_ACTIVE || !HAS_MOVED) + continue; + + // Clear hasMoved flag here + collider->hasMoved = false; + + // Update moved shapes in broadphase + for (auto* shape : collider->shapes) + broadphase.Update(shape->id, shape->ComputeAABB()); + } + } + + void SHCollisionSpace::DetectCollisions() noexcept + { + /* + * Broad-phase + */ + + // Broadphase Queries: Kinematic Triggers, Awake Dynamic Bodies & Dynamic Triggers + for (auto& collider : colliders | std::views::values) + { + // Colliders without bodies are considered to be static bodies + // This is specific to this engine because of Unity's stupid convention. + const bool IS_IMPLICIT_STATIC = !collider->rigidBody; + const bool IS_EXPLICIT_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC; + const bool IS_ACTIVE = collider->active; + + // Skip inactive colliders + if (!IS_ACTIVE || IS_IMPLICIT_STATIC || IS_EXPLICIT_STATIC) + continue; + + // All remaining are kinematic or dynamic + // Iterate through shapes: if kinematic / dynamic trigger, else if dynamic & awake + // Results are loaded into the narrowphase batch + broadphaseQuery(collider->rigidBody->GetType(), collider); + } + + /* + * Narrow-phase + */ + + // If no potential collisions, we can skip the entire narrow phase. No further updates necessary. + // All contact / trigger states persist in this step. + if (narrowphaseBatch.empty()) + return; + + // All narrowphase IDs are unique, there should be no duplicate collision checks. + // This applies both ways: A -> B and B -> A. + for (auto& [key, narrowphasePair] : narrowphaseBatch) + { + const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger(); + const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger(); + + if (IS_A_TRIGGER || IS_B_TRIGGER) + collideTriggers(key, narrowphasePair); + else + collideManifolds(key, narrowphasePair); + } + + // Clear every frame + narrowphaseBatch.clear(); + } + + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionSpace::broadphaseQuery(SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept + { + for (auto* shape : collider->shapes) + { + // For kinematic shapes, we only query triggers against everything else + if (rigidBodyType == SHRigidBody::Type::KINEMATIC && !shape->IsTrigger()) + continue; + + auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); + + // Build narrow-phase pairs + auto* shapeA = shape; + + const EntityID ID_A = shape->id.GetEntityID(); + const uint32_t INDEX_A = shape->id.GetShapeIndex(); + + for (auto& id : potentialCollisions) + { + // Get corresponding shape + const EntityID ID_B = id.GetEntityID(); + const uint32_t INDEX_B = id.GetShapeIndex(); + + auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); + + // Build collision ID + SHCollisionKey collisionKey; + collisionKey.SetEntityA(ID_A); + collisionKey.SetEntityB(ID_B); + collisionKey.SetCollisionShapeA(INDEX_A); + collisionKey.SetCollisionShapeB(INDEX_B); + + // Check if it already exists. If it doesn't, put into batch. + // The overloaded equality operator ensures no duplicate collision tests are performed. + auto narrowphasePair = narrowphaseBatch.find(collisionKey); + if (narrowphasePair == narrowphaseBatch.end()) + narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); + } + } + } + + void SHCollisionSpace::collideTriggers(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept + { + const auto* A = narrowphasePair.A; + const auto* B = narrowphasePair.B; + + const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B); + + // Send results to contact manager + if (contactManager) + contactManager->AddTrigger(COLLIDING, key); + } + + void SHCollisionSpace::collideManifolds(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept + { + auto* A = narrowphasePair.A; + auto* B = narrowphasePair.B; + + SHManifold newManifold { .A = A, .B = B }; + const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B); + + // Send results to contact manager + if (contactManager) + contactManager->AddManifold(COLLIDING, key, newManifold); + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h new file mode 100644 index 00000000..d89404dd --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h @@ -0,0 +1,131 @@ +/**************************************************************************************** + * \file SHCollisionSpace.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collision Space that handles collision detetction. + * This is to separate the logic between dynamics and collision detection, + * but the collision space does send information to the contact manager + * for dynamic resolution and collision state reporting. + * + * \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 "Broadphase/SHDynamicAABBTree.h" +#include "Contacts/SHCollisionEvents.h" +#include "Physics/Dynamics/SHContactManager.h" +#include "SHCollider.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Allows collision detection to be performed with the use of colliders & collision shapes. + * The space will generate manifold data for resolution when needed. + */ + class SH_API SHCollisionSpace + { + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionSpace () noexcept = default; + ~SHCollisionSpace () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetContactManager(SHContactManager* contactManager) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Adds a collider to the collision space for it to be tested for collision with + * other colliders. + * @param collider + * A collider to add. Duplicates will be ignored. + */ + void AddCollider (SHCollider* collider) noexcept; + + /** + * @brief + * Removes a collider from the collision space. This will prevent any collisions + * being detected between it and other colliders unless manually tested. + * @param collider + * A collider to remove. If a reference to it doesn't exist, it will be ignored. + */ + void RemoveCollider (SHCollider* collider) noexcept; + + /** + * @brief + * Invoke this method to update the broadphase of colliders that have been moved since + * the last frame. + */ + void UpdateBroadphase () noexcept; + + /** + * @brief + * Detects collisions between all colliders. Results are sent to the attached contact + * manager for resolution. + */ + void DetectCollisions () noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct NarrowphasePair + { + SHCollisionShape* A = nullptr; + SHCollisionShape* B = nullptr; + }; + + using Colliders = std::unordered_map; + using NarrowphaseBatch = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHContactManager* contactManager = nullptr; + + Colliders colliders; + NarrowphaseBatch narrowphaseBatch; + + SHAABBTree broadphase; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + // Broadphase helpers + + void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; + + // Narrowphase helpers + + void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; + void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; + + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp new file mode 100644 index 00000000..be65128d --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -0,0 +1,173 @@ +/**************************************************************************************** + * \file SHContactManager.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Contact Manager that stores collision information and + * resolves contact constraints. + * + * \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 + +// Primary Header +#include "SHContactManager.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHContactManager::TriggerEvents& SHContactManager::GetTriggerEvents() const noexcept + { + static TriggerEvents triggerEvents; + + triggerEvents.clear(); + + for (auto& [id, state] : triggers) + triggerEvents.emplace_back(SHTriggerEvent{ id, state }); + + return triggerEvents; + } + + const SHContactManager::CollisionEvents& SHContactManager::GetCollisionEvents() const noexcept + { + static CollisionEvents collisionEvents; + + collisionEvents.clear(); + + for (auto& [id, manifold] : manifolds) + { + SHCollisionEvent collisionEvent + { + .info = id + , .state = manifold.state + , .normal = manifold.normal + }; + + for (uint32_t i = 0; i < manifold.numContacts; ++i) + collisionEvent.contactPoints[i] = manifold.contacts[i].position; + + collisionEvents.emplace_back(collisionEvent); + } + + return collisionEvents; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHContactManager::Update() noexcept + { + // Clear expired or invalid collisions + for (auto manifold = manifolds.begin(); manifold != manifolds.end();) + { + const auto COLLISION_STATE = manifold->second.state; + + const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; + const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; + + if (IS_EXIT || IS_INVALID) + manifold = manifolds.erase(manifold); + else + ++manifold; + } + + // Clear expired or invalid triggers + for (auto trigger = triggers.begin(); trigger != triggers.end();) + { + const auto COLLISION_STATE = trigger->second; + + const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; + const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; + + if (IS_EXIT || IS_INVALID) + trigger = triggers.erase(trigger); + else + ++trigger; + } + } + + void SHContactManager::AddTrigger(bool isColliding, const SHCollisionKey& key) noexcept + { + auto trigger = triggers.find(key); + + // If id not found, emplace new object. + // New object is in the invalid state + if (trigger == triggers.end()) + trigger = triggers.emplace(key, SHCollisionState::INVALID).first; + + SHCollisionState& state = trigger->second; + updateCollisionState(isColliding, state); + + // If it was a false positive, remove the manifold immediately. + // Remove using iterator as it is on average faster. + if (state == SHCollisionState::INVALID) + trigger = triggers.erase(trigger); + } + + void SHContactManager::AddManifold(bool isColliding, const SHCollisionKey& key, const SHManifold& newManifold) noexcept + { + auto manifold = manifolds.find(key); + + // If id not found, emplace new manifold + if (manifold == manifolds.end()) + manifold = manifolds.emplace(key, newManifold).first; + else + { + // TODO: Update existing manifolds with new data + } + + SHCollisionState& state = manifold->second.state; + updateCollisionState(isColliding, state); + + // If it was a false positive, remove the manifold immediately. + // Remove using iterator as it is on average faster. + if (state == SHCollisionState::INVALID) + manifold = manifolds.erase(manifold); + } + + void SHContactManager::RemoveInvalidatedTrigger(EntityID eid) noexcept + { + remove(triggers, eid); + } + + void SHContactManager::RemoveInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) noexcept + { + remove(triggers, eid, shapeIndex); + } + + void SHContactManager::RemoveInvalidatedManifold(EntityID eid) noexcept + { + remove(manifolds, eid); + } + + void SHContactManager::RemoveInvalidatedManifold(EntityID eid, uint32_t shapeIndex) noexcept + { + remove(manifolds, eid, shapeIndex); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHContactManager::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 + { + // New states start at invalid. In false positive, remain unchanged. + // If previously colliding, move to exit. + state = state == SHCollisionState::INVALID ? SHCollisionState::INVALID : SHCollisionState::EXIT; + } + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h new file mode 100644 index 00000000..06a03a6a --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -0,0 +1,103 @@ +/**************************************************************************************** + * \file SHContactManager.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Contact Manager that stores collision information and + * resolves contact constraints. + * + * \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 + +// Project Headers +#include "Physics/Collision/Contacts/SHCollisionEvents.h" +#include "Physics/Collision/Contacts/SHCollisionKey.h" +#include "Physics/Collision/Contacts/SHManifold.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHContactManager + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using TriggerEvents = std::vector; + using CollisionEvents = std::vector; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHContactManager () noexcept = default; + ~SHContactManager () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + const TriggerEvents& GetTriggerEvents () const noexcept; + const CollisionEvents& GetCollisionEvents () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Removes any invalidated contacts and triggers. + * @return + */ + void Update () noexcept; + + void AddTrigger (bool isColliding, const SHCollisionKey& key) noexcept; + void AddManifold (bool isColliding, const SHCollisionKey& key, const SHManifold& newManifold) noexcept; + + void RemoveInvalidatedTrigger (EntityID eid) noexcept; + void RemoveInvalidatedTrigger (EntityID eid, uint32_t shapeIndex) noexcept; + void RemoveInvalidatedManifold (EntityID eid) noexcept; + void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using Manifolds = std::unordered_map; + using Triggers = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Manifolds manifolds; + Triggers triggers; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; + + // Removal Helpers + + template + void remove (std::unordered_map& container, EntityID eid); + template + void remove (std::unordered_map& container, EntityID eid, uint32_t shapeIndex); + + }; + + +} // namespace SHADE + +#include "SHContactManager.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp new file mode 100644 index 00000000..1403cd79 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp @@ -0,0 +1,61 @@ +/**************************************************************************************** + * \file SHContactManager.hpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for templated methods of the Contact Manager. + * + * \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 "SHContactManager.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + template + void SHContactManager::remove(std::unordered_map& container, EntityID eid) + { + if (container.empty()) + return; + + for (auto invalidated = container.begin(); invalidated != container.end();) + { + const auto& ID = invalidated->first; + + const bool MATCHES_A = ID.GetEntityA() == eid; + const bool MATCHES_B = ID.GetEntityB() == eid; + + if (MATCHES_A || MATCHES_B) + invalidated = container.erase(invalidated); + else + ++invalidated; + } + } + + template + void SHContactManager::remove(std::unordered_map& container, EntityID eid, uint32_t shapeIndex) + { + if (container.empty()) + return; + + for (auto invalidated = container.begin(); invalidated != container.end();) + { + const auto& ID = invalidated->first; + + const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; + const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; + + if (MATCHES_A || MATCHES_B) + invalidated = container.erase(invalidated); + else + ++invalidated; + } + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 8d0b69f8..b5dba378 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -13,11 +13,6 @@ // Primary Header #include "SHPhysicsWorld.h" -// Project Headers -#include "Physics/Collision/Narrowphase/SHCollision.h" -#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h" - - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -25,59 +20,39 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept - : settings { worldSettings } + : settings { worldSettings } + , collisionSpace { nullptr } { SHLOG_INFO_D("Creating Physics World") } SHPhysicsWorld::~SHPhysicsWorld() noexcept { - + collisionSpace = nullptr; } /*-----------------------------------------------------------------------------------*/ /* Getter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHAABBTree::AABBs& SHPhysicsWorld::GetBroadphaseAABBs() const noexcept + const SHContactManager::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept { - return broadphase.GetAABBs(); + return contactManager.GetTriggerEvents(); } - const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept + const SHContactManager::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept { - static TriggerEvents triggerEvents; - - triggerEvents.clear(); - - for (auto& [id, state] : triggers) - triggerEvents.emplace_back(SHTriggerEvent{ id, state }); - - return triggerEvents; + return contactManager.GetCollisionEvents(); } - const SHPhysicsWorld::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept + /*-----------------------------------------------------------------------------------*/ + /* Setter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsWorld::SetCollisionSpace(SHCollisionSpace* _collisionSpace) noexcept { - static CollisionEvents collisionEvents; - - collisionEvents.clear(); - - for (auto& [id, manifold] : manifolds) - { - SHCollisionEvent collisionEvent - { - .info = id - , .state = manifold.state - , .normal = manifold.normal - }; - - for (uint32_t i = 0; i < manifold.numContacts; ++i) - collisionEvent.contactPoints[i] = manifold.contacts[i].position; - - collisionEvents.emplace_back(collisionEvent); - } - - return collisionEvents; + collisionSpace = _collisionSpace; + _collisionSpace->SetContactManager(&contactManager); } /*-----------------------------------------------------------------------------------*/ @@ -97,93 +72,54 @@ namespace SHADE { rigidBodies.erase(rigidBody->entityID); - // Attempt to remove any invalidated manifolds - if (manifolds.empty()) - return; - - for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) - { - const auto& ID = manifoldPair->first; - - const bool MATCHES_A = ID.GetEntityA() == rigidBody->entityID; - const bool MATCHES_B = ID.GetEntityB() == rigidBody->entityID; - - if (MATCHES_A || MATCHES_B) - manifoldPair = manifolds.erase(manifoldPair); - else - ++manifoldPair; - } + // Contact manager to remove invalidated contacts + contactManager.RemoveInvalidatedManifold(rigidBody->entityID); // TODO: Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep } - void SHPhysicsWorld::AddCollider(SHCollider* collider) noexcept - { - const bool INSERTED = colliders.emplace(collider->entityID, collider).second; - if (!INSERTED) - { - SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID) - return; - } - - collider->broadphase = &broadphase; - - // Add all existing shapes to the broadphase - for (const auto* shape : collider->shapes) - broadphase.Insert(shape->id, shape->ComputeAABB()); - } - - void SHPhysicsWorld::RemoveCollider(SHCollider* collider) noexcept - { - colliders.erase(collider->entityID); - - const uint32_t NUM_SHAPES = static_cast(collider->shapes.size()); - if (NUM_SHAPES == 0) - return; - - for (uint32_t i = 0; i < NUM_SHAPES; ++i) - { - const SHCollisionShape* SHAPE = collider->shapes[i]; - - broadphase.Remove(SHAPE->id); - - if (SHAPE->IsTrigger()) - removeInvalidatedTrigger(collider->entityID, i); - else - removeInvalidatedManifold(collider->entityID, i); - } - - /* - * TODO: - * 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) { - // Clear containers of exit state collisions - updateEvents(); + // Contact manager to clear expired contacts + contactManager.Update(); - // TODO: Profile each of these - runBroadphase (); - runNarrowphase(); + /* + * Detect Collisions + */ + + if (collisionSpace) + collisionSpace->DetectCollisions(); + + /* + * Integrate Forces + */ for (auto* rigidBody : rigidBodies | std::views::values) { + if (!rigidBody->IsActive()) + continue; + rigidBody->ComputeWorldData(); integrateForces(*rigidBody, dt); } + + /* + * TODO: Resolve Contacts + */ + + /* + * Integrate Velocities + */ + for (auto* rigidBody : rigidBodies | std::views::values) + { + if (!rigidBody->IsActive()) + continue; + integrateVelocities(*rigidBody, dt); + } } /*-----------------------------------------------------------------------------------*/ @@ -262,275 +198,4 @@ namespace SHADE rigidBody.ClearForces(); } - void SHPhysicsWorld::runBroadphase() noexcept - { - // Update any colliders that have moved - for (auto& collider : colliders | std::views::values) - { - if (!collider->hasMoved) - continue; - - // Clear hasMoved flag here - collider->hasMoved = false; - - // Update moved shapes in broadphase - for (auto* shape : collider->shapes) - broadphase.Update(shape->id, shape->ComputeAABB()); - } - - // Query: Kinematic Triggers, Awake Dynamic Bodies & Dynamic Triggers - for (auto& collider : colliders | std::views::values) - { - // Default static bodies - if (!collider->rigidBody) - continue; - - // Explicit static bodies - const bool IS_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC; - if (IS_STATIC) - continue; - - // All remaining are kinematic or dynamic - // Iterate through shapes: if kinematic / dynamic trigger, else if dynamic & awake - if (collider->rigidBody->GetType() == SHRigidBody::Type::KINEMATIC) - queryKinematic(collider); - - if (collider->rigidBody->GetType() == SHRigidBody::Type::DYNAMIC) - queryDynamic(collider); - } - - } - - void SHPhysicsWorld::queryKinematic(SHCollider* collider) noexcept - { - for (auto* shape : collider->shapes) - { - // For kinematic shapes, we only query triggers against everything else - if (!shape->IsTrigger()) - continue; - - auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); - - // Build narrow-phase pairs - auto* shapeA = shape; - - const EntityID ID_A = shape->id.GetEntityID(); - const uint32_t INDEX_A = shape->id.GetShapeIndex(); - - for (auto& id : potentialCollisions) - { - // Get corresponding shape - const EntityID ID_B = id.GetEntityID(); - const uint32_t INDEX_B = id.GetShapeIndex(); - - auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); - - // Build collision ID - SHCollisionKey collisionKey; - collisionKey.SetEntityA(ID_A); - collisionKey.SetEntityB(ID_B); - collisionKey.SetCollisionShapeA(INDEX_A); - collisionKey.SetCollisionShapeB(INDEX_B); - - // Check if it already exists. If it doesn't, put into batch. - auto narrowphasePair = narrowphaseBatch.find(collisionKey); - if (narrowphasePair == narrowphaseBatch.end()) - narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); - } - } - } - - void SHPhysicsWorld::queryDynamic(SHCollider* collider) noexcept - { - for (auto* shape : collider->shapes) - { - auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); - - // Build narrow-phase pairs - auto* shapeA = shape; - - const EntityID ID_A = shape->id.GetEntityID(); - const uint32_t INDEX_A = shape->id.GetShapeIndex(); - - for (auto& id : potentialCollisions) - { - // Get corresponding shape - const EntityID ID_B = id.GetEntityID(); - const uint32_t INDEX_B = id.GetShapeIndex(); - - auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); - - // Build collision ID - SHCollisionKey collisionKey; - collisionKey.SetEntityA(ID_A); - collisionKey.SetEntityB(ID_B); - collisionKey.SetCollisionShapeA(INDEX_A); - collisionKey.SetCollisionShapeB(INDEX_B); - - // Check if it already exists. If it doesn't, put into batch. - auto narrowphasePair = narrowphaseBatch.find(collisionKey); - if (narrowphasePair == narrowphaseBatch.end()) - narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); - } - } - } - - void SHPhysicsWorld::runNarrowphase() noexcept - { - if (narrowphaseBatch.empty()) - return; - - for (auto& [id, narrowphasePair] : narrowphaseBatch) - { - const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger(); - const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger(); - - // Check if ID exists in trigger - if (IS_A_TRIGGER || IS_B_TRIGGER) - collideTriggers(id, narrowphasePair); - else - collideManifolds(id, narrowphasePair); - } - - // Clear every frame - narrowphaseBatch.clear(); - } - - void SHPhysicsWorld::collideTriggers(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept - { - const auto* A = narrowphasePair.A; - const auto* B = narrowphasePair.B; - - const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B); - - auto trigger = triggers.find(id); - - // If id not found, emplace new object. - // New object is in the invalid state - if (trigger == triggers.end()) - trigger = triggers.emplace(id, SHCollisionState::INVALID).first; - - SHCollisionState& state = trigger->second; - updateCollisionState(COLLIDING, state); - - // If it was a false positive, remove the manifold immediately. - // Remove using iterator as it is on average faster. - if (state == SHCollisionState::INVALID) - trigger = triggers.erase(trigger); - } - - void SHPhysicsWorld::collideManifolds(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept - { - auto* A = narrowphasePair.A; - auto* B = narrowphasePair.B; - - SHManifold newManifold { .A = A, .B = B }; - const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B); - - auto manifold = manifolds.find(id); - - // If id not found, emplace new manifold - if (manifold == manifolds.end()) - manifold = manifolds.emplace(id, newManifold).first; - else - { - // TODO: Update existing manifolds with new data - } - - SHCollisionState& state = manifold->second.state; - updateCollisionState(COLLIDING, state); - - // If it was a false positive, remove the manifold immediately. - // Remove using iterator as it is on average faster. - if (state == SHCollisionState::INVALID) - manifold = manifolds.erase(manifold); - } - - 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 - { - // 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 - { - // Clear expired or invalid collisions - for (auto manifold = manifolds.begin(); manifold != manifolds.end();) - { - const auto COLLISION_STATE = manifold->second.state; - - const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; - const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; - - if (IS_EXIT || IS_INVALID) - manifold = manifolds.erase(manifold); - else - ++manifold; - } - - // Clear expired or invalid triggers - for (auto trigger = triggers.begin(); trigger != triggers.end();) - { - const auto COLLISION_STATE = trigger->second; - - const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; - const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; - - if (IS_EXIT || IS_INVALID) - trigger = triggers.erase(trigger); - else - ++trigger; - } - } - - void SHPhysicsWorld::removeInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) - { - if (triggers.empty()) - return; - - for (auto invalidatedTrigger = triggers.begin(); invalidatedTrigger != triggers.end();) - { - const auto& ID = invalidatedTrigger->first; - - const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; - const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; - - if (MATCHES_A || MATCHES_B) - invalidatedTrigger = triggers.erase(invalidatedTrigger); - else - ++invalidatedTrigger; - } - } - - void SHPhysicsWorld::removeInvalidatedManifold(EntityID eid, uint32_t shapeIndex) - { - if (manifolds.empty()) - return; - - for (auto invalidatedManifold = manifolds.begin(); invalidatedManifold != manifolds.end();) - { - const auto& ID = invalidatedManifold->first; - - const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; - const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; - - if (MATCHES_A || MATCHES_B) - invalidatedManifold = manifolds.erase(invalidatedManifold); - else - ++invalidatedManifold; - } - } - - - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index a0743a30..8248299a 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -13,10 +13,8 @@ #include // Project Headers -#include "Physics/Collision/Broadphase/SHDynamicAABBTree.h" -#include "Physics/Collision/Contacts/SHCollisionEvents.h" -#include "Physics/Collision/Contacts/SHManifold.h" -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCollisionSpace.h" +#include "SHContactManager.h" #include "SHRigidBody.h" @@ -26,10 +24,15 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates the overall simulation of physics. The bulk of dynamics are handled here, + * with the collision detection handled by an attached collision space.
+ * A collision space must be created separately and attached with the world. + */ class SH_API SHPhysicsWorld { public: - /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ @@ -47,9 +50,6 @@ namespace SHADE bool sleepingEnabled = true; }; - using TriggerEvents = std::vector; - using CollisionEvents = std::vector; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ @@ -71,29 +71,44 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept; + const SHContactManager::TriggerEvents& GetTriggerEvents () const noexcept; + const SHContactManager::CollisionEvents& GetCollisionEvents () const noexcept; - const TriggerEvents& GetTriggerEvents () const noexcept; - const CollisionEvents& GetCollisionEvents () const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetCollisionSpace(SHCollisionSpace* collisionSpace) noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Adds a rigid body to the world for it to be simulated using motion dynamics. + * @param rigidBody + * A rigid body to add. Duplicates will be ignored. + */ void AddRigidBody (SHRigidBody* rigidBody) noexcept; - void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; - - 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. + * Removes a rigid body from the world. It's motion will not be affected unless + * explicitly modified. + * @param rigidBody + * A rigid body to add. Duplicates will be ignored. + */ + void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; + + /** + * @brief + * Performs a single simulation step.
+ * Detect Collisions -> Integrate Forces -> Resolve Contacts -> Integrate Velocities + * @param dt + * A discrete time step for the simulation. This should be consistent for deteministic + * behaviour. */ - void UpdateBroadphase (SHCollider* collider) noexcept; void Step (float dt); private: @@ -101,42 +116,18 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - struct NarrowphasePair - { - SHCollisionShape* A = nullptr; - SHCollisionShape* B = nullptr; - }; - // EntityIDs are used to map resolved contraints back to bodies using RigidBodies = std::unordered_map; - using Colliders = std::unordered_map; - - // Collisions - - using NarrowphaseBatch = std::unordered_map; - using Manifolds = std::unordered_map; - using Triggers = std::unordered_map; - - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ WorldSettings settings; - - // Containers + SHCollisionSpace* collisionSpace; RigidBodies rigidBodies; - Colliders colliders; - - NarrowphaseBatch narrowphaseBatch; - Manifolds manifolds; - Triggers triggers; - - // World components - - SHAABBTree broadphase; + SHContactManager contactManager; /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -146,22 +137,8 @@ namespace SHADE void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept; void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept; - // Broadphase helpers - - void runBroadphase () noexcept; - void queryKinematic (SHCollider* collider) noexcept; - void queryDynamic (SHCollider* collider) noexcept; - - // Narrowphase helpers - - void runNarrowphase () noexcept; - void collideTriggers (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept; - void collideManifolds (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept; - void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; - void updateEvents () noexcept; - void removeInvalidatedTrigger (EntityID eid, uint32_t shapeIndex); - void removeInvalidatedManifold (EntityID eid, uint32_t shapeIndex); + }; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index b43b5b77..9bf43115 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -87,9 +87,8 @@ namespace SHADE { const SHColour& AABB_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::BROADPHASE)]; - auto& broadphaseAABBs = physicsSystem->GetWorld()->GetBroadphaseAABBs(); - - for (auto& aabb : broadphaseAABBs) + const auto& BROADPHASE_AABBS = physicsSystem->collisionSpace->GetBroadphaseAABBs(); + for (auto& aabb : BROADPHASE_AABBS) { // Compute AABB Transform const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f); diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 200642e1..5b0e5563 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -16,6 +16,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" @@ -50,15 +51,25 @@ namespace SHADE const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); for (auto& rigidBodyComponent : RIGIDBODY_DENSE) { - auto* transformComponent = SHComponentManager::GetComponent_s(rigidBodyComponent.GetEID()); + const EntityID EID = rigidBodyComponent.GetEID(); + + // Skip missing transforms + auto* transformComponent = SHComponentManager::GetComponent_s(EID); if (!transformComponent) continue; + // Skip invalid bodies (Should not occur) if (!rigidBodyComponent.rigidBody) continue; + // Skip inactive bodies + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); + if (!IS_ACTIVE) + continue; + const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); + // Skip objects that have not moved if (!MOTION_STATE) continue; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 178a6120..17f3f83d 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -16,6 +16,7 @@ // Project Headers #include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneManager.h" namespace SHADE { @@ -40,35 +41,54 @@ namespace SHADE for (auto& [entityID, physicsObject] : physicsObjects) { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); - - if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) - continue; - - const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); - const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); - const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale(); + // Assume transform is always active + const bool UPDATE_TRANSFORM = TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged(); // We assume that all engine components and physics object components have been successfully linked if (physicsObject.rigidBody) { - SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + const bool RIGIDBODY_ACTIVE = physicsObject.rigidBody->IsActive(); - motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); - motionState.ForceOrientation(TRANSFORM_COMPONENT->GetWorldOrientation()); + if (IS_ACTIVE != RIGIDBODY_ACTIVE) + physicsObject.rigidBody->SetIsActive(IS_ACTIVE); + + if (UPDATE_TRANSFORM) + { + const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); + + SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); + motionState.ForcePosition(WORLD_POS); + motionState.ForceOrientation(WORLD_ROT); + } } if (physicsObject.collider) { - physicsObject.collider->SetPosition(WORLD_POS); - physicsObject.collider->SetOrientation(WORLD_ROT); - physicsObject.collider->SetScale(WORLD_SCL); + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + const bool COLLIDER_ACTIVE = physicsObject.collider->IsActive(); - physicsObject.collider->RecomputeShapes(); + if (IS_ACTIVE != COLLIDER_ACTIVE) + physicsObject.collider->SetIsActive(IS_ACTIVE); - physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider); + if (UPDATE_TRANSFORM) + { + const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); + const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale(); + + physicsObject.collider->SetPosition(WORLD_POS); + physicsObject.collider->SetOrientation(WORLD_ROT); + physicsObject.collider->SetScale(WORLD_SCL); + + physicsObject.collider->RecomputeShapes(); + } } } + + physicsSystem->collisionSpace->UpdateBroadphase(); } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 65bbc5d4..508c19ad 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -21,6 +21,7 @@ #include "Editor/SHEditor.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Physics/Interface/SHColliderComponent.h" +#include "Scripting/SHScriptEngine.h" namespace SHADE { @@ -33,6 +34,7 @@ namespace SHADE , interpolationFactor { 0.0 } , fixedDT { DEFAULT_FIXED_STEP } , physicsWorld { nullptr } + , collisionSpace { nullptr } { // Add more events here to register them @@ -44,6 +46,7 @@ namespace SHADE SHPhysicsSystem::~SHPhysicsSystem() noexcept { + delete collisionSpace; delete physicsWorld; } @@ -51,11 +54,6 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHPhysicsWorld* SHPhysicsSystem::GetWorld() const noexcept - { - return physicsWorld; - } - double SHPhysicsSystem::GetFixedUpdateRate() const noexcept { return 1.0 / fixedDT; @@ -66,6 +64,16 @@ namespace SHADE return fixedDT; } + const std::vector& SHPhysicsSystem::GetTriggerInfo() const noexcept + { + return physicsWorld->GetTriggerEvents(); + } + + const std::vector& SHPhysicsSystem::GetCollisionInfo() const noexcept + { + return physicsWorld->GetCollisionEvents(); + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -137,7 +145,48 @@ namespace SHADE void SHPhysicsSystem::ForceUpdate() { + if (!physicsWorld) + return; + auto* scriptingSystem = SHSystemManager::GetSystem(); + + if (scriptingSystem == nullptr) + { + SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); + } + + scriptingSystem->ExecuteFixedUpdates(); + physicsWorld->Step(static_cast(fixedDT)); + + const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); + for (auto& rigidBodyComponent : RIGIDBODY_DENSE) + { + const EntityID EID = rigidBodyComponent.GetEID(); + + // Skip missing transforms + auto* transformComponent = SHComponentManager::GetComponent_s(EID); + if (!transformComponent) + continue; + + // Skip invalid bodies (Should not occur) + if (!rigidBodyComponent.rigidBody) + continue; + + // Skip inactive bodies + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); + if (!IS_ACTIVE) + continue; + + const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); + + // Skip objects that have not moved + if (!MOTION_STATE) + continue; + + // We ignore interpolations here because we are only stepping once + transformComponent->SetWorldPosition(MOTION_STATE.position); + transformComponent->SetWorldOrientation(MOTION_STATE.orientation); + } } /*-----------------------------------------------------------------------------------*/ @@ -162,17 +211,29 @@ namespace SHADE { if (PHYSICS_OBJECT.rigidBody) physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); - - if (PHYSICS_OBJECT.collider) - physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); } delete physicsWorld; physicsWorld = nullptr; } - // Create the physics world - physicsWorld = new SHPhysicsWorld; + if (collisionSpace) + { + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + { + if (PHYSICS_OBJECT.collider) + collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider); + } + + delete collisionSpace; + collisionSpace = nullptr; + } + + // Create the physics world & collision space + physicsWorld = new SHPhysicsWorld; + collisionSpace = new SHCollisionSpace; + + physicsWorld->SetCollisionSpace(collisionSpace); // Immediately add all existing bodies and colliders to the world. // Since we recreated the scene and the world, the initial data has been reset and determinism is guaranteed. @@ -184,7 +245,7 @@ namespace SHADE physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->AddCollider(PHYSICS_OBJECT.collider); + collisionSpace->AddCollider(PHYSICS_OBJECT.collider); } return onSceneInitEvent.get()->handle; @@ -203,9 +264,12 @@ namespace SHADE physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); + collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider); } + delete collisionSpace; + collisionSpace = nullptr; + delete physicsWorld; physicsWorld = nullptr; @@ -247,10 +311,10 @@ namespace SHADE { physicsObjectManager.AddCollider(EID); - if (physicsWorld) + if (collisionSpace) { auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; - physicsWorld->AddCollider(collider); + collisionSpace->AddCollider(collider); } } @@ -289,17 +353,16 @@ namespace SHADE if (IS_COLLIDER) { - if (physicsWorld) + if (collisionSpace) { auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; - physicsWorld->RemoveCollider(collider); + collisionSpace->RemoveCollider(collider); } physicsObjectManager.RemoveCollider(EID); } - return onComponentRemovedEvent.get()->handle; } -} // namespace SHADE \ No newline at end of file +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index fca12498..ab28a299 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -33,6 +33,13 @@ namespace SHADE */ class SH_API SHPhysicsSystem final : public SHSystem { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsDebugDrawSystem; + public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -45,7 +52,6 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] const SHPhysicsWorld* GetWorld () const noexcept; [[nodiscard]] double GetFixedUpdateRate() const noexcept; [[nodiscard]] double GetFixedDT () const noexcept; @@ -56,6 +62,9 @@ namespace SHADE void SetFixedUpdateRate(double fixedUpdateRate) noexcept; void SetFixedDT(double fixedDt) noexcept; + const std::vector& GetTriggerInfo () const noexcept; + const std::vector& GetCollisionInfo () const noexcept; + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ @@ -137,6 +146,7 @@ namespace SHADE // Sub-systems / managers SHPhysicsWorld* physicsWorld; + SHCollisionSpace* collisionSpace; SHPhysicsObjectManager physicsObjectManager; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index 06f1b464..f72eb271 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -1,8 +1,6 @@ /************************************************************************************//*! \file SHPhysicsSystemInterface.cpp -\author Tng Kah Wei, kahwei.tng, 390009620 -\par email: kahwei.tng\@digipen.edu -\date Oct 31, 2022 +\author Diren D Bharwani, diren.dbharwani, 390002520 \brief Contains the definitions of the functions of the static SHPhysicsSystemInterface class. @@ -10,10 +8,13 @@ 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. *//*************************************************************************************/ -// Precompiled Headers + + #include "SHpch.h" + // Primary Header #include "SHPhysicsSystemInterface.h" + // Project Includes #include "ECS_Base/Managers/SHSystemManager.h" #include "Physics/System/SHPhysicsSystem.h" @@ -23,42 +24,47 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Static Usage Functions */ /*-----------------------------------------------------------------------------------*/ - const std::vector& SHPhysicsSystemInterface::GetCollisionInfo() noexcept + const std::vector& SHPhysicsSystemInterface::GetCollisionInfo() noexcept { - static std::vector emptyVec; + static std::vector emptyVec; - //auto phySystem = SHSystemManager::GetSystem(); - //if (phySystem) - //{ - // return phySystem->GetAllCollisionInfo(); - //} + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetCollisionInfo(); - //SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); + SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); return emptyVec; } - const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept + const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept { - static std::vector emptyVec; + static std::vector emptyVec; - //auto phySystem = SHSystemManager::GetSystem(); - //if (phySystem) - //{ - // return phySystem->GetAllTriggerInfo(); - //} + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetTriggerInfo(); - //SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); + SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); return emptyVec; } double SHPhysicsSystemInterface::GetFixedDT() noexcept { - auto phySystem = SHSystemManager::GetSystem(); - if (phySystem) - { - return 1.0 / phySystem->GetFixedUpdateRate(); - } + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetFixedDT(); SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); return 0.0; } + + int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetFixedUpdateRate(); + + SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead."); + return 0.0; + } + } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index ed190cc9..e6103e87 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -1,22 +1,20 @@ /************************************************************************************//*! \file SHPhysicsSystemInterface.h -\author Tng Kah Wei, kahwei.tng, 390009620 -\par email: kahwei.tng\@digipen.edu -\date Oct 31, 2022 +\author Diren D Bharwani, diren.dbharwani, 390002520 \brief Contains the definition of the SHGraphicsSystemInterface static class. 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 -// STL Includes #include // Project Headers #include "ECS_Base/Entity/SHEntity.h" -#include "Physics/Collision/SHCollisionInfo.h" +#include "Physics/Collision/Contacts/SHCollisionEvents.h" namespace SHADE @@ -49,8 +47,8 @@ namespace SHADE /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; + [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; [[nodiscard]] static double GetFixedDT () noexcept; [[nodiscard]] static int GetFixedUpdateRate () noexcept; }; diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index a5a0ebc7..1393fe33 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -30,7 +30,6 @@ of DigiPen Institute of Technology is prohibited. #include "Engine/Application.hxx" #include "Physics/System/SHPhysicsSystemInterface.h" #include "Physics/SHPhysicsEvents.h" -#include "Physics/Collision/SHCollisionInfo.h" namespace SHADE { @@ -605,8 +604,8 @@ namespace SHADE { auto entities = { - std::make_pair(collisionInfo.GetEntityA(), collisionInfo.GetEntityB()), - std::make_pair(collisionInfo.GetEntityB(), collisionInfo.GetEntityA()) + std::make_pair(collisionInfo.info.GetEntityA(), collisionInfo.info.GetEntityB()), + std::make_pair(collisionInfo.info.GetEntityB(), collisionInfo.info.GetEntityA()) }; for (auto entity : entities) { @@ -625,15 +624,15 @@ namespace SHADE for (int i = 0; i < entityScripts->Count; ++i) { Script^ script = entityScripts[i]; - switch (collisionInfo.GetCollisionState()) + switch (collisionInfo.state) { - case SHCollisionInfo::State::ENTER: + case SHCollisionState::ENTER: script->OnCollisionEnter(info); break; - case SHCollisionInfo::State::STAY: + case SHCollisionState::STAY: script->OnCollisionStay(info); break; - case SHCollisionInfo::State::EXIT: + case SHCollisionState::EXIT: script->OnCollisionExit(info); break; } @@ -647,8 +646,8 @@ namespace SHADE { auto entities = { - std::make_pair(triggerInfo.GetEntityA(), triggerInfo.GetEntityB()), - std::make_pair(triggerInfo.GetEntityB(), triggerInfo.GetEntityA()) + std::make_pair(triggerInfo.info.GetEntityA(), triggerInfo.info.GetEntityB()), + std::make_pair(triggerInfo.info.GetEntityB(), triggerInfo.info.GetEntityA()) }; for (auto entity : entities) { @@ -667,15 +666,15 @@ namespace SHADE for (int i = 0; i < entityScripts->Count; ++i) { Script^ script = entityScripts[i]; - switch (triggerInfo.GetCollisionState()) + switch (triggerInfo.state) { - case SHCollisionInfo::State::ENTER: + case SHCollisionState::ENTER: script->OnTriggerEnter(info); break; - case SHCollisionInfo::State::STAY: + case SHCollisionState::STAY: script->OnTriggerStay(info); break; - case SHCollisionInfo::State::EXIT: + case SHCollisionState::EXIT: script->OnTriggerExit(info); break; } -- 2.40.1 From 265a5bece8aa8ab0804a692550faa2c2697bd730 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 00:40:01 +0800 Subject: [PATCH 25/84] Slight refactor to fix collision states for very fast moving objects --- Assets/Scenes/PhysicsSandbox.shade | 8 +- .../Physics/Collision/Contacts/SHManifold.h | 26 ++- .../Physics/Collision/Contacts/SHManifold.hpp | 151 ++++++++++++++++++ .../Physics/Collision/SHCollisionSpace.cpp | 30 ++-- .../src/Physics/Dynamics/SHContactManager.cpp | 118 +++++++------- .../src/Physics/Dynamics/SHContactManager.h | 34 ++-- .../src/Physics/Dynamics/SHContactManager.hpp | 4 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 3 - 8 files changed, 283 insertions(+), 91 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 21840aca..d983c22b 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,8 +4,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 3, z: 0} - Rotate: {x: 0, y: 0, z: -0} + Translate: {x: 0, y: 0.0579863191, z: 0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: @@ -15,7 +15,7 @@ Drag: 1 Angular Drag: 1 Use Gravity: true - Gravity Scale: 1 + Gravity Scale: 10 Interpolate: true Sleeping Enabled: true Freeze Position X: false @@ -48,7 +48,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 2, z: 3} + Position: {x: 0, y: 0.5, z: 2} Pitch: 0 Yaw: 0 Roll: 0 diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h index 0534f749..c2b6ddb2 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h @@ -25,6 +25,23 @@ namespace SHADE struct SH_API SHManifold { public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHManifold (SHCollisionShape* a, SHCollisionShape* b) noexcept; + SHManifold (const SHManifold& rhs) noexcept; + SHManifold (SHManifold&& rhs) noexcept; + + ~SHManifold () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHManifold& operator=(const SHManifold& rhs) noexcept; + SHManifold& operator=(SHManifold&& rhs) noexcept; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ @@ -32,8 +49,8 @@ namespace SHADE // We only need 4 contact points to build a stable manifold. static constexpr int MAX_NUM_CONTACTS = 4; - SHCollisionShape* A = nullptr; - SHCollisionShape* B = nullptr; + SHCollisionShape* A; + SHCollisionShape* B; uint32_t numContacts = 0; SHCollisionState state = SHCollisionState::INVALID; @@ -44,4 +61,7 @@ namespace SHADE }; -} \ No newline at end of file +} // namespace SHADE + +#include "SHManifold.hpp" + diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp new file mode 100644 index 00000000..f0e1374f --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp @@ -0,0 +1,151 @@ +/**************************************************************************************** + * \file SHManifold.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collision Manifold + * + * \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 "SHManifold.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + inline SHManifold::SHManifold(SHCollisionShape* a, SHCollisionShape* b) noexcept + : A { a } + , B { b } + {} + + inline SHManifold::SHManifold(const SHManifold& rhs) noexcept + : A { rhs.A } + , B { rhs.B } + , numContacts { rhs.numContacts } + , state { rhs.state } + , normal { rhs.normal } + { + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) + tangents[i] = rhs.tangents[i]; + + for (int i = 0; i < MAX_NUM_CONTACTS; ++i) + { + contacts[i].penetration = rhs.contacts[i].penetration; + contacts[i].bias = rhs.contacts[i].bias; + contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; + contacts[i].normalMass = rhs.contacts[i].normalMass; + + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + { + contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; + contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; + } + + contacts[i].position = rhs.contacts[i].position; + contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; + } + } + + inline SHManifold::SHManifold(SHManifold&& rhs) noexcept + : A { rhs.A } + , B { rhs.B } + , numContacts { rhs.numContacts } + , state { rhs.state } + , normal { rhs.normal } + { + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) + tangents[i] = rhs.tangents[i]; + + for (int i = 0; i < MAX_NUM_CONTACTS; ++i) + { + contacts[i].penetration = rhs.contacts[i].penetration; + contacts[i].bias = rhs.contacts[i].bias; + contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; + contacts[i].normalMass = rhs.contacts[i].normalMass; + + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + { + contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; + contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; + } + + contacts[i].position = rhs.contacts[i].position; + contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; + } + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + inline SHManifold& SHManifold::operator=(const SHManifold& rhs) noexcept + { + if (this == &rhs) + return *this; + + A = rhs.A; + B = rhs.B; + numContacts = rhs.numContacts; + state = rhs.state; + normal = rhs.normal; + + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) + tangents[i] = rhs.tangents[i]; + + for (int i = 0; i < MAX_NUM_CONTACTS; ++i) + { + contacts[i].penetration = rhs.contacts[i].penetration; + contacts[i].bias = rhs.contacts[i].bias; + contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; + contacts[i].normalMass = rhs.contacts[i].normalMass; + + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + { + contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; + contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; + } + + contacts[i].position = rhs.contacts[i].position; + contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; + } + + return *this; + } + + inline SHManifold& SHManifold::operator=(SHManifold&& rhs) noexcept + { + A = rhs.A; + B = rhs.B; + numContacts = rhs.numContacts; + state = rhs.state; + normal = rhs.normal; + + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) + tangents[i] = rhs.tangents[i]; + + for (int i = 0; i < MAX_NUM_CONTACTS; ++i) + { + contacts[i].penetration = rhs.contacts[i].penetration; + contacts[i].bias = rhs.contacts[i].bias; + contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; + contacts[i].normalMass = rhs.contacts[i].normalMass; + + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + { + contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; + contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; + } + + contacts[i].position = rhs.contacts[i].position; + contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; + } + + return *this; + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp index bc76d14a..ab4520ee 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -102,6 +102,8 @@ namespace SHADE void SHCollisionSpace::DetectCollisions() noexcept { + // TODO: Profile broad-phase and narrow-phase + /* * Broad-phase */ @@ -112,11 +114,14 @@ namespace SHADE // Colliders without bodies are considered to be static bodies // This is specific to this engine because of Unity's stupid convention. const bool IS_IMPLICIT_STATIC = !collider->rigidBody; - const bool IS_EXPLICIT_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC; const bool IS_ACTIVE = collider->active; // Skip inactive colliders - if (!IS_ACTIVE || IS_IMPLICIT_STATIC || IS_EXPLICIT_STATIC) + if (!IS_ACTIVE || IS_IMPLICIT_STATIC) + continue; + + const bool IS_EXPLICIT_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC; + if (IS_EXPLICIT_STATIC) continue; // All remaining are kinematic or dynamic @@ -149,6 +154,10 @@ namespace SHADE // Clear every frame narrowphaseBatch.clear(); + + // Test all collisions + if (contactManager) + contactManager->Update(); } @@ -198,14 +207,12 @@ namespace SHADE void SHCollisionSpace::collideTriggers(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept { - const auto* A = narrowphasePair.A; - const auto* B = narrowphasePair.B; + auto* A = narrowphasePair.A; + auto* B = narrowphasePair.B; - const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B); - - // Send results to contact manager + // Send to contact manager if (contactManager) - contactManager->AddTrigger(COLLIDING, key); + contactManager->AddTrigger(key, A, B); } void SHCollisionSpace::collideManifolds(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept @@ -213,11 +220,8 @@ namespace SHADE auto* A = narrowphasePair.A; auto* B = narrowphasePair.B; - SHManifold newManifold { .A = A, .B = B }; - const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B); - - // Send results to contact manager + // Send to contact manager if (contactManager) - contactManager->AddManifold(COLLIDING, key, newManifold); + contactManager->AddManifold(key, A, B); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index be65128d..0ab20b38 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -14,6 +14,9 @@ // Primary Header #include "SHContactManager.h" +// Project Headers +#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -26,8 +29,8 @@ namespace SHADE triggerEvents.clear(); - for (auto& [id, state] : triggers) - triggerEvents.emplace_back(SHTriggerEvent{ id, state }); + for (auto& [id, trigger] : triggers) + triggerEvents.emplace_back(SHTriggerEvent{ id, trigger.state }); return triggerEvents; } @@ -62,92 +65,83 @@ namespace SHADE void SHContactManager::Update() noexcept { - // Clear expired or invalid collisions - for (auto manifold = manifolds.begin(); manifold != manifolds.end();) + // Clear expired or invalid collisions. If not, test collision. + for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) { - const auto COLLISION_STATE = manifold->second.state; + // Test collision of every manifold. + SHManifold& oldManifold = manifoldPair->second; + SHManifold newManifold = oldManifold; - const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; - const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; + const bool IS_COLLIDING = SHCollisionDispatcher::Collide(newManifold, *newManifold.A, *newManifold.B); - if (IS_EXIT || IS_INVALID) - manifold = manifolds.erase(manifold); - else - ++manifold; + auto& collisionState = newManifold.state; + updateCollisionState(IS_COLLIDING, collisionState); + + const bool IS_INVALID = collisionState == SHCollisionState::INVALID; + if (IS_INVALID) + { + manifoldPair = manifolds.erase(manifoldPair); + continue; + } + + updateManifold(oldManifold, newManifold); + ++manifoldPair; } - // Clear expired or invalid triggers - for (auto trigger = triggers.begin(); trigger != triggers.end();) + // Clear expired or invalid triggers, If not, test collision. + for (auto triggerPair = triggers.begin(); triggerPair != triggers.end();) { - const auto COLLISION_STATE = trigger->second; + // Test collision of every trigger. + Trigger& oldTrigger = triggerPair->second; + Trigger newTrigger = oldTrigger; - const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; - const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; + const bool IS_COLLIDING = SHCollisionDispatcher::Collide(*newTrigger.A, *newTrigger.B); - if (IS_EXIT || IS_INVALID) - trigger = triggers.erase(trigger); + auto& collisionState = newTrigger.state; + updateCollisionState(IS_COLLIDING, collisionState); + + const bool IS_INVALID = collisionState == SHCollisionState::INVALID; + if (IS_INVALID) + triggerPair = triggers.erase(triggerPair); else - ++trigger; + ++triggerPair; } } - void SHContactManager::AddTrigger(bool isColliding, const SHCollisionKey& key) noexcept + void SHContactManager::AddTrigger(const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept { + // If id not found, emplace new trigger. auto trigger = triggers.find(key); - - // If id not found, emplace new object. - // New object is in the invalid state if (trigger == triggers.end()) - trigger = triggers.emplace(key, SHCollisionState::INVALID).first; - - SHCollisionState& state = trigger->second; - updateCollisionState(isColliding, state); - - // If it was a false positive, remove the manifold immediately. - // Remove using iterator as it is on average faster. - if (state == SHCollisionState::INVALID) - trigger = triggers.erase(trigger); + triggers.emplace(key, Trigger{ A, B, SHCollisionState::INVALID }).first; } - void SHContactManager::AddManifold(bool isColliding, const SHCollisionKey& key, const SHManifold& newManifold) noexcept + void SHContactManager::AddManifold(const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept { - auto manifold = manifolds.find(key); - // If id not found, emplace new manifold + auto manifold = manifolds.find(key); if (manifold == manifolds.end()) - manifold = manifolds.emplace(key, newManifold).first; - else - { - // TODO: Update existing manifolds with new data - } - - SHCollisionState& state = manifold->second.state; - updateCollisionState(isColliding, state); - - // If it was a false positive, remove the manifold immediately. - // Remove using iterator as it is on average faster. - if (state == SHCollisionState::INVALID) - manifold = manifolds.erase(manifold); + manifolds.emplace(key, SHManifold{ A, B }).first; } void SHContactManager::RemoveInvalidatedTrigger(EntityID eid) noexcept { - remove(triggers, eid); + removeInvalidObject(triggers, eid); } void SHContactManager::RemoveInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) noexcept { - remove(triggers, eid, shapeIndex); + removeInvalidObject(triggers, eid, shapeIndex); } void SHContactManager::RemoveInvalidatedManifold(EntityID eid) noexcept { - remove(manifolds, eid); + removeInvalidObject(manifolds, eid); } void SHContactManager::RemoveInvalidatedManifold(EntityID eid, uint32_t shapeIndex) noexcept { - remove(manifolds, eid, shapeIndex); + removeInvalidObject(manifolds, eid, shapeIndex); } /*-----------------------------------------------------------------------------------*/ @@ -164,10 +158,26 @@ namespace SHADE } else { - // New states start at invalid. In false positive, remain unchanged. + // If already exited and still not colliding, the collision has expired. + // Invalid states are removed in the next frame + if (state == SHCollisionState::EXIT) + state = SHCollisionState::INVALID; + // If previously colliding, move to exit. - state = state == SHCollisionState::INVALID ? SHCollisionState::INVALID : SHCollisionState::EXIT; + if (state == SHCollisionState::ENTER || state == SHCollisionState::STAY) + state = SHCollisionState::EXIT; } } + void SHContactManager::updateManifold(SHManifold& oldManifold, SHManifold& newManifold) noexcept + { + oldManifold.state = newManifold.state; + + // Early out since exiting a collision does not require an update beyond updating the state + if (newManifold.state == SHCollisionState::EXIT) + return; + + + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h index 06a03a6a..9e082db1 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -54,26 +54,35 @@ namespace SHADE /** * @brief - * Removes any invalidated contacts and triggers. + * Removes any invalidated contacts and triggers, then performs narrowphase collision + * detection on existing triggers and manifolds. * @return */ - void Update () noexcept; + void Update () noexcept; - void AddTrigger (bool isColliding, const SHCollisionKey& key) noexcept; - void AddManifold (bool isColliding, const SHCollisionKey& key, const SHManifold& newManifold) noexcept; + void AddTrigger (const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept; + void AddManifold (const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept; - void RemoveInvalidatedTrigger (EntityID eid) noexcept; - void RemoveInvalidatedTrigger (EntityID eid, uint32_t shapeIndex) noexcept; - void RemoveInvalidatedManifold (EntityID eid) noexcept; - void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept; + void RemoveInvalidatedTrigger (EntityID eid) noexcept; + void RemoveInvalidatedTrigger (EntityID eid, uint32_t shapeIndex) noexcept; + void RemoveInvalidatedManifold (EntityID eid) noexcept; + void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept; private: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ + struct Trigger + { + SHCollisionShape* A = nullptr; + SHCollisionShape* B = nullptr; + + SHCollisionState state = SHCollisionState::INVALID; + }; + using Manifolds = std::unordered_map; - using Triggers = std::unordered_map; + using Triggers = std::unordered_map; /*---------------------------------------------------------------------------------*/ /* Data Members */ @@ -86,14 +95,15 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; + static void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; + static void updateManifold (SHManifold& oldManifold, SHManifold& newManifold) noexcept; // Removal Helpers template - void remove (std::unordered_map& container, EntityID eid); + static void removeInvalidObject (std::unordered_map& container, EntityID eid) noexcept; template - void remove (std::unordered_map& container, EntityID eid, uint32_t shapeIndex); + static void removeInvalidObject (std::unordered_map& container, EntityID eid, uint32_t shapeIndex) noexcept; }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp index 1403cd79..04a4b234 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp @@ -20,7 +20,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ template - void SHContactManager::remove(std::unordered_map& container, EntityID eid) + void SHContactManager::removeInvalidObject(std::unordered_map& container, EntityID eid) noexcept { if (container.empty()) return; @@ -40,7 +40,7 @@ namespace SHADE } template - void SHContactManager::remove(std::unordered_map& container, EntityID eid, uint32_t shapeIndex) + void SHContactManager::removeInvalidObject(std::unordered_map& container, EntityID eid, uint32_t shapeIndex) noexcept { if (container.empty()) return; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index b5dba378..bb42364d 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -81,9 +81,6 @@ namespace SHADE void SHPhysicsWorld::Step(float dt) { - // Contact manager to clear expired contacts - contactManager.Update(); - /* * Detect Collisions */ -- 2.40.1 From 33ef5e0d3d1ffbe433993944d1644b3eec6c897b Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 01:10:28 +0800 Subject: [PATCH 26/84] Implemented accumulated impulses untested --- .../src/Physics/Dynamics/SHContactManager.cpp | 58 ++++++++++++++++--- .../src/Physics/Dynamics/SHContactManager.h | 4 +- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 0ab20b38..1159f445 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -15,6 +15,7 @@ #include "SHContactManager.h" // Project Headers +#include "Math/SHMathHelpers.h" #include "Physics/Collision/Narrowphase/SHCollisionDispatch.h" namespace SHADE @@ -69,12 +70,12 @@ namespace SHADE for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) { // Test collision of every manifold. - SHManifold& oldManifold = manifoldPair->second; - SHManifold newManifold = oldManifold; + SHManifold& manifold = manifoldPair->second; + SHManifold oldManifold = manifold; - const bool IS_COLLIDING = SHCollisionDispatcher::Collide(newManifold, *newManifold.A, *newManifold.B); + const bool IS_COLLIDING = SHCollisionDispatcher::Collide(manifold, *manifold.A, *manifold.B); - auto& collisionState = newManifold.state; + auto& collisionState = oldManifold.state; updateCollisionState(IS_COLLIDING, collisionState); const bool IS_INVALID = collisionState == SHCollisionState::INVALID; @@ -84,7 +85,7 @@ namespace SHADE continue; } - updateManifold(oldManifold, newManifold); + updateManifold(manifold, oldManifold); ++manifoldPair; } @@ -169,15 +170,56 @@ namespace SHADE } } - void SHContactManager::updateManifold(SHManifold& oldManifold, SHManifold& newManifold) noexcept + void SHContactManager::updateManifold(SHManifold& manifold, const SHManifold& oldManifold) noexcept { - oldManifold.state = newManifold.state; + manifold.state = oldManifold.state; // Early out since exiting a collision does not require an update beyond updating the state - if (newManifold.state == SHCollisionState::EXIT) + if (manifold.state == SHCollisionState::EXIT) return; + const SHVec3& NORMAL = manifold.normal; + SHVec3& tangent0 = manifold.tangents[0]; + SHVec3& tangent1 = manifold.tangents[1]; + const SHVec3& OLD_TANGENT_0 = oldManifold.tangents[0]; + const SHVec3& OLD_TANGENT_1 = oldManifold.tangents[1]; + + // Compute tangents + if (std::fabs(NORMAL.x) >= SHMath::EULER_CONSTANT) + tangent0 = SHVec3{ NORMAL.y, -NORMAL.x, 0.0f }; + else + tangent0 = SHVec3{ 0.0f, NORMAL.z, -NORMAL.y }; + + tangent0 = SHVec3::Normalise(tangent0); + tangent1 = SHVec3::Cross(NORMAL, tangent0); + + // Accumulate impulses + for (uint32_t i = 0; i < manifold.numContacts; ++i) + { + SHContact& contact = manifold.contacts[i]; + + // Reset impulses + contact.normalImpulse = 0.0f; + contact.tangentImpulse[0] = contact.tangentImpulse[1] = 0.0f; + + for (uint32_t j = 0; j < oldManifold.numContacts; ++j) + { + const SHContact& OLD_CONTACT = oldManifold.contacts[j]; + + if (OLD_CONTACT.featurePair.key != contact.featurePair.key) + continue; + + // If contact features persists, re-project old solution + contact.normalImpulse = OLD_CONTACT.normalImpulse; + + const SHVec3 FRICTION_FORCE = OLD_TANGENT_0 * OLD_CONTACT.tangentImpulse[0] + OLD_TANGENT_1 * OLD_CONTACT.tangentImpulse[1]; + contact.tangentImpulse[0] = SHVec3::Dot(FRICTION_FORCE, tangent0); + contact.tangentImpulse[1] = SHVec3::Dot(FRICTION_FORCE, tangent1); + + break; + } + } } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h index 9e082db1..ecbf6dd4 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -95,8 +95,8 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - static void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; - static void updateManifold (SHManifold& oldManifold, SHManifold& newManifold) noexcept; + static void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; + static void updateManifold (SHManifold& manifold, const SHManifold& newManifold) noexcept; // Removal Helpers -- 2.40.1 From d109d06764fc653dfe7ca34e1ec1ed96a025285e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 18:57:10 +0800 Subject: [PATCH 27/84] Implemented sequential impulses using baumgarte stabilisation There is a bug with masses of static bodies not being properly set --- Assets/Scenes/PhysicsSandbox.shade | 8 +- .../CollisionShapes/SHCollisionShape.cpp | 10 + .../CollisionShapes/SHCollisionShape.h | 3 + .../Collision/Contacts/SHCollisionEvents.h | 2 +- .../Physics/Collision/Contacts/SHContact.h | 30 +- .../Physics/Collision/Contacts/SHManifold.hpp | 80 +---- .../Constraints/SHContactConstraint.h | 57 ++++ .../src/Physics/Dynamics/SHContactManager.cpp | 37 ++- .../src/Physics/Dynamics/SHContactManager.h | 30 +- .../src/Physics/Dynamics/SHContactSolver.cpp | 290 ++++++++++++++++++ .../src/Physics/Dynamics/SHContactSolver.h | 108 +++++++ .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 26 +- .../src/Physics/Dynamics/SHPhysicsWorld.h | 4 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 16 +- .../src/Physics/Dynamics/SHRigidBody.h | 1 + 15 files changed, 599 insertions(+), 103 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp create mode 100644 SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index d983c22b..8323a26e 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 0.0579863191, z: 0} + Translate: {x: 0, y: 3, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -15,7 +15,7 @@ Drag: 1 Angular Drag: 1 Use Gravity: true - Gravity Scale: 10 + Gravity Scale: 1 Interpolate: true Sleeping Enabled: true Freeze Position X: false @@ -48,7 +48,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 0.5, z: 2} + Position: {x: 0, y: 0.5, z: 3} Pitch: 0 Yaw: 0 Roll: 0 @@ -70,7 +70,7 @@ Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: - Type: Dynamic + Type: Static Auto Mass: false Mass: 1 Drag: 0.00999999978 diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index 5dd17d35..d3f26a8b 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -37,6 +37,16 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + EntityID SHCollisionShape::GetEntityID() const noexcept + { + return id.GetEntityID(); + } + + uint32_t SHCollisionShape::GetIndex() const noexcept + { + return id.GetShapeIndex(); + } + float SHCollisionShape::GetFriction() const noexcept { return material.GetFriction(); diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 6e779eea..2cc156e1 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -75,6 +75,9 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + [[nodiscard]] EntityID GetEntityID () const noexcept; + [[nodiscard]] uint32_t GetIndex () const noexcept; + // Material Properties // TODO: Remove individual setters once instanced materials are supported diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h index db55ca50..3dbb16d0 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h @@ -51,7 +51,7 @@ namespace SHADE public: static constexpr int MAX_NUM_CONTACTS = 4; - SHCollisionKey info; + SHCollisionKey info; SHCollisionState state; SHVec3 normal; SHVec3 contactPoints[MAX_NUM_CONTACTS]; diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h index c70f6e39..15c24ef2 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -27,16 +27,26 @@ namespace SHADE union SHContactFeatures { public: + /*---------------------------------------------------------------------------------*/ + /* Type Definit */ + /*---------------------------------------------------------------------------------*/ + + enum class Type : uint8_t + { + VERTEX = 0 + , FACE = 1 + }; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ struct { - uint8_t incomingIncident; - uint8_t outgoingIncident; - uint8_t incomingReference; - uint8_t outgoingReference; + uint8_t indexA; + uint8_t indexB; + uint8_t typeA; + uint8_t typeB; }; uint32_t key = 0; @@ -56,13 +66,15 @@ namespace SHADE static constexpr int NUM_TANGENTS = 2; float penetration = 0.0f; - float bias = 0.0f; - float normalImpulse = 0.0f; - float normalMass = 0.0f; - float tangentImpulse[NUM_TANGENTS] = { 0.0f }; - float tangentMass[NUM_TANGENTS] = { 0.0f }; + float bias = 0.0f; // Restitution + Baumguarte factor + float normalImpulse = 0.0f; // Accumulated normal impulse + float normalMass = 0.0f; // Effective mass along the normal + float tangentImpulse[NUM_TANGENTS] = { 0.0f }; // Accumulated tangent impulses + float tangentMass[NUM_TANGENTS] = { 0.0f }; // Effective masses along the tangents SHVec3 position; + SHVec3 rA; // Vector from COM of A to the contact + SHVec3 rB; // Vector from COM of B to the contact SHContactFeatures featurePair; }; } diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp index f0e1374f..e43b9625 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp @@ -31,25 +31,11 @@ namespace SHADE , state { rhs.state } , normal { rhs.normal } { + static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); + memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) tangents[i] = rhs.tangents[i]; - - for (int i = 0; i < MAX_NUM_CONTACTS; ++i) - { - contacts[i].penetration = rhs.contacts[i].penetration; - contacts[i].bias = rhs.contacts[i].bias; - contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; - contacts[i].normalMass = rhs.contacts[i].normalMass; - - for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) - { - contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; - contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; - } - - contacts[i].position = rhs.contacts[i].position; - contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; - } } inline SHManifold::SHManifold(SHManifold&& rhs) noexcept @@ -59,25 +45,11 @@ namespace SHADE , state { rhs.state } , normal { rhs.normal } { + static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); + memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) tangents[i] = rhs.tangents[i]; - - for (int i = 0; i < MAX_NUM_CONTACTS; ++i) - { - contacts[i].penetration = rhs.contacts[i].penetration; - contacts[i].bias = rhs.contacts[i].bias; - contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; - contacts[i].normalMass = rhs.contacts[i].normalMass; - - for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) - { - contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; - contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; - } - - contacts[i].position = rhs.contacts[i].position; - contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; - } } /*-----------------------------------------------------------------------------------*/ @@ -95,26 +67,12 @@ namespace SHADE state = rhs.state; normal = rhs.normal; + static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); + memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) tangents[i] = rhs.tangents[i]; - for (int i = 0; i < MAX_NUM_CONTACTS; ++i) - { - contacts[i].penetration = rhs.contacts[i].penetration; - contacts[i].bias = rhs.contacts[i].bias; - contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; - contacts[i].normalMass = rhs.contacts[i].normalMass; - - for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) - { - contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; - contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; - } - - contacts[i].position = rhs.contacts[i].position; - contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; - } - return *this; } @@ -126,26 +84,12 @@ namespace SHADE state = rhs.state; normal = rhs.normal; + static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); + memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); + for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) tangents[i] = rhs.tangents[i]; - for (int i = 0; i < MAX_NUM_CONTACTS; ++i) - { - contacts[i].penetration = rhs.contacts[i].penetration; - contacts[i].bias = rhs.contacts[i].bias; - contacts[i].normalImpulse = rhs.contacts[i].normalImpulse; - contacts[i].normalMass = rhs.contacts[i].normalMass; - - for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) - { - contacts[i].tangentImpulse[j] = rhs.contacts[i].tangentImpulse[j]; - contacts[i].tangentMass[j] = rhs.contacts[i].tangentMass[j]; - } - - contacts[i].position = rhs.contacts[i].position; - contacts[i].featurePair.key = rhs.contacts[i].featurePair.key; - } - return *this; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h new file mode 100644 index 00000000..55e195a6 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h @@ -0,0 +1,57 @@ +/**************************************************************************************** + * \file SHContactConstraint.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Contact Constraint. + * + * \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 "Physics/Collision/Contacts/SHManifold.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + struct SH_API SHContactConstraint + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + // Use the entity IDs to map resolved constraints back to the bodies + + EntityID idA = MAX_EID; + EntityID idB = MAX_EID; + + uint32_t numContacts = 0; + + // Material Data + + float friction = 0.0f; + float restitution = 0.0f; + + // Mass Data + + float invMassA = 0.0f; + float invMassB = 0.0f; + SHMatrix invInertiaA; + SHMatrix invInertiaB; + SHVec3 centerOfMassA; + SHVec3 centerOfMassB; + + // Collision Data + + SHVec3 normal; + SHVec3 tangents[SHContact::NUM_TANGENTS]; + SHContact contacts[SHManifold::MAX_NUM_CONTACTS]; + }; +} // namespace SHADE + diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 1159f445..3ad3c0b3 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -60,6 +60,25 @@ namespace SHADE return collisionEvents; } + const SHContactManager::ContactPoints& SHContactManager::GetContactPoints() const noexcept + { + static ContactPoints contactPoints; + + contactPoints.clear(); + + for (auto& manifold : manifolds | std::views::values) + { + // Skip exit state manifolds + if (manifold.state == SHCollisionState::EXIT) + continue; + + for (uint32_t i = 0; i < manifold.numContacts; ++i) + contactPoints.emplace_back(manifold.contacts[i].position); + } + + return contactPoints; + } + /*-----------------------------------------------------------------------------------*/ /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -207,17 +226,17 @@ namespace SHADE { const SHContact& OLD_CONTACT = oldManifold.contacts[j]; - if (OLD_CONTACT.featurePair.key != contact.featurePair.key) - continue; + if (OLD_CONTACT.featurePair.key == contact.featurePair.key) + { + // If contact features persists, re-project old solution + contact.normalImpulse = OLD_CONTACT.normalImpulse; - // If contact features persists, re-project old solution - contact.normalImpulse = OLD_CONTACT.normalImpulse; + const SHVec3 FRICTION_FORCE = OLD_TANGENT_0 * OLD_CONTACT.tangentImpulse[0] + OLD_TANGENT_1 * OLD_CONTACT.tangentImpulse[1]; + contact.tangentImpulse[0] = SHVec3::Dot(FRICTION_FORCE, tangent0); + contact.tangentImpulse[1] = SHVec3::Dot(FRICTION_FORCE, tangent1); - const SHVec3 FRICTION_FORCE = OLD_TANGENT_0 * OLD_CONTACT.tangentImpulse[0] + OLD_TANGENT_1 * OLD_CONTACT.tangentImpulse[1]; - contact.tangentImpulse[0] = SHVec3::Dot(FRICTION_FORCE, tangent0); - contact.tangentImpulse[1] = SHVec3::Dot(FRICTION_FORCE, tangent1); - - break; + break; + } } } } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h index ecbf6dd4..692dc2e8 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -1,8 +1,7 @@ /**************************************************************************************** * \file SHContactManager.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Contact Manager that stores collision information and - * resolves contact constraints. + * \brief Interface for a Contact Manager that stores collision information. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -24,8 +23,19 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates a class that stores collision information. + */ class SH_API SHContactManager { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsWorld; + public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -33,6 +43,7 @@ namespace SHADE using TriggerEvents = std::vector; using CollisionEvents = std::vector; + using ContactPoints = std::vector; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -42,11 +53,12 @@ namespace SHADE ~SHContactManager () noexcept = default; /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ + /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - const TriggerEvents& GetTriggerEvents () const noexcept; - const CollisionEvents& GetCollisionEvents () const noexcept; + const TriggerEvents& GetTriggerEvents () const noexcept; + const CollisionEvents& GetCollisionEvents () const noexcept; + const ContactPoints& GetContactPoints () const noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ @@ -58,7 +70,7 @@ namespace SHADE * detection on existing triggers and manifolds. * @return */ - void Update () noexcept; + void Update () noexcept; void AddTrigger (const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept; void AddManifold (const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept; @@ -88,15 +100,15 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - Manifolds manifolds; - Triggers triggers; + Manifolds manifolds; + Triggers triggers; /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ static void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; - static void updateManifold (SHManifold& manifold, const SHManifold& newManifold) noexcept; + static void updateManifold (SHManifold& manifold, const SHManifold& oldManifold) noexcept; // Removal Helpers diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp new file mode 100644 index 00000000..84805c57 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -0,0 +1,290 @@ +/**************************************************************************************** + * \file SHContactSolver.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Contact Solver. + * + * \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 + +// Primary Header +#include "SHContactSolver.h" + +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Getter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHContactSolver::VelocityStates& SHContactSolver::GetVelocities() const noexcept + { + return velocityStates; + } + + const SHContactSolver::ContactConstraints& SHContactSolver::GetContantConstraints() const noexcept + { + return contactConstraints; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHContactSolver::AddContact(const SHManifold& manifold, const SHRigidBody* rigidBodyA, const SHRigidBody* rigidBodyB) noexcept + { + SHContactConstraint& newConstraint = contactConstraints.emplace_back(SHContactConstraint{}); + + const auto* SHAPE_A = manifold.A; + const auto* SHAPE_B = manifold.B; + + newConstraint.idA = SHAPE_A->GetEntityID(); + newConstraint.idB = SHAPE_B->GetEntityID(); + + // Add velocities if it doesn't already exist + velocityStates.emplace(newConstraint.idA, VelocityState{ rigidBodyA->linearVelocity, rigidBodyB->angularVelocity }); + velocityStates.emplace(newConstraint.idB, VelocityState{ rigidBodyB->linearVelocity, rigidBodyB->angularVelocity }); + + // Mix friction & restitution + const float FRICTION_A = manifold.A->GetFriction(); + const float RESTITUTION_A = manifold.A->GetBounciness(); + + const float FRICTION_B = manifold.B->GetFriction(); + const float RESTITUTION_B = manifold.B->GetBounciness(); + + newConstraint.friction = std::sqrtf(FRICTION_A * FRICTION_B); + newConstraint.restitution = std::max(RESTITUTION_A, RESTITUTION_B); + + // Mass data + + newConstraint.invMassA = rigidBodyA->invMass; + newConstraint.invMassB = rigidBodyB->invMass; + + newConstraint.invInertiaA = rigidBodyA->worldInvInertia; + newConstraint.invInertiaB = rigidBodyB->worldInvInertia; + + newConstraint.centerOfMassA = rigidBodyA->worldCentroid; + newConstraint.centerOfMassB = rigidBodyB->worldCentroid; + + // Collision data + + newConstraint.numContacts = manifold.numContacts; + + newConstraint.normal = manifold.normal; + + static constexpr size_t TANGENTS_SIZE = sizeof(SHVec3) * SHContact::NUM_TANGENTS; + static constexpr size_t CONTACTS_SIZE = sizeof(SHContact) * SHManifold::MAX_NUM_CONTACTS; + + memcpy_s(newConstraint.tangents, TANGENTS_SIZE, manifold.tangents, TANGENTS_SIZE); + memcpy_s(newConstraint.contacts, CONTACTS_SIZE, manifold.contacts, CONTACTS_SIZE); + + // Compute rA & rB for contacts + for (uint32_t i = 0; i < newConstraint.numContacts; ++i) + { + newConstraint.contacts[i].rA = newConstraint.contacts[i].position - newConstraint.centerOfMassA; + newConstraint.contacts[i].rB = newConstraint.contacts[i].position - newConstraint.centerOfMassB; + } + } + + void SHContactSolver::ClearContacts() noexcept + { + contactConstraints.clear(); + } + + void SHContactSolver::SolveContacts(int numIterations, float dt) noexcept + { + preSolve(dt); + + for (int i = 0; i < numIterations; ++i) + solve(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHContactSolver::preSolve(float dt) noexcept + { + const float INV_DT = 1.0f / dt; + + for (auto& constraint : contactConstraints) + { + const float INV_MASS_SUM = constraint.invMassA + constraint.invMassB; + + SHVec3 vA = velocityStates[constraint.idA].linearVelocity; + SHVec3 wA = velocityStates[constraint.idA].angularVelocity; + SHVec3 vB = velocityStates[constraint.idB].linearVelocity; + SHVec3 wB = velocityStates[constraint.idB].angularVelocity; + + for (uint32_t i = 0; i < constraint.numContacts; ++i) + { + SHContact& contact = constraint.contacts[i]; + + // Calculate JM-1JT (Effective mass) + /* + * rXnT * I-1 * rXn: + * + * 1. 3x3 * 3x1 = 3x1 + * 2. 1x3 * 3x1 = 1x1 + * + * First do I-1 * rXn + * | ix 0 0 || x | | ix * x | + * | 0 iy 0 || y | = | iy * y | + * | 0 0 iz || z | | iz * z | + * + * Then dot product the result with rXnT + * | ix * x |[ u v w ] + * | iy * y | = [ ix * x * w + iy * y * v + iz * z * w ] + * | iz * z | + * + * Simplified: + * + * rXnT /dot (I-1 * rXn) + */ + + // Effective mass along Normal + const SHVec3 RA_CROSS_N = SHVec3::Cross(contact.rA, constraint.normal); + const SHVec3 RB_CROSS_N = SHVec3::Cross(contact.rB, constraint.normal); + + contact.normalMass = INV_MASS_SUM; + contact.normalMass += SHVec3::Dot(RA_CROSS_N, constraint.invInertiaA * RA_CROSS_N); + contact.normalMass += SHVec3::Dot(RB_CROSS_N, constraint.invInertiaB * RB_CROSS_N); + + // Invert the normal mass (we want the actual mass, not the inverse mass) + contact.normalMass = contact.normalMass == 0.0f ? 0.0f : 1.0f / contact.normalMass; + + // Effective mass along tangents (same steps as above) + + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + { + const SHVec3 RA_CROSS_T = SHVec3::Cross(contact.rA, constraint.tangents[j]); + const SHVec3 RB_CROSS_T = SHVec3::Cross(contact.rB, constraint.tangents[j]); + + contact.tangentMass[j] = INV_MASS_SUM; + contact.tangentMass[j] += SHVec3::Dot(RA_CROSS_T, constraint.invInertiaA * RA_CROSS_T); + contact.tangentMass[j] += SHVec3::Dot(RB_CROSS_T, constraint.invInertiaB * RB_CROSS_T); + + contact.tangentMass[j] = contact.tangentMass[j] == 0.0f ? 0.0f : 1.0f / contact.tangentMass[j]; + } + + // Warm starting + // Compute impulses + SHVec3 impulse = constraint.normal * contact.normalImpulse; + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + impulse += constraint.tangents[j] * contact.tangentImpulse[j]; + + // Apply impulses onto velocities + vA -= impulse * constraint.invMassA; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, impulse); + + vB += impulse * constraint.invMassB; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse); + + // Calculate bias per contact + /* + * error bias = baumgarte factor / dt * penetration + * restituion bias = restitution * (relative velocity /dot normal) + */ + + const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA); + const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); + const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); + + const float ERROR_BIAS = BAUMGARTE_FACTOR * INV_DT * contact.penetration; + const float RESTITUTION_BIAS = -constraint.restitution * RV_N; + + contact.bias = ERROR_BIAS + RESTITUTION_BIAS; + } + + velocityStates[constraint.idA].linearVelocity = vA; + velocityStates[constraint.idA].angularVelocity = wA; + velocityStates[constraint.idB].linearVelocity = vB; + velocityStates[constraint.idB].angularVelocity = wB; + + } + } + + void SHContactSolver::solve() noexcept + { + for (auto& constraint : contactConstraints) + { + SHVec3 vA = velocityStates[constraint.idA].linearVelocity; + SHVec3 wA = velocityStates[constraint.idA].angularVelocity; + SHVec3 vB = velocityStates[constraint.idB].linearVelocity; + SHVec3 wB = velocityStates[constraint.idB].angularVelocity; + + for (uint32_t i = 0; i < constraint.numContacts; ++i) + { + SHContact& contact = constraint.contacts[i]; + + // Compute relative velocity + SHVec3 velocityA = vA + SHVec3::Cross(wA, contact.rA); + SHVec3 velocityB = vB + SHVec3::Cross(wB, contact.rB); + SHVec3 relativeVelocity = velocityB - velocityA; + + // Solve tangent impulse + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + { + // Get scalar of relative velocity along tangent + const float VT = SHVec3::Dot(relativeVelocity, constraint.tangents[j]); + + // Compute true tangent impulse + const float MAX_TANGENT_IMPULSE = constraint.friction * contact.normalImpulse; + const float OLD_TANGENT_IMPULSE = contact.tangentImpulse[j]; + + // We cannot exceed the maximum frictional force (coulumb's law) + // Compute true tangent impulse + float newTangentImpulse = -VT * contact.tangentMass[j]; + contact.tangentImpulse[j] = std::clamp(OLD_TANGENT_IMPULSE + newTangentImpulse, -MAX_TANGENT_IMPULSE, MAX_TANGENT_IMPULSE); + newTangentImpulse = contact.tangentImpulse[j] - OLD_TANGENT_IMPULSE; + + const SHVec3 TANGENT_IMPULSE = newTangentImpulse * constraint.tangents[j]; + + // Apply impulses + vA -= TANGENT_IMPULSE * constraint.invMassA; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, TANGENT_IMPULSE); + + vB += TANGENT_IMPULSE * constraint.invMassB; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE); + } + + // Solve normal impulse + // Re-compute relative velocity + velocityA = vA + SHVec3::Cross(wA, contact.rA); + velocityB = vB + SHVec3::Cross(wB, contact.rB); + relativeVelocity = velocityB - velocityA; + + // Get scalar of relative velocity along the normal + const float VN = SHVec3::Dot(relativeVelocity, constraint.normal); + + // Compute true normal impulse + const float OLD_NORMAL_IMPULSE = contact.normalImpulse; + + float newNormalImpulse = -(VN + contact.bias) * contact.normalMass; + contact.normalImpulse = std::max(OLD_NORMAL_IMPULSE + newNormalImpulse, 0.0f); + newNormalImpulse = contact.normalImpulse - OLD_NORMAL_IMPULSE; + + const SHVec3 NORMAL_IMPULSE = newNormalImpulse * constraint.normal; + + // Apply impulses + vA -= NORMAL_IMPULSE * constraint.invMassA; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE); + + vB += NORMAL_IMPULSE * constraint.invMassB; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE); + } + + velocityStates[constraint.idA].linearVelocity = vA; + velocityStates[constraint.idA].angularVelocity = wA; + velocityStates[constraint.idB].linearVelocity = vB; + velocityStates[constraint.idB].angularVelocity = wB; + } + } + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h new file mode 100644 index 00000000..28d5de6f --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h @@ -0,0 +1,108 @@ +/**************************************************************************************** + * \file SHContactSolver.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Contact Solver that builds contacct constraints and solves + * them. + * + * \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 "Constraints/SHContactConstraint.h" +#include "SHContactManager.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates an object that builds contact constraints and solves them. + */ + class SH_API SHContactSolver + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct VelocityState + { + // Velocities + + SHVec3 linearVelocity; + SHVec3 angularVelocity; + }; + + using VelocityStates = std::unordered_map; + using ContactConstraints = std::vector; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHContactSolver () noexcept = default; + ~SHContactSolver () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const VelocityStates& GetVelocities () const noexcept; + [[nodiscard]] const ContactConstraints& GetContantConstraints () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Build a contact constraint from a new manifold. + * @param manifold + * A manifold to build a contact constraint from. + * @param rigidBodyA + * The rigid body belonging to the first collision shape. + * @param rigidBodyB + * The rigid body belonging to the second collision shape. + */ + void AddContact (const SHManifold& manifold, const SHRigidBody* rigidBodyA, const SHRigidBody* rigidBodyB) noexcept; + + void ClearContacts () noexcept; + + /** + * @brief + * Solves all the contact constraints. + * @param numIterations + * The number of times to iterate over constraints when solving them. + * @param dt + * The delta time of the simulation step. + */ + void SolveContacts (int numIterations, float dt) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr float BAUMGARTE_FACTOR = 0.2f; + static constexpr float PENETRATION_SLOP = 0.05f; + + VelocityStates velocityStates; + ContactConstraints contactConstraints; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void preSolve (float dt) noexcept; + void solve () noexcept; + + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index bb42364d..cb453d24 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -103,9 +103,33 @@ namespace SHADE /* - * TODO: Resolve Contacts + * Resolve Contacts */ + // Build constraints + for (auto& [id, manifold] : contactManager.manifolds) + { + SHRigidBody* bodyA = rigidBodies[id.GetEntityA()]; + SHRigidBody* bodyB = rigidBodies[id.GetEntityB()]; + + contactSolver.AddContact(manifold, bodyA, bodyB); + } + + // Solve contacts + contactSolver.SolveContacts(settings.numVelocitySolverIterations, dt); + + // Map velocities back to bodies + const auto& VELOCITY_STATES = contactSolver.GetVelocities(); + for (auto& [id, velocityState] : VELOCITY_STATES) + { + SHRigidBody* body = rigidBodies[id]; + body->linearVelocity = velocityState.linearVelocity; + body->angularVelocity = velocityState.angularVelocity; + } + + // Clear contacts + contactSolver.ClearContacts(); + /* * Integrate Velocities */ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index 8248299a..9bc2199e 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -15,6 +15,7 @@ // Project Headers #include "Physics/Collision/SHCollisionSpace.h" #include "SHContactManager.h" +#include "SHContactSolver.h" #include "SHRigidBody.h" @@ -46,7 +47,7 @@ namespace SHADE SHVec3 gravity = SHVec3{ 0.0f, -9.81f, 0.0f }; uint16_t numVelocitySolverIterations = 10; - uint16_t numPositionSolverIterations = 5; + uint16_t numPositionSolverIterations = 5; // Unused until PGS is implemented bool sleepingEnabled = true; }; @@ -128,6 +129,7 @@ namespace SHADE RigidBodies rigidBodies; SHContactManager contactManager; + SHContactSolver contactSolver; /*---------------------------------------------------------------------------------*/ /* Function Members */ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index aa8027c7..542b6082 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -296,7 +296,18 @@ namespace SHADE return; bodyType = newType; - invMass = newType == Type::DYNAMIC ? 1.0f : 0.0f; + + if (bodyType != Type::DYNAMIC) + { + invMass = 0.0f; + localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = 0.0f; + worldInvInertia.m[0][0] = worldInvInertia.m[1][1] = worldInvInertia.m[2][2] = 0.0f; + } + else + { + invMass = 1.0f; + localInvInertia = SHMatrix::Identity; + } } void SHRigidBody::SetGravityScale(float newGravityScale) noexcept @@ -598,6 +609,9 @@ namespace SHADE void SHRigidBody::ComputeWorldData() noexcept { + if (bodyType == Type::STATIC) + return; + const SHMatrix ROTATION = SHMatrix::Rotate(motionState.orientation); // Compute world inertia diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index ab30bbcf..606895ee 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -40,6 +40,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ friend class SHPhysicsWorld; + friend class SHContactSolver; public: /*-----------------------------------------------------------------------------------*/ -- 2.40.1 From 92ed8a29ffaa97895631f3b787df635b357073b3 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 19:04:10 +0800 Subject: [PATCH 28/84] Fixed bug with non-dynamic masses being overriden --- Assets/Scenes/PhysicsSandbox.shade | 2 +- SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp | 1 + SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 8323a26e..f2a5dd95 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -72,7 +72,7 @@ RigidBody Component: Type: Static Auto Mass: false - Mass: 1 + Mass: .inf Drag: 0.00999999978 Angular Drag: 0.00999999978 Use Gravity: false diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 542b6082..b724321b 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -319,6 +319,7 @@ namespace SHADE { if (bodyType != Type::DYNAMIC) { + invMass = 0.0f; SHLOG_WARNING("Cannot set mass of a non-Dynamic Body {}", entityID) return; } diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index 1d1c06bf..04bb5b6b 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -20,7 +20,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHRigidBodyComponent::SHRigidBodyComponent() noexcept - : type { Type::STATIC } + : type { Type::DYNAMIC } , interpolate { true } , rigidBody { nullptr } {} -- 2.40.1 From f4f6cb7eae178a333730ab6fed7f461b94c57829 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 22 Dec 2022 01:10:25 +0800 Subject: [PATCH 29/84] Fixed sequential impulses --- Assets/Scenes/PhysicsSandbox.shade | 2 +- SHADE_Engine/src/Math/Geometry/SHSphere.cpp | 2 +- .../CollisionShapes/SHCollisionShape.cpp | 7 +- .../CollisionShapes/SHCollisionShape.h | 21 ++-- .../SHSphereCollisionShape.cpp | 20 ++-- .../Physics/Collision/Contacts/SHContact.h | 2 +- .../Physics/Collision/Contacts/SHManifold.h | 7 +- .../Physics/Collision/Contacts/SHManifold.hpp | 33 ++++-- .../src/Physics/Collision/SHCollider.cpp | 2 +- .../src/Physics/Collision/SHCollider.h | 3 +- .../Constraints/SHContactConstraint.h | 7 +- .../src/Physics/Dynamics/SHContactManager.cpp | 110 ++++++++++++------ .../src/Physics/Dynamics/SHContactManager.h | 25 ++-- .../src/Physics/Dynamics/SHContactSolver.cpp | 87 +++++++------- .../src/Physics/Dynamics/SHContactSolver.h | 11 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 25 +--- 16 files changed, 201 insertions(+), 163 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index f2a5dd95..90cba8d0 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 3, z: 0} + Translate: {x: 0.186280191, y: 4.3224473, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp index 7dca00c0..7dbc8f41 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp @@ -115,7 +115,7 @@ namespace SHADE bool SHSphere::Contains(const SHSphere& rhs) const noexcept { - return BoundingSphere::Contains(rhs); + return BoundingSphere::Contains(rhs) == CONTAINS; } float SHSphere::Volume() const noexcept diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index d3f26a8b..3696dd50 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -27,7 +27,7 @@ namespace SHADE SHCollisionShape::SHCollisionShape(SHCollisionShapeID id, Type colliderType) : id { id } , flags { 0 } - , parentTransform { nullptr } + , collider { nullptr } , collisionTag { SHCollisionTagMatrix::GetTag(0) } { flags |= 1U << SHUtilities::ConvertEnum(colliderType); @@ -135,11 +135,6 @@ namespace SHADE material = newMaterial; } - void SHCollisionShape::SetParentTransform(SHTransform& parentTF) noexcept - { - parentTransform = &parentTF; - } - void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept { transform.position = posOffset; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 2cc156e1..0690b071 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -22,6 +22,12 @@ namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHRigidBody; + /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -34,10 +40,11 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCollider; - friend class SHColliderComponent; - friend class SHCollisionShapeFactory; - friend class SHCollisionSpace; + friend class SHCollider; + friend class SHColliderComponent; + friend class SHCollisionShapeFactory; + friend class SHCollisionSpace; + friend struct SHManifold; public: /*---------------------------------------------------------------------------------*/ @@ -108,8 +115,6 @@ namespace SHADE void SetDensity (float density) noexcept; void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; - void SetParentTransform (SHTransform& parentTF) noexcept; - void SetPositionOffset (const SHVec3& posOffset) noexcept; void SetRotationOffset (const SHVec3& rotOffset) noexcept; @@ -137,13 +142,13 @@ namespace SHADE SHPhysicsMaterial material; - SHTransform* parentTransform; + SHCollider* collider; // The collider it belongs to. SHTransform transform; // Needed for conversion to euler angles SHVec3 rotationOffset; - uint8_t flags; // 0 0 0 isColliding trigger capsule sphere box + uint8_t flags; // 0 0 0 isColliding trigger capsule sphere box SHCollisionTag* collisionTag; RTTR_ENABLE() diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index b1110489..30497f36 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -16,6 +16,7 @@ // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" +#include "Physics/Collision/SHCollider.h" namespace SHADE { @@ -38,7 +39,7 @@ namespace SHADE { material = rhs.material; - parentTransform = rhs.parentTransform; + collider = rhs.collider; transform = rhs.transform; rotationOffset = rhs.rotationOffset; flags = rhs.flags; @@ -54,7 +55,7 @@ namespace SHADE { material = rhs.material; - parentTransform = rhs.parentTransform; + collider = rhs.collider; transform = rhs.transform; rotationOffset = rhs.rotationOffset; flags = rhs.flags; @@ -75,7 +76,7 @@ namespace SHADE id = rhs.id; material = rhs.material; - parentTransform = rhs.parentTransform; + collider = rhs.collider; transform = rhs.transform; rotationOffset = rhs.rotationOffset; flags = rhs.flags; @@ -101,7 +102,7 @@ namespace SHADE id = rhs.id; material = rhs.material; - parentTransform = rhs.parentTransform; + collider = rhs.collider; transform = rhs.transform; rotationOffset = rhs.rotationOffset; flags = rhs.flags; @@ -179,12 +180,14 @@ namespace SHADE void SHSphereCollisionShape::ComputeTransforms() noexcept { - const float SPHERE_SCALE = std::fabs(SHMath::Max({ parentTransform->scale.x, parentTransform->scale.y, parentTransform->scale.z })); + const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); + + const float SPHERE_SCALE = std::fabs(SHMath::Max({ PARENT_TRANSFORM.scale.x, PARENT_TRANSFORM.scale.y, PARENT_TRANSFORM.scale.z })); SetScale(SPHERE_SCALE); // Recompute center - const SHQuaternion FINAL_ROT = parentTransform->orientation * transform.orientation; - const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(parentTransform->position); + 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); } @@ -212,7 +215,8 @@ namespace SHADE SHMatrix SHSphereCollisionShape::ComputeWorldTransform() const noexcept { - const SHQuaternion ROTATION = parentTransform->orientation * transform.orientation; + const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); + const SHQuaternion ROTATION = PARENT_TRANSFORM.orientation * transform.orientation; const SHVec3 SCALE{ Radius }; return SHMatrix::Transform diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h index 15c24ef2..0c137f2f 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -49,7 +49,7 @@ namespace SHADE uint8_t typeB; }; - uint32_t key = 0; + uint32_t key = std::numeric_limits::max(); }; /** diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h index c2b6ddb2..15741276 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h @@ -49,8 +49,11 @@ namespace SHADE // We only need 4 contact points to build a stable manifold. static constexpr int MAX_NUM_CONTACTS = 4; - SHCollisionShape* A; - SHCollisionShape* B; + SHCollisionShape* shapeA; + SHCollisionShape* shapeB; + + SHRigidBody* bodyA = nullptr; + SHRigidBody* bodyB = nullptr; uint32_t numContacts = 0; SHCollisionState state = SHCollisionState::INVALID; diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp index e43b9625..23be8c79 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp @@ -20,13 +20,18 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ inline SHManifold::SHManifold(SHCollisionShape* a, SHCollisionShape* b) noexcept - : A { a } - , B { b } - {} + : shapeA { a } + , shapeB { b } + { + bodyA = shapeA->collider->rigidBody; + bodyB = shapeB->collider->rigidBody; + } inline SHManifold::SHManifold(const SHManifold& rhs) noexcept - : A { rhs.A } - , B { rhs.B } + : shapeA { rhs.shapeA } + , shapeB { rhs.shapeB } + , bodyA { rhs.bodyA } + , bodyB { rhs.bodyB } , numContacts { rhs.numContacts } , state { rhs.state } , normal { rhs.normal } @@ -39,8 +44,10 @@ namespace SHADE } inline SHManifold::SHManifold(SHManifold&& rhs) noexcept - : A { rhs.A } - , B { rhs.B } + : shapeA { rhs.shapeA } + , shapeB { rhs.shapeB } + , bodyA { rhs.bodyA } + , bodyB { rhs.bodyB } , numContacts { rhs.numContacts } , state { rhs.state } , normal { rhs.normal } @@ -61,8 +68,10 @@ namespace SHADE if (this == &rhs) return *this; - A = rhs.A; - B = rhs.B; + shapeA = rhs.shapeA; + shapeB = rhs.shapeB; + bodyA = rhs.bodyA; + bodyB = rhs.bodyB; numContacts = rhs.numContacts; state = rhs.state; normal = rhs.normal; @@ -78,8 +87,10 @@ namespace SHADE inline SHManifold& SHManifold::operator=(SHManifold&& rhs) noexcept { - A = rhs.A; - B = rhs.B; + shapeA = rhs.shapeA; + shapeB = rhs.shapeB; + bodyA = rhs.bodyA; + bodyB = rhs.bodyB; numContacts = rhs.numContacts; state = rhs.state; normal = rhs.normal; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 928945c9..7d7d1a60 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -307,7 +307,7 @@ namespace SHADE SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); // Set offsets - sphere->SetParentTransform(transform); + sphere->collider = this; sphere->SetPositionOffset(posOffset); sphere->SetRotationOffset(rotOffset); diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index c31be5eb..51b33cfb 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -40,7 +40,8 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCollisionSpace; + friend class SHCollisionSpace; + friend struct SHManifold; public: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h index 55e195a6..04be00b4 100644 --- a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h +++ b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h @@ -28,10 +28,7 @@ namespace SHADE // Use the entity IDs to map resolved constraints back to the bodies - EntityID idA = MAX_EID; - EntityID idB = MAX_EID; - - uint32_t numContacts = 0; + SHCollisionKey key; // Material Data @@ -52,6 +49,8 @@ namespace SHADE SHVec3 normal; SHVec3 tangents[SHContact::NUM_TANGENTS]; SHContact contacts[SHManifold::MAX_NUM_CONTACTS]; + + uint32_t numContacts = 0; }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 3ad3c0b3..3b80b3b3 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -83,6 +83,42 @@ namespace SHADE /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHContactManager::AddTrigger(const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept + { + // If id not found, emplace new trigger. + auto trigger = triggers.find(key); + if (trigger == triggers.end()) + triggers.emplace(key, Trigger{ A, B, SHCollisionState::INVALID }); + } + + void SHContactManager::AddManifold(const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept + { + // If id not found, emplace new manifold + auto manifold = manifolds.find(key); + if (manifold == manifolds.end()) + manifolds.emplace(key, SHManifold{ A, B }); + } + + void SHContactManager::RemoveInvalidatedTrigger(EntityID eid) noexcept + { + removeInvalidObject(triggers, eid); + } + + void SHContactManager::RemoveInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) noexcept + { + removeInvalidObject(triggers, eid, shapeIndex); + } + + void SHContactManager::RemoveInvalidatedManifold(EntityID eid) noexcept + { + removeInvalidObject(manifolds, eid); + } + + void SHContactManager::RemoveInvalidatedManifold(EntityID eid, uint32_t shapeIndex) noexcept + { + removeInvalidObject(manifolds, eid, shapeIndex); + } + void SHContactManager::Update() noexcept { // Clear expired or invalid collisions. If not, test collision. @@ -92,9 +128,9 @@ namespace SHADE SHManifold& manifold = manifoldPair->second; SHManifold oldManifold = manifold; - const bool IS_COLLIDING = SHCollisionDispatcher::Collide(manifold, *manifold.A, *manifold.B); + const bool IS_COLLIDING = SHCollisionDispatcher::Collide(manifold, *manifold.shapeA, *manifold.shapeB); - auto& collisionState = oldManifold.state; + auto& collisionState = manifold.state; updateCollisionState(IS_COLLIDING, collisionState); const bool IS_INVALID = collisionState == SHCollisionState::INVALID; @@ -128,41 +164,45 @@ namespace SHADE } } - void SHContactManager::AddTrigger(const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept + void SHContactManager::SolveCollisions(int numIterations, float dt) noexcept { - // If id not found, emplace new trigger. - auto trigger = triggers.find(key); - if (trigger == triggers.end()) - triggers.emplace(key, Trigger{ A, B, SHCollisionState::INVALID }).first; + static constexpr int SIZE_CONTACTS = sizeof(SHContact) * SHManifold::MAX_NUM_CONTACTS; + + // Build constraints + for (auto& [key, manifold] : manifolds) + contactSolver.AddContact(key, manifold); + + // Solve contacts + contactSolver.SolveContacts(numIterations, dt); + + // Map impulses back to manifolds + const auto& CONTACT_CONSTRAINTS = contactSolver.GetContantConstraints(); + const auto& VELOCITY_STATES = contactSolver.GetVelocities(); + + for (auto& [key, contactConstraint] : CONTACT_CONSTRAINTS) + { + SHManifold& manifold = manifolds.find(key)->second; + + for (uint32_t i = 0; i < contactConstraint.numContacts; ++i) + manifold.contacts[i] = contactConstraint.contacts[i]; + + // Assign velocities back to the bodies + SHRigidBody* bodyA = manifold.bodyA; + SHRigidBody* bodyB = manifold.bodyB; + + const auto& STATE_A = VELOCITY_STATES.find(key.GetEntityA())->second; + const auto& STATE_B = VELOCITY_STATES.find(key.GetEntityB())->second; + + bodyA->SetLinearVelocity(STATE_A.linearVelocity); + bodyB->SetLinearVelocity(STATE_B.linearVelocity); + + bodyA->SetAngularVelocity(STATE_A.angularVelocity); + bodyB->SetAngularVelocity(STATE_B.angularVelocity); + } + + contactSolver.Reset(); } - void SHContactManager::AddManifold(const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept - { - // If id not found, emplace new manifold - auto manifold = manifolds.find(key); - if (manifold == manifolds.end()) - manifolds.emplace(key, SHManifold{ A, B }).first; - } - - void SHContactManager::RemoveInvalidatedTrigger(EntityID eid) noexcept - { - removeInvalidObject(triggers, eid); - } - - void SHContactManager::RemoveInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) noexcept - { - removeInvalidObject(triggers, eid, shapeIndex); - } - - void SHContactManager::RemoveInvalidatedManifold(EntityID eid) noexcept - { - removeInvalidObject(manifolds, eid); - } - - void SHContactManager::RemoveInvalidatedManifold(EntityID eid, uint32_t shapeIndex) noexcept - { - removeInvalidObject(manifolds, eid, shapeIndex); - } /*-----------------------------------------------------------------------------------*/ /* Private Member Functions Definitions */ @@ -191,8 +231,6 @@ namespace SHADE void SHContactManager::updateManifold(SHManifold& manifold, const SHManifold& oldManifold) noexcept { - manifold.state = oldManifold.state; - // Early out since exiting a collision does not require an update beyond updating the state if (manifold.state == SHCollisionState::EXIT) return; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h index 692dc2e8..c2433345 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -16,6 +16,7 @@ #include "Physics/Collision/Contacts/SHCollisionEvents.h" #include "Physics/Collision/Contacts/SHCollisionKey.h" #include "Physics/Collision/Contacts/SHManifold.h" +#include "SHContactSolver.h" namespace SHADE { @@ -64,14 +65,6 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Removes any invalidated contacts and triggers, then performs narrowphase collision - * detection on existing triggers and manifolds. - * @return - */ - void Update () noexcept; - void AddTrigger (const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept; void AddManifold (const SHCollisionKey& key, SHCollisionShape* A, SHCollisionShape* B) noexcept; @@ -80,6 +73,20 @@ namespace SHADE void RemoveInvalidatedManifold (EntityID eid) noexcept; void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept; + /** + * @brief + * Removes any invalidated contacts and triggers, then performs narrowphase collision + * detection on existing triggers and manifolds. + */ + void Update () noexcept; + + /** + * @brief + * Builds contact constraints and solves them. Results are stored in the corresponding + * manifolds abiding by the sequential impulse method. + */ + void SolveCollisions (int numIterations, float dt) noexcept; + private: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -103,6 +110,8 @@ namespace SHADE Manifolds manifolds; Triggers triggers; + SHContactSolver contactSolver; + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index 84805c57..c14c9eb5 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -36,40 +36,39 @@ namespace SHADE /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHContactSolver::AddContact(const SHManifold& manifold, const SHRigidBody* rigidBodyA, const SHRigidBody* rigidBodyB) noexcept + void SHContactSolver::AddContact(const SHCollisionKey& key, const SHManifold& manifold) noexcept { - SHContactConstraint& newConstraint = contactConstraints.emplace_back(SHContactConstraint{}); + SHContactConstraint& newConstraint = contactConstraints.emplace(key, SHContactConstraint{}).first->second; - const auto* SHAPE_A = manifold.A; - const auto* SHAPE_B = manifold.B; + const auto* SHAPE_A = manifold.shapeA; + const auto* SHAPE_B = manifold.shapeB; - newConstraint.idA = SHAPE_A->GetEntityID(); - newConstraint.idB = SHAPE_B->GetEntityID(); + const auto* BODY_A = manifold.bodyA; + const auto* BODY_B = manifold.bodyB; // Add velocities if it doesn't already exist - velocityStates.emplace(newConstraint.idA, VelocityState{ rigidBodyA->linearVelocity, rigidBodyB->angularVelocity }); - velocityStates.emplace(newConstraint.idB, VelocityState{ rigidBodyB->linearVelocity, rigidBodyB->angularVelocity }); + velocityStates.emplace(key.GetEntityA(), VelocityState{ BODY_A->linearVelocity, BODY_A->angularVelocity }); + velocityStates.emplace(key.GetEntityB(), VelocityState{ BODY_B->linearVelocity, BODY_B->angularVelocity }); // Mix friction & restitution - const float FRICTION_A = manifold.A->GetFriction(); - const float RESTITUTION_A = manifold.A->GetBounciness(); + const float FRICTION_A = SHAPE_A->GetFriction(); + const float RESTITUTION_A = SHAPE_A->GetBounciness(); - const float FRICTION_B = manifold.B->GetFriction(); - const float RESTITUTION_B = manifold.B->GetBounciness(); + const float FRICTION_B = SHAPE_B->GetFriction(); + const float RESTITUTION_B = SHAPE_B->GetBounciness(); - newConstraint.friction = std::sqrtf(FRICTION_A * FRICTION_B); - newConstraint.restitution = std::max(RESTITUTION_A, RESTITUTION_B); + newConstraint.friction = std::sqrtf(FRICTION_A * FRICTION_B); + newConstraint.restitution = std::max(RESTITUTION_A, RESTITUTION_B); // Mass data - newConstraint.invMassA = rigidBodyA->invMass; - newConstraint.invMassB = rigidBodyB->invMass; + newConstraint.invMassA = BODY_A->invMass; + newConstraint.invInertiaA = BODY_A->worldInvInertia; + newConstraint.centerOfMassA = BODY_A->worldCentroid; - newConstraint.invInertiaA = rigidBodyA->worldInvInertia; - newConstraint.invInertiaB = rigidBodyB->worldInvInertia; - - newConstraint.centerOfMassA = rigidBodyA->worldCentroid; - newConstraint.centerOfMassB = rigidBodyB->worldCentroid; + newConstraint.invMassB = BODY_B->invMass; + newConstraint.invInertiaB = BODY_B->worldInvInertia; + newConstraint.centerOfMassB = BODY_B->worldCentroid; // Collision data @@ -91,8 +90,9 @@ namespace SHADE } } - void SHContactSolver::ClearContacts() noexcept + void SHContactSolver::Reset() noexcept { + velocityStates.clear(); contactConstraints.clear(); } @@ -112,14 +112,14 @@ namespace SHADE { const float INV_DT = 1.0f / dt; - for (auto& constraint : contactConstraints) + for (auto& [key, constraint] : contactConstraints) { const float INV_MASS_SUM = constraint.invMassA + constraint.invMassB; - SHVec3 vA = velocityStates[constraint.idA].linearVelocity; - SHVec3 wA = velocityStates[constraint.idA].angularVelocity; - SHVec3 vB = velocityStates[constraint.idB].linearVelocity; - SHVec3 wB = velocityStates[constraint.idB].angularVelocity; + SHVec3 vA = velocityStates[key.GetEntityA()].linearVelocity; + SHVec3 wA = velocityStates[key.GetEntityA()].angularVelocity; + SHVec3 vB = velocityStates[key.GetEntityB()].linearVelocity; + SHVec3 wB = velocityStates[key.GetEntityB()].angularVelocity; for (uint32_t i = 0; i < constraint.numContacts; ++i) { @@ -156,7 +156,7 @@ namespace SHADE contact.normalMass += SHVec3::Dot(RB_CROSS_N, constraint.invInertiaB * RB_CROSS_N); // Invert the normal mass (we want the actual mass, not the inverse mass) - contact.normalMass = contact.normalMass == 0.0f ? 0.0f : 1.0f / contact.normalMass; + contact.normalMass = 1.0f / contact.normalMass; // Effective mass along tangents (same steps as above) @@ -169,7 +169,7 @@ namespace SHADE contact.tangentMass[j] += SHVec3::Dot(RA_CROSS_T, constraint.invInertiaA * RA_CROSS_T); contact.tangentMass[j] += SHVec3::Dot(RB_CROSS_T, constraint.invInertiaB * RB_CROSS_T); - contact.tangentMass[j] = contact.tangentMass[j] == 0.0f ? 0.0f : 1.0f / contact.tangentMass[j]; + contact.tangentMass[j] = 1.0f / contact.tangentMass[j]; } // Warm starting @@ -195,28 +195,27 @@ namespace SHADE const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); - const float ERROR_BIAS = BAUMGARTE_FACTOR * INV_DT * contact.penetration; + const float ERROR_BIAS = BAUMGARTE_FACTOR * INV_DT * std::min(0.0f, -contact.penetration + PENETRATION_SLOP); const float RESTITUTION_BIAS = -constraint.restitution * RV_N; contact.bias = ERROR_BIAS + RESTITUTION_BIAS; } - velocityStates[constraint.idA].linearVelocity = vA; - velocityStates[constraint.idA].angularVelocity = wA; - velocityStates[constraint.idB].linearVelocity = vB; - velocityStates[constraint.idB].angularVelocity = wB; - + velocityStates[key.GetEntityA()].linearVelocity = vA; + velocityStates[key.GetEntityA()].angularVelocity = wA; + velocityStates[key.GetEntityB()].linearVelocity = vB; + velocityStates[key.GetEntityB()].angularVelocity = wB; } } void SHContactSolver::solve() noexcept { - for (auto& constraint : contactConstraints) + for (auto& [key, constraint] : contactConstraints) { - SHVec3 vA = velocityStates[constraint.idA].linearVelocity; - SHVec3 wA = velocityStates[constraint.idA].angularVelocity; - SHVec3 vB = velocityStates[constraint.idB].linearVelocity; - SHVec3 wB = velocityStates[constraint.idB].angularVelocity; + SHVec3 vA = velocityStates[key.GetEntityA()].linearVelocity; + SHVec3 wA = velocityStates[key.GetEntityA()].angularVelocity; + SHVec3 vB = velocityStates[key.GetEntityB()].linearVelocity; + SHVec3 wB = velocityStates[key.GetEntityB()].angularVelocity; for (uint32_t i = 0; i < constraint.numContacts; ++i) { @@ -279,10 +278,10 @@ namespace SHADE wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE); } - velocityStates[constraint.idA].linearVelocity = vA; - velocityStates[constraint.idA].angularVelocity = wA; - velocityStates[constraint.idB].linearVelocity = vB; - velocityStates[constraint.idB].angularVelocity = wB; + velocityStates[key.GetEntityA()].linearVelocity = vA; + velocityStates[key.GetEntityA()].angularVelocity = wA; + velocityStates[key.GetEntityB()].linearVelocity = vB; + velocityStates[key.GetEntityB()].angularVelocity = wB; } } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h index 28d5de6f..7a4f2d47 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h @@ -13,7 +13,6 @@ // Project Headers #include "Constraints/SHContactConstraint.h" -#include "SHContactManager.h" namespace SHADE { @@ -41,7 +40,7 @@ namespace SHADE }; using VelocityStates = std::unordered_map; - using ContactConstraints = std::vector; + using ContactConstraints = std::unordered_map; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -66,14 +65,10 @@ namespace SHADE * Build a contact constraint from a new manifold. * @param manifold * A manifold to build a contact constraint from. - * @param rigidBodyA - * The rigid body belonging to the first collision shape. - * @param rigidBodyB - * The rigid body belonging to the second collision shape. */ - void AddContact (const SHManifold& manifold, const SHRigidBody* rigidBodyA, const SHRigidBody* rigidBodyB) noexcept; + void AddContact (const SHCollisionKey& key, const SHManifold& manifold) noexcept; - void ClearContacts () noexcept; + void Reset () noexcept; /** * @brief diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index cb453d24..dfa3f482 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -103,32 +103,11 @@ namespace SHADE /* + * TODO: A lot of this needs to be cleaned up. * Resolve Contacts */ - // Build constraints - for (auto& [id, manifold] : contactManager.manifolds) - { - SHRigidBody* bodyA = rigidBodies[id.GetEntityA()]; - SHRigidBody* bodyB = rigidBodies[id.GetEntityB()]; - - contactSolver.AddContact(manifold, bodyA, bodyB); - } - - // Solve contacts - contactSolver.SolveContacts(settings.numVelocitySolverIterations, dt); - - // Map velocities back to bodies - const auto& VELOCITY_STATES = contactSolver.GetVelocities(); - for (auto& [id, velocityState] : VELOCITY_STATES) - { - SHRigidBody* body = rigidBodies[id]; - body->linearVelocity = velocityState.linearVelocity; - body->angularVelocity = velocityState.angularVelocity; - } - - // Clear contacts - contactSolver.ClearContacts(); + contactManager.SolveCollisions(settings.numVelocitySolverIterations, dt); /* * Integrate Velocities -- 2.40.1 From b667e4df872316bebb69afb1a117f43e8f5db47b Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 22 Dec 2022 03:11:14 +0800 Subject: [PATCH 30/84] Implemented axis locking constraints --- Assets/Scenes/PhysicsSandbox.shade | 162 +++++++++++------- .../Dynamics/Constraints/SHVelocityState.h | 56 ++++++ .../src/Physics/Dynamics/SHContactManager.cpp | 12 +- .../src/Physics/Dynamics/SHContactSolver.cpp | 94 +++++----- .../src/Physics/Dynamics/SHContactSolver.h | 11 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 25 +-- .../src/Physics/Dynamics/SHRigidBody.cpp | 19 +- .../src/Physics/Dynamics/SHRigidBody.h | 5 +- 8 files changed, 249 insertions(+), 135 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 90cba8d0..1438b558 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.186280191, y: 4.3224473, z: 0} + Translate: {x: 0, y: 3, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -19,6 +19,107 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false + Freeze Position Y: true + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: true + Colliders: + - Is Trigger: false + Type: Sphere + Radius: 1 + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 500 +- EID: 1 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Camera Component: + Position: {x: 0, y: 0.5, z: 5} + Pitch: 0 + Yaw: 0 + Roll: 0 + Width: 1920 + Height: 1080 + Near: 0.00999999978 + Far: 10000 + Perspective: true + IsActive: true + Scripts: ~ +- EID: 2 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: -2.5, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: false + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: true + Colliders: + - Is Trigger: false + Type: Sphere + Radius: 5 + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 3 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 5, z: 0} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Dynamic + Auto Mass: false + Mass: 1 + Drag: 1 + Angular Drag: 1 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false @@ -41,61 +142,4 @@ - Type: PhysicsTestObj Enabled: true forceAmount: 50 - torqueAmount: 500 -- EID: 1 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Camera Component: - Position: {x: 0, y: 0.5, z: 3} - Pitch: 0 - Yaw: 0 - Roll: 0 - Width: 1920 - Height: 1080 - Near: 0.00999999978 - Far: 10000 - Perspective: true - IsActive: true - Scripts: ~ -- EID: 2 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - Translate: {x: 0, y: 1, z: 0} - Rotate: {x: 0, y: 0, z: 0} - Scale: {x: 1, y: 1, z: 1} - IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: false - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: false - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true - Collider Component: - DrawColliders: true - Colliders: - - Is Trigger: false - Type: Sphere - Radius: 1 - Friction: 0.400000006 - Bounciness: 0 - Density: 1 - Position Offset: {x: 0, y: 0, z: 0} - Rotation Offset: {x: 0, y: 0, z: 0} - IsActive: true - Scripts: ~ \ No newline at end of file + torqueAmount: 500 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h new file mode 100644 index 00000000..6cbb6efb --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h @@ -0,0 +1,56 @@ +/**************************************************************************************** + * \file SHVelocityState.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Velocity State for constraint solving. + * + * \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 "Physics/Dynamics/SHRigidBody.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + struct SH_API SHVelocityState + { + public: + SHVec3 LinearVelocity; + SHVec3 AngularVelocity; + + SHVec3 LinearLockFactor; + SHVec3 AngularLockFactor; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHVelocityState (const SHRigidBody* rigidBody) noexcept + { + LinearVelocity = rigidBody->GetLinearVelocity(); + AngularVelocity = rigidBody->GetAngularVelocity(); + + LinearLockFactor = SHVec3 + { + rigidBody->GetFreezePositionX() ? 0.0f : 1.0f + , rigidBody->GetFreezePositionY() ? 0.0f : 1.0f + , rigidBody->GetFreezePositionZ() ? 0.0f : 1.0f + }; + + AngularLockFactor = SHVec3 + { + rigidBody->GetFreezeRotationX() ? 0.0f : 1.0f + , rigidBody->GetFreezeRotationY() ? 0.0f : 1.0f + , rigidBody->GetFreezeRotationZ() ? 0.0f : 1.0f + }; + } + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 3b80b3b3..83047635 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -190,14 +190,14 @@ namespace SHADE SHRigidBody* bodyA = manifold.bodyA; SHRigidBody* bodyB = manifold.bodyB; - const auto& STATE_A = VELOCITY_STATES.find(key.GetEntityA())->second; - const auto& STATE_B = VELOCITY_STATES.find(key.GetEntityB())->second; + const auto& STATE_A = VELOCITY_STATES.find(key.GetEntityA())->second; + const auto& STATE_B = VELOCITY_STATES.find(key.GetEntityB())->second; - bodyA->SetLinearVelocity(STATE_A.linearVelocity); - bodyB->SetLinearVelocity(STATE_B.linearVelocity); + bodyA->SetLinearVelocity(STATE_A.LinearVelocity); + bodyB->SetLinearVelocity(STATE_B.LinearVelocity); - bodyA->SetAngularVelocity(STATE_A.angularVelocity); - bodyB->SetAngularVelocity(STATE_B.angularVelocity); + bodyA->SetAngularVelocity(STATE_A.AngularVelocity); + bodyB->SetAngularVelocity(STATE_B.AngularVelocity); } contactSolver.Reset(); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index c14c9eb5..ed4c9aa8 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -47,8 +47,8 @@ namespace SHADE const auto* BODY_B = manifold.bodyB; // Add velocities if it doesn't already exist - velocityStates.emplace(key.GetEntityA(), VelocityState{ BODY_A->linearVelocity, BODY_A->angularVelocity }); - velocityStates.emplace(key.GetEntityB(), VelocityState{ BODY_B->linearVelocity, BODY_B->angularVelocity }); + velocityStates.emplace(key.GetEntityA(), SHVelocityState{ BODY_A }); + velocityStates.emplace(key.GetEntityB(), SHVelocityState{ BODY_B }); // Mix friction & restitution const float FRICTION_A = SHAPE_A->GetFriction(); @@ -116,10 +116,18 @@ namespace SHADE { const float INV_MASS_SUM = constraint.invMassA + constraint.invMassB; - SHVec3 vA = velocityStates[key.GetEntityA()].linearVelocity; - SHVec3 wA = velocityStates[key.GetEntityA()].angularVelocity; - SHVec3 vB = velocityStates[key.GetEntityB()].linearVelocity; - SHVec3 wB = velocityStates[key.GetEntityB()].angularVelocity; + SHVelocityState& velocityStateA = velocityStates.find(key.GetEntityA())->second; + SHVelocityState& velocityStateB = velocityStates.find(key.GetEntityB())->second; + + SHVec3 vA = velocityStateA.LinearVelocity; + SHVec3 wA = velocityStateA.AngularVelocity; + SHVec3 vB = velocityStateB.LinearVelocity; + SHVec3 wB = velocityStateB.AngularVelocity; + + const SHVec3& LINEAR_LOCK_A = velocityStateA.LinearLockFactor; + const SHVec3& ANGULAR_LOCK_A = velocityStateA.AngularLockFactor; + const SHVec3& LINEAR_LOCK_B = velocityStateB.LinearLockFactor; + const SHVec3& ANGULAR_LOCK_B = velocityStateB.AngularLockFactor; for (uint32_t i = 0; i < constraint.numContacts; ++i) { @@ -172,19 +180,6 @@ namespace SHADE contact.tangentMass[j] = 1.0f / contact.tangentMass[j]; } - // Warm starting - // Compute impulses - SHVec3 impulse = constraint.normal * contact.normalImpulse; - for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) - impulse += constraint.tangents[j] * contact.tangentImpulse[j]; - - // Apply impulses onto velocities - vA -= impulse * constraint.invMassA; - wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, impulse); - - vB += impulse * constraint.invMassB; - wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse); - // Calculate bias per contact /* * error bias = baumgarte factor / dt * penetration @@ -199,12 +194,25 @@ namespace SHADE const float RESTITUTION_BIAS = -constraint.restitution * RV_N; contact.bias = ERROR_BIAS + RESTITUTION_BIAS; + + // Warm starting + // Compute impulses + SHVec3 impulse = constraint.normal * contact.normalImpulse; + for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) + impulse += constraint.tangents[j] * contact.tangentImpulse[j]; + + // Apply impulses onto velocities + vA -= impulse * constraint.invMassA * LINEAR_LOCK_A; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, impulse) * ANGULAR_LOCK_A; + + vB += impulse * constraint.invMassB * LINEAR_LOCK_B; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse) * ANGULAR_LOCK_B; } - velocityStates[key.GetEntityA()].linearVelocity = vA; - velocityStates[key.GetEntityA()].angularVelocity = wA; - velocityStates[key.GetEntityB()].linearVelocity = vB; - velocityStates[key.GetEntityB()].angularVelocity = wB; + velocityStateA.LinearVelocity = vA; + velocityStateA.AngularVelocity = wA; + velocityStateB.LinearVelocity = vB; + velocityStateB.AngularVelocity = wB; } } @@ -212,10 +220,18 @@ namespace SHADE { for (auto& [key, constraint] : contactConstraints) { - SHVec3 vA = velocityStates[key.GetEntityA()].linearVelocity; - SHVec3 wA = velocityStates[key.GetEntityA()].angularVelocity; - SHVec3 vB = velocityStates[key.GetEntityB()].linearVelocity; - SHVec3 wB = velocityStates[key.GetEntityB()].angularVelocity; + SHVelocityState& velocityStateA = velocityStates.find(key.GetEntityA())->second; + SHVelocityState& velocityStateB = velocityStates.find(key.GetEntityB())->second; + + SHVec3 vA = velocityStateA.LinearVelocity; + SHVec3 wA = velocityStateA.AngularVelocity; + SHVec3 vB = velocityStateB.LinearVelocity; + SHVec3 wB = velocityStateB.AngularVelocity; + + const SHVec3& LINEAR_LOCK_A = velocityStateA.LinearLockFactor; + const SHVec3& ANGULAR_LOCK_A = velocityStateA.AngularLockFactor; + const SHVec3& LINEAR_LOCK_B = velocityStateB.LinearLockFactor; + const SHVec3& ANGULAR_LOCK_B = velocityStateB.AngularLockFactor; for (uint32_t i = 0; i < constraint.numContacts; ++i) { @@ -245,11 +261,11 @@ namespace SHADE const SHVec3 TANGENT_IMPULSE = newTangentImpulse * constraint.tangents[j]; // Apply impulses - vA -= TANGENT_IMPULSE * constraint.invMassA; - wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, TANGENT_IMPULSE); + vA -= TANGENT_IMPULSE * constraint.invMassA * LINEAR_LOCK_A; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, TANGENT_IMPULSE) * ANGULAR_LOCK_A; - vB += TANGENT_IMPULSE * constraint.invMassB; - wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE); + vB += TANGENT_IMPULSE * constraint.invMassB * LINEAR_LOCK_B; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE) * ANGULAR_LOCK_B; } // Solve normal impulse @@ -271,17 +287,17 @@ namespace SHADE const SHVec3 NORMAL_IMPULSE = newNormalImpulse * constraint.normal; // Apply impulses - vA -= NORMAL_IMPULSE * constraint.invMassA; - wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE); + vA -= NORMAL_IMPULSE * constraint.invMassA * LINEAR_LOCK_A; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE) * ANGULAR_LOCK_A; - vB += NORMAL_IMPULSE * constraint.invMassB; - wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE); + vB += NORMAL_IMPULSE * constraint.invMassB * LINEAR_LOCK_B; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE) * ANGULAR_LOCK_B; } - velocityStates[key.GetEntityA()].linearVelocity = vA; - velocityStates[key.GetEntityA()].angularVelocity = wA; - velocityStates[key.GetEntityB()].linearVelocity = vB; - velocityStates[key.GetEntityB()].angularVelocity = wB; + velocityStateA.LinearVelocity = vA; + velocityStateA.AngularVelocity = wA; + velocityStateB.LinearVelocity = vB; + velocityStateB.AngularVelocity = wB; } } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h index 7a4f2d47..56955f74 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h @@ -13,6 +13,7 @@ // Project Headers #include "Constraints/SHContactConstraint.h" +#include "Constraints/SHVelocityState.h" namespace SHADE { @@ -31,15 +32,7 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - struct VelocityState - { - // Velocities - - SHVec3 linearVelocity; - SHVec3 angularVelocity; - }; - - using VelocityStates = std::unordered_map; + using VelocityStates = std::unordered_map; using ContactConstraints = std::unordered_map; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index dfa3f482..8451bd5b 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -143,29 +143,13 @@ namespace SHADE // Apply drag (exponentially applied) rigidBody.linearVelocity *= 1.0f / (1.0f + dt * rigidBody.linearDrag); rigidBody.angularVelocity *= 1.0f / (1.0f + dt * rigidBody.angularDrag); + + rigidBody.constrainLinearVelocities(); + rigidBody.constrainAngularVelocities(); } void SHPhysicsWorld::integrateVelocities(SHRigidBody& rigidBody, float dt) const noexcept { - static const auto ENFORCE_CONSTRAINED_VELOCITIES = [](SHRigidBody& rigidBody) - { - // Enforce linear constraints - rigidBody.linearVelocity = SHVec3 - { - rigidBody.GetFreezePositionX() ? 0.0f : rigidBody.linearVelocity.x - , rigidBody.GetFreezePositionY() ? 0.0f : rigidBody.linearVelocity.y - , rigidBody.GetFreezePositionZ() ? 0.0f : rigidBody.linearVelocity.z - }; - - // Enforce angular constraints - rigidBody.angularVelocity = SHVec3 - { - rigidBody.GetFreezeRotationX() ? 0.0f : rigidBody.angularVelocity.x - , rigidBody.GetFreezeRotationY() ? 0.0f : rigidBody.angularVelocity.y - , rigidBody.GetFreezeRotationZ() ? 0.0f : rigidBody.angularVelocity.z - }; - }; - // Always reset movement flag rigidBody.motionState.hasMoved = false; @@ -178,7 +162,8 @@ namespace SHADE // Both dynamic and kinematic can sleep when their velocities are under the thresholds. else if (!rigidBody.IsSleeping()) { - ENFORCE_CONSTRAINED_VELOCITIES(rigidBody); + rigidBody.constrainLinearVelocities(); + rigidBody.constrainAngularVelocities(); rigidBody.motionState.IntegratePosition(rigidBody.linearVelocity, dt); rigidBody.motionState.IntegrateOrientation(rigidBody.angularVelocity, dt); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index b724321b..3e24fa27 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -200,6 +200,8 @@ namespace SHADE const SHVec3& SHRigidBody::GetLinearVelocity() const noexcept { + // Check if linear velocity needs to be constrained + return linearVelocity; } @@ -378,6 +380,7 @@ namespace SHADE } linearVelocity = newLinearVelocity; + constrainLinearVelocities(); } void SHRigidBody::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept @@ -389,6 +392,7 @@ namespace SHADE } angularVelocity = newAngularVelocity; + constrainAngularVelocities(); } void SHRigidBody::SetIsActive(bool isActive) noexcept @@ -676,7 +680,20 @@ namespace SHADE const auto* FIRST_SHAPE = collider->GetCollisionShape(0); localInvInertia = SHMatrix::Inverse(FIRST_SHAPE->GetInertiaTensor(1.0f / invMass)); } - + } + + void SHRigidBody::constrainLinearVelocities() noexcept + { + linearVelocity.x = GetFreezePositionX() ? 0.0f : linearVelocity.x; + linearVelocity.y = GetFreezePositionY() ? 0.0f : linearVelocity.y; + linearVelocity.z = GetFreezePositionZ() ? 0.0f : linearVelocity.z; + } + + void SHRigidBody::constrainAngularVelocities() noexcept + { + angularVelocity.x = GetFreezeRotationX() ? 0.0f : angularVelocity.x; + angularVelocity.y = GetFreezeRotationY() ? 0.0f : angularVelocity.y; + angularVelocity.z = GetFreezeRotationZ() ? 0.0f : angularVelocity.z; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 606895ee..34424a1c 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -249,7 +249,7 @@ namespace SHADE SHVec3 linearVelocity; SHVec3 angularVelocity; - // aZ aY aX pZ pY pX 0 0 0 0 inIsland autoMass enableGravity enableSleeping sleeping active + // aZ aY aX rotLockActive pZ pY pX posLockActive 0 0 inIsland autoMass enableGravity enableSleeping sleeping active uint16_t flags; SHMotionState motionState; @@ -262,6 +262,9 @@ namespace SHADE void computeMass () noexcept; void computeInertiaTensor () noexcept; void computeMassAndInertiaTensor() noexcept; + + void constrainLinearVelocities () noexcept; + void constrainAngularVelocities () noexcept; }; -- 2.40.1 From 22c0a14081e2109de18a977382dd4412cbc38b4e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 23 Dec 2022 00:55:36 +0800 Subject: [PATCH 31/84] Renamed SHBox to SHAABB for clarity The future SHBox will represent an OBB --- .../src/Camera/SHCameraArmComponent.h | 2 +- SHADE_Engine/src/Camera/SHCameraSystem.cpp | 2 +- .../Inspector/SHEditorComponentView.hpp | 2 +- .../Math/Geometry/{SHBox.cpp => SHAABB.cpp} | 74 +++++------- .../src/Math/Geometry/{SHBox.h => SHAABB.h} | 114 ++++++++++++++---- SHADE_Engine/src/Math/Geometry/SHSphere.h | 16 +-- .../Broadphase/SHDynamicAABBTree.cpp | 38 +++--- .../Collision/Broadphase/SHDynamicAABBTree.h | 10 +- .../CollisionShapes/SHCollisionShape.h | 4 +- .../SHSphereCollisionShape.cpp | 4 +- .../CollisionShapes/SHSphereCollisionShape.h | 2 +- .../src/Serialization/SHYAMLConverters.h | 5 +- SHADE_Managed/src/Components/Collider.cxx | 20 +-- 13 files changed, 171 insertions(+), 122 deletions(-) rename SHADE_Engine/src/Math/Geometry/{SHBox.cpp => SHAABB.cpp} (71%) rename SHADE_Engine/src/Math/Geometry/{SHBox.h => SHAABB.h} (55%) diff --git a/SHADE_Engine/src/Camera/SHCameraArmComponent.h b/SHADE_Engine/src/Camera/SHCameraArmComponent.h index 9d8ec853..dfae1cd5 100644 --- a/SHADE_Engine/src/Camera/SHCameraArmComponent.h +++ b/SHADE_Engine/src/Camera/SHCameraArmComponent.h @@ -10,7 +10,7 @@ namespace SHADE { - class SHBox; + class SHAABB; class SHRay; class SH_API SHCameraArmComponent final: public SHComponent diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index d94bd3f8..af7d0f98 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -10,7 +10,7 @@ #include "Scene/SHSceneManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" -#include "Math/Geometry/SHBox.h" +#include "Math/Geometry/SHAABB.h" #include "Math/SHRay.h" #include "Physics/System/SHPhysicsSystem.h" diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 2bbc0305..622a2d37 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -346,7 +346,7 @@ namespace SHADE { //SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); // - //const auto* BOX = reinterpret_cast(collider->GetShape()); + //const auto* BOX = reinterpret_cast(collider->GetShape()); //SHEditorWidgets::DragVec3 //( // "Half Extents", { "X", "Y", "Z" }, diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp similarity index 71% rename from SHADE_Engine/src/Math/Geometry/SHBox.cpp rename to SHADE_Engine/src/Math/Geometry/SHAABB.cpp index 05595fe1..8a44457f 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHBox.h" +#include "SHAABB.h" // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHRay.h" @@ -24,14 +24,12 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHBox::SHBox() noexcept - : RelativeExtents { SHVec3::One } + SHAABB::SHAABB() noexcept { type = Type::BOX; } - SHBox::SHBox(const SHVec3& c, const SHVec3& hE) noexcept - : RelativeExtents { SHVec3::One } + SHAABB::SHAABB(const SHVec3& c, const SHVec3& hE) noexcept { type = Type::BOX; @@ -40,7 +38,7 @@ namespace SHADE } - SHBox::SHBox(const SHBox& rhs) noexcept + SHAABB::SHAABB(const SHAABB& rhs) noexcept { if (this == &rhs) return; @@ -49,23 +47,21 @@ namespace SHADE Center = rhs.Center; Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; } - SHBox::SHBox(SHBox&& rhs) noexcept + SHAABB::SHAABB(SHAABB&& rhs) noexcept { type = Type::BOX; Center = rhs.Center; Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; } /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHBox& SHBox::operator=(const SHBox& rhs) noexcept + SHAABB& SHAABB::operator=(const SHAABB& rhs) noexcept { if (rhs.type != Type::BOX) { @@ -75,13 +71,12 @@ namespace SHADE { Center = rhs.Center; Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; } return *this; } - SHBox& SHBox::operator=(SHBox&& rhs) noexcept + SHAABB& SHAABB::operator=(SHAABB&& rhs) noexcept { if (rhs.type != Type::BOX) { @@ -91,7 +86,6 @@ namespace SHADE { Center = rhs.Center; Extents = rhs.Extents; - RelativeExtents = rhs.RelativeExtents; } return *this; @@ -101,27 +95,22 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHVec3 SHBox::GetCenter() const noexcept + SHVec3 SHAABB::GetCenter() const noexcept { return Center; } - SHVec3 SHBox::GetWorldExtents() const noexcept + SHVec3 SHAABB::GetWorldExtents() const noexcept { return Extents; } - const SHVec3& SHBox::GetRelativeExtents() const noexcept - { - return RelativeExtents; - } - - SHVec3 SHBox::GetMin() const noexcept + SHVec3 SHAABB::GetMin() const noexcept { return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z }; } - SHVec3 SHBox::GetMax() const noexcept + SHVec3 SHAABB::GetMax() const noexcept { return SHVec3{ Center.x + Extents.x, Center.y + Extents.y, Center.z + Extents.z }; } @@ -130,22 +119,17 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHBox::SetCenter(const SHVec3& newCenter) noexcept + void SHAABB::SetCenter(const SHVec3& newCenter) noexcept { Center = newCenter; } - void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept + void SHAABB::SetWorldExtents(const SHVec3& newWorldExtents) noexcept { Extents = newWorldExtents; } - void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept - { - RelativeExtents = newRelativeExtents; - } - - void SHBox::SetMin(const SHVec3& min) noexcept + void SHAABB::SetMin(const SHVec3& min) noexcept { const SHVec3 MAX = GetMax(); @@ -153,7 +137,7 @@ namespace SHADE Extents = SHVec3::Abs((MAX - min) * 0.5f); } - void SHBox::SetMax(const SHVec3& max) noexcept + void SHAABB::SetMax(const SHVec3& max) noexcept { const SHVec3 MIN = GetMin(); @@ -161,13 +145,13 @@ namespace SHADE Extents = SHVec3::Abs((max - MIN) * 0.5f); } - void SHBox::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept + void SHAABB::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept { Center = SHVec3::Lerp(min, max, 0.5f); Extents = SHVec3::Abs((max - min) * 0.5f); } - std::vector SHBox::GetVertices() const noexcept + std::vector SHAABB::GetVertices() const noexcept { std::vector vertices{ 8 }; GetCorners(vertices.data()); @@ -178,12 +162,12 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHBox::TestPoint(const SHVec3& point) const noexcept + bool SHAABB::TestPoint(const SHVec3& point) const noexcept { return BoundingBox::Contains(point); } - SHRaycastResult SHBox::Raycast(const SHRay& ray) const noexcept + SHRaycastResult SHAABB::Raycast(const SHRay& ray) const noexcept { SHRaycastResult result; @@ -197,17 +181,17 @@ namespace SHADE return result; } - bool SHBox::Contains(const SHBox& rhs) const noexcept + bool SHAABB::Contains(const SHAABB& rhs) const noexcept { return BoundingBox::Contains(rhs) == CONTAINS; } - float SHBox::Volume() const noexcept + float SHAABB::Volume() const noexcept { return 8.0f * (Extents.x * Extents.y * Extents.z); } - float SHBox::SurfaceArea() const noexcept + float SHAABB::SurfaceArea() const noexcept { return 8.0f * ((Extents.x * Extents.y) + (Extents.x * Extents.z) @@ -218,21 +202,21 @@ namespace SHADE /* Static Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHBox SHBox::Combine(const SHBox& lhs, const SHBox& rhs) noexcept + SHAABB SHAABB::Combine(const SHAABB& lhs, const SHAABB& rhs) noexcept { - SHBox result; + SHAABB result; CreateMerged(result, lhs, rhs); return result; } - bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept + bool SHAABB::Intersect(const SHAABB& lhs, const SHAABB& rhs) noexcept { return lhs.Intersects(rhs); } - SHBox SHBox::BuildFromBoxes(const SHBox* boxes, size_t numBoxes) noexcept + SHAABB SHAABB::BuildFromBoxes(const SHAABB* boxes, size_t numBoxes) noexcept { - SHBox result; + SHAABB result; for (size_t i = 1; i < numBoxes; ++i) CreateMerged(result, boxes[i - 1], boxes[i]); @@ -240,9 +224,9 @@ namespace SHADE return result; } - SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept + SHAABB SHAABB::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept { - SHBox result; + SHAABB result; CreateFromPoints(result, numVertices, vertices, stride); return result; } diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHAABB.h similarity index 55% rename from SHADE_Engine/src/Math/Geometry/SHBox.h rename to SHADE_Engine/src/Math/Geometry/SHAABB.h index 63383c00..46608ded 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.h +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.h @@ -22,7 +22,7 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SH_API SHBox : public SHShape, + class SH_API SHAABB : public SHShape, private DirectX::BoundingBox { public: @@ -36,19 +36,19 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - ~SHBox () override = default; + ~SHAABB () override = default; - SHBox () noexcept; - SHBox (const SHVec3& center, const SHVec3& halfExtents) noexcept; - SHBox (const SHBox& rhs) noexcept; - SHBox (SHBox&& rhs) noexcept; + SHAABB () noexcept; + SHAABB (const SHVec3& center, const SHVec3& halfExtents) noexcept; + SHAABB (const SHAABB& rhs) noexcept; + SHAABB (SHAABB&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHBox& operator= (const SHBox& rhs) noexcept; - SHBox& operator= (SHBox&& rhs) noexcept; + SHAABB& operator= (const SHAABB& rhs) noexcept; + SHAABB& operator= (SHAABB&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -56,7 +56,6 @@ namespace SHADE [[nodiscard]] SHVec3 GetCenter () const noexcept; [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] const SHVec3& GetRelativeExtents () const noexcept; [[nodiscard]] SHVec3 GetMin () const noexcept; [[nodiscard]] SHVec3 GetMax () const noexcept; [[nodiscard]] std::vector GetVertices () const noexcept; @@ -67,7 +66,6 @@ namespace SHADE void SetCenter (const SHVec3& newCenter) noexcept; void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; - void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept; void SetMin (const SHVec3& min) noexcept; void SetMax (const SHVec3& max) noexcept; void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; @@ -76,28 +74,96 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + /** + * @brief + * Checks if a point is inside the aabb. + * @param point + * The point to check. + * @return + * True if the point is inside the aabb. + */ + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] bool Contains (const SHBox& rhs) const noexcept; - [[nodiscard]] float Volume () const noexcept; - [[nodiscard]] float SurfaceArea () const noexcept; + /** + * @brief + * Casts a ray against the aabb. + * @param ray + * The ray to cast. + * @return + * The result of the raycast.
+ * 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 aabb is contained by this aabb. + * @param rhs + * The aabb to check. + * @return + * True if the other sphere is completely contained by this aabb. + */ + [[nodiscard]] bool Contains (const SHAABB& rhs) const noexcept; + + /** + * @brief + * Calculates the volume of the aabb. + */ + [[nodiscard]] float Volume () const noexcept; + + /** + * @brief + * Calculates the surface area of the aabb. + */ + [[nodiscard]] float SurfaceArea () const noexcept; /*---------------------------------------------------------------------------------*/ /* Static Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static SHBox Combine (const SHBox& lhs, const SHBox& rhs) noexcept; - [[nodiscard]] static bool Intersect (const SHBox& lhs, const SHBox& rhs) noexcept; - [[nodiscard]] static SHBox BuildFromBoxes (const SHBox* boxes, size_t numBoxes) noexcept; - [[nodiscard]] static SHBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; + /** + * @brief + * Combines two aabbs to form a larger aabb. + * If one aabb is completely contained by the other, the result is the larger aabb. + * @return + * The combined aabb. + */ + [[nodiscard]] static SHAABB Combine (const SHAABB& lhs, const SHAABB& rhs) noexcept; - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Checks if two aabbs are intersecting. + * @return + * True if they are intersecting. + */ + [[nodiscard]] static bool Intersect (const SHAABB& lhs, const SHAABB& rhs) noexcept; - SHVec3 RelativeExtents; + /** + * @brief + * Builds a single aabb from multiple aabbs. + * @param spheres + * The set of aabbs to build from. + * @param numSpheres + * The number of aabbs in the set to build from. + * @return + * An aabb that contains all the spheres in the set. + */ + [[nodiscard]] static SHAABB BuildFromBoxes (const SHAABB* boxes, size_t numBoxes) noexcept; + + /** + * @brief + * Builds a aabb from a set of vertices. + * @param vertices + * The vertices to build a aabb 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 aabb that contains all the vertices in the set. + */ + [[nodiscard]] static SHAABB BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; }; diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.h b/SHADE_Engine/src/Math/Geometry/SHSphere.h index 91771a21..80a21aa4 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.h +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.h @@ -56,7 +56,7 @@ namespace SHADE * @return * True if the point is inside the sphere. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; /** * @brief @@ -67,7 +67,7 @@ namespace SHADE * The result of the raycast.
* See the corresponding header for the contents of the raycast result object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; /** * @brief @@ -77,19 +77,19 @@ namespace SHADE * @return * True if the other sphere is completely contained by this sphere. */ - [[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept; + [[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept; /** * @brief * Calculates the volume of the sphere. */ - [[nodiscard]] float Volume () const noexcept; + [[nodiscard]] float Volume () const noexcept; /** * @brief * Calculates the surface area of the sphere. */ - [[nodiscard]] float SurfaceArea () const noexcept; + [[nodiscard]] float SurfaceArea () const noexcept; /*---------------------------------------------------------------------------------*/ @@ -103,7 +103,7 @@ namespace SHADE * @return * The combined sphere. */ - [[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept; + [[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept; /** * @brief @@ -111,7 +111,7 @@ namespace SHADE * @return * True if they are intersecting. */ - [[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept; + [[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept; /** * @brief @@ -123,7 +123,7 @@ namespace SHADE * @return * A sphere that contains all the spheres in the set. */ - [[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept; + [[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept; /** * @brief diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index 540d5375..5fa93021 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -105,7 +105,7 @@ namespace SHADE /* Getter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - const std::vector& SHAABBTree::GetAABBs() const noexcept + const std::vector& SHAABBTree::GetAABBs() const noexcept { static AABBs aabbs; static std::stack nodeIndices; @@ -142,7 +142,7 @@ namespace SHADE /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHAABBTree::Insert(SHCollisionShapeID id, const SHBox& AABB) + void SHAABBTree::Insert(SHCollisionShapeID id, const SHAABB& AABB) { const int32_t NEW_INDEX = allocateNode(); @@ -170,7 +170,7 @@ namespace SHADE insertLeaf(NEW_INDEX); } - void SHAABBTree::Update(SHCollisionShapeID id, const SHBox& AABB) + void SHAABBTree::Update(SHCollisionShapeID id, const SHAABB& AABB) { // Get node index const int32_t INDEX_TO_UPDATE = nodeMap[id]; @@ -206,7 +206,7 @@ namespace SHADE freeNode(INDEX_TO_REMOVE); } - const std::vector& SHAABBTree::Query(SHCollisionShapeID id, const SHBox& AABB) const noexcept + const std::vector& SHAABBTree::Query(SHCollisionShapeID id, const SHAABB& AABB) const noexcept { static std::vector potentialCollisions; static std::stack nodeIndices; @@ -226,7 +226,7 @@ namespace SHADE continue; const Node& NODE = nodes[INDEX]; - if (!SHBox::Intersect(AABB, NODE.AABB)) + if (!SHAABB::Intersect(AABB, NODE.AABB)) continue; // Avoid checking against shapes of the same composite collider (and itself) @@ -328,12 +328,12 @@ namespace SHADE // Find best sibling for new leaf // Utilise Surface Area Heuristic - const SHBox& LEAF_AABB = nodes[index].AABB; + const SHAABB& LEAF_AABB = nodes[index].AABB; uint32_t searchIndex = root; while (!isLeaf(searchIndex)) { - const SHBox COMBINED_AABB = SHBox::Combine(LEAF_AABB, nodes[searchIndex].AABB); + const SHAABB COMBINED_AABB = SHAABB::Combine(LEAF_AABB, nodes[searchIndex].AABB); const float COMBINED_AREA = COMBINED_AABB.SurfaceArea(); const float INHERITED_COST = 2.0f * (COMBINED_AREA - nodes[searchIndex].AABB.SurfaceArea()); @@ -344,8 +344,8 @@ namespace SHADE float leftCost = 0.0f; float rightCost = 0.0f; - const float LEFT_COMBINED_AREA = SHBox::Combine(LEAF_AABB, nodes[LEFT_INDEX].AABB).SurfaceArea(); - const float RIGHT_COMBINED_AREA = SHBox::Combine(LEAF_AABB, nodes[RIGHT_INDEX].AABB).SurfaceArea(); + const float LEFT_COMBINED_AREA = SHAABB::Combine(LEAF_AABB, nodes[LEFT_INDEX].AABB).SurfaceArea(); + const float RIGHT_COMBINED_AREA = SHAABB::Combine(LEAF_AABB, nodes[RIGHT_INDEX].AABB).SurfaceArea(); // Compute cost for descending into the left if (isLeaf(LEFT_INDEX)) @@ -377,7 +377,7 @@ namespace SHADE Node& newParent = nodes[NEW_PARENT]; newParent.parent = OLD_PARENT; newParent.id = SHCollisionShapeID{ MAX_EID, std::numeric_limits::max() }; - newParent.AABB = SHBox::Combine(LEAF_AABB, nodes[BEST_SIBLING].AABB); + newParent.AABB = SHAABB::Combine(LEAF_AABB, nodes[BEST_SIBLING].AABB); newParent.height = nodes[BEST_SIBLING].height + 1; newParent.left = BEST_SIBLING; @@ -437,7 +437,7 @@ namespace SHADE const Node& RIGHT_NODE = nodes[RIGHT_INDEX]; nodes[index].height = 1 + SHMath::Max(LEFT_NODE.height, RIGHT_NODE.height); - nodes[index].AABB = SHBox::Combine(LEFT_NODE.AABB, RIGHT_NODE.AABB); + nodes[index].AABB = SHAABB::Combine(LEFT_NODE.AABB, RIGHT_NODE.AABB); // Sync up to the root index = nodes[index].parent; @@ -506,8 +506,8 @@ namespace SHADE nodeA.right = G; nodeG.parent = index; - nodeA.AABB = SHBox::Combine(nodeB.AABB, nodeG.AABB); - nodeC.AABB = SHBox::Combine(nodeA.AABB, nodeF.AABB); + nodeA.AABB = SHAABB::Combine(nodeB.AABB, nodeG.AABB); + nodeC.AABB = SHAABB::Combine(nodeA.AABB, nodeF.AABB); nodeA.height = 1 + SHMath::Max(nodeB.height, nodeG.height); nodeC.height = 1 + SHMath::Max(nodeA.height, nodeF.height); @@ -518,8 +518,8 @@ namespace SHADE nodeA.right = F; nodeF.parent = index; - nodeA.AABB = SHBox::Combine(nodeB.AABB, nodeF.AABB); - nodeC.AABB = SHBox::Combine(nodeA.AABB, nodeG.AABB); + nodeA.AABB = SHAABB::Combine(nodeB.AABB, nodeF.AABB); + nodeC.AABB = SHAABB::Combine(nodeA.AABB, nodeG.AABB); nodeA.height = 1 + SHMath::Max(nodeB.height, nodeF.height); nodeC.height = 1 + SHMath::Max(nodeA.height, nodeG.height); @@ -569,8 +569,8 @@ namespace SHADE nodeA.left = E; nodeE.parent = index; - nodeA.AABB = SHBox::Combine(nodeC.AABB, nodeE.AABB); - nodeB.AABB = SHBox::Combine(nodeA.AABB, nodeD.AABB); + nodeA.AABB = SHAABB::Combine(nodeC.AABB, nodeE.AABB); + nodeB.AABB = SHAABB::Combine(nodeA.AABB, nodeD.AABB); nodeA.height = 1 + SHMath::Max(nodeC.height, nodeE.height); nodeB.height = 1 + SHMath::Max(nodeA.height, nodeD.height); @@ -581,8 +581,8 @@ namespace SHADE nodeA.left = D; nodeD.parent = index; - nodeA.AABB = SHBox::Combine(nodeC.AABB, nodeD.AABB); - nodeB.AABB = SHBox::Combine(nodeA.AABB, nodeE.AABB); + nodeA.AABB = SHAABB::Combine(nodeC.AABB, nodeD.AABB); + nodeB.AABB = SHAABB::Combine(nodeA.AABB, nodeE.AABB); nodeA.height = 1 + SHMath::Max(nodeC.height, nodeD.height); nodeB.height = 1 + SHMath::Max(nodeA.height, nodeE.height); diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h index 420f30e7..32b5095a 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h @@ -32,7 +32,7 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using AABBs = std::vector; + using AABBs = std::vector; /*---------------------------------------------------------------------------------*/ /* Data Members */ @@ -67,11 +67,11 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - void Insert (SHCollisionShapeID id, const SHBox& AABB); - void Update (SHCollisionShapeID id, const SHBox& AABB); + void Insert (SHCollisionShapeID id, const SHAABB& AABB); + void Update (SHCollisionShapeID id, const SHAABB& AABB); void Remove (SHCollisionShapeID id) noexcept; - [[nodiscard]] const std::vector& Query(SHCollisionShapeID id, const SHBox& AABB) const noexcept; + [[nodiscard]] const std::vector& Query(SHCollisionShapeID id, const SHAABB& AABB) const noexcept; [[nodiscard]] const std::vector& Query(const SHRay& ray, float distance) const noexcept; private: @@ -103,7 +103,7 @@ namespace SHADE /* Data Members */ /*-------------------------------------------------------------------------------*/ - SHBox AABB; + SHAABB AABB; SHCollisionShapeID id; // Used to lookup the collision shape & entity for culling against itself union diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 0690b071..61f2b43c 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -17,7 +17,7 @@ #include "Physics/Collision/CollisionTags/SHCollisionTags.h" #include "Physics/Collision/SHPhysicsMaterial.h" #include "SHCollisionShapeID.h" -#include "Math/Geometry/SHBox.h" +#include "Math/Geometry/SHAABB.h" #include "Math/Transform/SHTransform.h" namespace SHADE @@ -131,7 +131,7 @@ namespace SHADE virtual void ComputeTransforms () noexcept = 0; [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; - [[nodiscard]] virtual SHBox ComputeAABB () const noexcept = 0; + [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index 30497f36..71d965c5 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -227,9 +227,9 @@ namespace SHADE ); } - SHBox SHSphereCollisionShape::ComputeAABB() const noexcept + SHAABB SHSphereCollisionShape::ComputeAABB() const noexcept { - return SHBox{ Center, SHVec3{ Radius } }; + return SHAABB{ Center, SHVec3{ Radius } }; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index eb41f93c..6e119cd1 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -128,7 +128,7 @@ namespace SHADE [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; - [[nodiscard]] SHBox ComputeAABB () const noexcept override; + [[nodiscard]] SHAABB ComputeAABB () const noexcept override; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index b225a9a4..59ee532a 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -132,7 +132,7 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - //const auto* BOX = reinterpret_cast(rhs.GetShape()); + //const auto* BOX = reinterpret_cast(rhs.GetShape()); //node[HalfExtents] = BOX->GetRelativeExtents(); } break; @@ -170,8 +170,7 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - //if (node[HalfExtents].IsDefined()) - // rhs.SetBoundingBox(node[HalfExtents].as()); + } break; case SHCollisionShape::Type::SPHERE: diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 1c84637a..3dd1446e 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -128,39 +128,39 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 BoxCollider::Center::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + //return Convert::ToCLI(getNativeCollisionShape().GetCenter()); return Vector3::Zero; } void BoxCollider::Center::set(Vector3 value) { - //getNativeCollisionShape().SetCenter(Convert::ToNative(value)); + //getNativeCollisionShape().SetCenter(Convert::ToNative(value)); } Vector3 BoxCollider::HalfExtents::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + //return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); return Vector3::Zero; } void BoxCollider::HalfExtents::set(Vector3 value) { - //getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); + //getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); } Vector3 BoxCollider::Min::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetMin()); + //return Convert::ToCLI(getNativeCollisionShape().GetMin()); return Vector3::Zero; } void BoxCollider::Min::set(Vector3 value) { - //getNativeCollisionShape().SetMin(Convert::ToNative(value)); + //getNativeCollisionShape().SetMin(Convert::ToNative(value)); } Vector3 BoxCollider::Max::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetMax()); + //return Convert::ToCLI(getNativeCollisionShape().GetMax()); return Vector3::Zero; } void BoxCollider::Max::set(Vector3 value) { - //getNativeCollisionShape().SetMax(Convert::ToNative(value)); + //getNativeCollisionShape().SetMax(Convert::ToNative(value)); } /*---------------------------------------------------------------------------------*/ @@ -168,12 +168,12 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool BoxCollider::TestPoint(Vector3 point) { - //return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + //return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); return false; } bool BoxCollider::Raycast(Ray ray, float maxDistance) { - //return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + //return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); return false; } -- 2.40.1 From 89f1f600640c9d7420a674b4192ae8ad950f8c58 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 24 Dec 2022 02:19:53 +0800 Subject: [PATCH 32/84] Added physics settings menu for easily toggling debug draw states --- Assets/Scenes/PhysicsSandbox.shade | 16 +++++++------- .../src/Application/SBApplication.cpp | 6 ------ .../EditorWindow/MenuBar/SHEditorMenuBar.cpp | 21 +++++++++++++++++++ .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 5 +++++ .../src/Physics/Dynamics/SHPhysicsWorld.h | 1 + .../Routines/SHPhysicsDebugDrawRoutine.cpp | 11 ++++++++-- .../System/SHPhysicsDebugDrawSystem.cpp | 16 +++++++++++--- .../Physics/System/SHPhysicsDebugDrawSystem.h | 20 ++++++++++-------- .../src/Physics/System/SHPhysicsSystem.h | 10 ++++----- 9 files changed, 73 insertions(+), 33 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 1438b558..60a97885 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 3, z: 0} + Translate: {x: 0.0700113177, y: 2.5, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -19,14 +19,14 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false Freeze Rotation Z: false IsActive: true Collider Component: - DrawColliders: true + DrawColliders: false Colliders: - Is Trigger: false Type: Sphere @@ -65,8 +65,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: -2.5, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: 0, y: 0, z: 0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: @@ -87,11 +87,11 @@ Freeze Rotation Z: false IsActive: true Collider Component: - DrawColliders: true + DrawColliders: false Colliders: - Is Trigger: false Type: Sphere - Radius: 5 + Radius: 2.5 Friction: 0.400000006 Bounciness: 0 Density: 1 @@ -127,7 +127,7 @@ Freeze Rotation Z: false IsActive: true Collider Component: - DrawColliders: true + DrawColliders: false Colliders: - Is Trigger: false Type: Sphere diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 8607702d..dfeb781b 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -185,12 +185,6 @@ 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()->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBP); - } SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, SHFrameRateController::GetRawDeltaTime()); editor->PollPicking(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index a1335e19..a08f0f75 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -25,6 +25,7 @@ #include "Serialization/SHSerialization.h" #include "Serialization/Configurations/SHConfigurationManager.h" #include "Editor/EditorWindow/SHEditorWindowManager.h" +#include "Physics/System/SHPhysicsDebugDrawSystem.h" const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" }; @@ -202,6 +203,26 @@ namespace SHADE ImGui::EndMenu(); } + if (ImGui::BeginMenu("Physics Settings")) + { + if (auto* physicsDebugDraw = SHSystemManager::GetSystem()) + { + bool drawColliders = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS); + if (ImGui::Checkbox("Draw Colliders", &drawColliders)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS, drawColliders); + + bool drawContactPoints = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS); + if (ImGui::Checkbox("Draw Contact Points", &drawContactPoints)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS, drawContactPoints); + + bool drawBroadphase = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE); + if (ImGui::Checkbox("Draw Broadphase", &drawBroadphase)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBroadphase); + } + + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 8451bd5b..4e6e8165 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -35,6 +35,11 @@ namespace SHADE /* Getter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ + const SHContactManager::ContactPoints& SHPhysicsWorld::GetContactPoints() const noexcept + { + return contactManager.GetContactPoints(); + } + const SHContactManager::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept { return contactManager.GetTriggerEvents(); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index 9bc2199e..f63bac40 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -72,6 +72,7 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + const SHContactManager::ContactPoints& GetContactPoints () const noexcept; const SHContactManager::TriggerEvents& GetTriggerEvents () const noexcept; const SHContactManager::CollisionEvents& GetCollisionEvents () const noexcept; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index 9bf43115..8aad19f5 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -38,7 +38,7 @@ namespace SHADE { auto* physicsDebugDrawSystem = reinterpret_cast(GetSystem()); - if (!physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::ACTIVE)) + if (!physicsDebugDrawSystem->IsDebugDrawActive()) return; auto* debugDrawSystem = SHSystemManager::GetSystem(); @@ -74,7 +74,14 @@ namespace SHADE if (DRAW_CONTACTS) { - // TODO + const SHColour& CONTACT_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)]; + + const auto& CONTACT_POINTS = physicsSystem->physicsWorld->GetContactPoints(); + for (auto& contactPoint : CONTACT_POINTS) + { + const SHMatrix TRS = SHMatrix::Transform(contactPoint, SHQuaternion::Identity, SHVec3{ 0.1f }); + debugDrawSystem->DrawCube(TRS, CONTACT_COLOUR); + } } if (DRAW_RAYCASTS) diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 958ac61a..9940ad20 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -44,6 +44,11 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + bool SHPhysicsDebugDrawSystem::IsDebugDrawActive() const noexcept + { + return flags & ACTIVE_FLAG; + } + bool SHPhysicsDebugDrawSystem::GetFlagState(DebugDrawFlags flag) const noexcept { const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); @@ -58,6 +63,10 @@ namespace SHADE { const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); state ? flags |= ENUM_VALUE : flags &= ~ENUM_VALUE; + + // If no other debug drawing state is active, turn active off. Otherwise, we maintain + // the active state. + flags == ACTIVE_FLAG ? flags = 0 : flags |= ACTIVE_FLAG; } /*-----------------------------------------------------------------------------------*/ @@ -97,7 +106,7 @@ namespace SHADE if (EVENT_DATA->debugDrawState) { if (collidersToDraw.empty()) - SetFlagState(DebugDrawFlags::ACTIVE, true); + flags |= ACTIVE_FLAG; collidersToDraw.emplace(EVENT_DATA->entityID); } @@ -105,8 +114,9 @@ namespace SHADE { collidersToDraw.erase(EVENT_DATA->entityID); - if (collidersToDraw.empty()) - SetFlagState(DebugDrawFlags::ACTIVE, false); + // if no colliders queued for drawing and no other debug drawing is enabled, disable debug drawing + if (collidersToDraw.empty() && flags == ACTIVE_FLAG) + flags = 0; } return onColliderDrawEvent.get()->handle; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index 79b88d3f..14f86364 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -35,11 +35,10 @@ namespace SHADE enum class DebugDrawFlags : uint8_t { - ACTIVE = 0x0001 - , COLLIDERS = 0x0002 - , CONTACTS = 0x0004 - , RAYCASTS = 0x0008 - , BROADPHASE = 0x0010 + COLLIDERS = 0x02 + , CONTACTS = 0x04 + , RAYCASTS = 0x08 + , BROADPHASE = 0x10 }; /*---------------------------------------------------------------------------------*/ @@ -53,7 +52,8 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept; + [[nodiscard]] bool IsDebugDrawActive () const noexcept; + [[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ @@ -64,10 +64,10 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - void Init () override; - void Exit () override; + void Init () override; + void Exit () override; - void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept; + void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept; /*---------------------------------------------------------------------------------*/ /* System Routines */ @@ -123,6 +123,8 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ + static constexpr uint8_t ACTIVE_FLAG = 0x01; + static const SHColour DEBUG_DRAW_COLOURS[static_cast(Colours::COUNT)]; // 0 0 0 drawBroadphase drawRaycasts drawContacts drawAllColliders debugDrawActive diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index ab28a299..c7dff6c6 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -52,8 +52,11 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] double GetFixedUpdateRate() const noexcept; - [[nodiscard]] double GetFixedDT () const noexcept; + [[nodiscard]] double GetFixedUpdateRate() const noexcept; + [[nodiscard]] double GetFixedDT () const noexcept; + + [[nodiscard]] const std::vector& GetTriggerInfo () const noexcept; + [[nodiscard]] const std::vector& GetCollisionInfo () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ @@ -62,9 +65,6 @@ namespace SHADE void SetFixedUpdateRate(double fixedUpdateRate) noexcept; void SetFixedDT(double fixedDt) noexcept; - const std::vector& GetTriggerInfo () const noexcept; - const std::vector& GetCollisionInfo () const noexcept; - /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ -- 2.40.1 From 0df6e09ed6334de0ca070b1bc24d20456e6d4ee6 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 24 Dec 2022 13:32:50 +0800 Subject: [PATCH 33/84] Added box collision shapes --- Assets/Scenes/PhysicsSandbox.shade | 5 +- .../Inspector/SHEditorComponentView.hpp | 24 +- SHADE_Engine/src/Math/Geometry/SHAABB.cpp | 20 +- SHADE_Engine/src/Math/Geometry/SHAABB.h | 22 +- SHADE_Engine/src/Math/Geometry/SHBox.cpp | 169 +++++++++++ SHADE_Engine/src/Math/Geometry/SHBox.h | 135 +++++++++ SHADE_Engine/src/Math/Geometry/SHShape.h | 7 +- SHADE_Engine/src/Math/SHQuaternion.cpp | 4 + SHADE_Engine/src/Math/SHQuaternion.h | 7 +- .../Broadphase/SHDynamicAABBTree.cpp | 9 + .../CollisionShapes/SHBoxCollisionShape.cpp | 265 ++++++++++++++++++ .../CollisionShapes/SHBoxCollisionShape.h | 158 +++++++++++ .../SHCollisionShapeFactory.cpp | 24 ++ .../CollisionShapes/SHCollisionShapeFactory.h | 21 +- .../CollisionShapes/SHSphereCollisionShape.h | 24 +- .../src/Physics/Collision/SHCollider.cpp | 54 ++++ .../src/Physics/Collision/SHCollider.h | 29 +- .../Routines/SHPhysicsDebugDrawRoutine.cpp | 2 +- .../System/SHPhysicsDebugDrawSystem.cpp | 2 +- .../src/Serialization/SHYAMLConverters.h | 10 +- SHADE_Managed/src/Components/Collider.cxx | 4 +- 21 files changed, 929 insertions(+), 66 deletions(-) create mode 100644 SHADE_Engine/src/Math/Geometry/SHBox.cpp create mode 100644 SHADE_Engine/src/Math/Geometry/SHBox.h create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 60a97885..e001867a 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -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 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 622a2d37..cf5cdeb1 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -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(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(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(shape); + auto* sphere = reinterpret_cast(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")) { diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp index 8a44457f..30683216 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp @@ -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 diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.h b/SHADE_Engine/src/Math/Geometry/SHAABB.h index 46608ded..76e0b2b7 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.h +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.h @@ -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 * @@ -54,21 +54,21 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] SHVec3 GetMin () const noexcept; - [[nodiscard]] SHVec3 GetMax () const noexcept; - [[nodiscard]] std::vector GetVertices () const noexcept; + [[nodiscard]] SHVec3 GetCenter () const noexcept; + [[nodiscard]] SHVec3 GetExtents () const noexcept; + [[nodiscard]] SHVec3 GetMin () const noexcept; + [[nodiscard]] SHVec3 GetMax () const noexcept; + [[nodiscard]] std::vector GetVertices () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCenter (const SHVec3& newCenter) noexcept; - void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; - void SetMin (const SHVec3& min) noexcept; - void SetMax (const SHVec3& max) noexcept; - void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; + void SetCenter (const SHVec3& newCenter) 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; /*---------------------------------------------------------------------------------*/ /* Function Members */ diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp new file mode 100644 index 00000000..9dacc623 --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHBox.cpp @@ -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 + +// 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 SHBox::GetVertices() const noexcept + { + std::vector 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h new file mode 100644 index 00000000..bb1098bc --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHBox.h @@ -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 + +// 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 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.
+ * 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h index 812cb169..2b644917 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -30,10 +30,9 @@ namespace SHADE enum class Type { - BOX - , SPHERE - , CAPSULE - , CONVEX_HULL + SPHERE + , AABB + , BOX , COUNT , NONE = -1 diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp index 021f0a6a..1f4645df 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.cpp +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -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 ) {} diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h index 93c546ca..3342c4cb 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.h +++ b/SHADE_Engine/src/Math/SHQuaternion.h @@ -47,9 +47,10 @@ namespace SHADE SHQuaternion (const SHQuaternion& rhs) = default; SHQuaternion (SHQuaternion&& rhs) = default; - SHQuaternion () noexcept; - SHQuaternion (const SHVec4& vec4) noexcept; - SHQuaternion (float x, float y, float z, float w) noexcept; + SHQuaternion () noexcept; + SHQuaternion (const SHVec4& vec4) noexcept; + SHQuaternion (const XMFLOAT4& xmfloat4) noexcept; + SHQuaternion (float x, float y, float z, float w) noexcept; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index 5fa93021..127494cb 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -204,6 +204,8 @@ namespace SHADE removeLeaf(INDEX_TO_REMOVE); freeNode(INDEX_TO_REMOVE); + + nodeMap.erase(id); } const std::vector& 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; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp new file mode 100644 index 00000000..67e497a8 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -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 + +// 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::max() }; + SHVec3 max{ std::numeric_limits::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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h new file mode 100644 index 00000000..35da5e6e --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h @@ -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.
+ * 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp index d6ef5f0d..97409cf0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp @@ -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()) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h index f5820317..c82d7e26 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h @@ -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. @@ -63,7 +76,7 @@ namespace SHADE * @param shape * The shape to destroy. */ - void DestroyShape (SHCollisionShape* shape); + void DestroyShape (SHCollisionShape* shape); private: /*---------------------------------------------------------------------------------*/ @@ -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; + using Boxes = std::unordered_map; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ Spheres spheres; - // TODO: Add boxes, capsules and hulls + Boxes boxes; + // TODO: Add capsules and hulls }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 6e119cd1..a1ebf6a3 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -93,7 +93,7 @@ namespace SHADE * @brief * Recomputes the transform of this sphere. */ - void ComputeTransforms () noexcept override; + void ComputeTransforms () noexcept override; /** * @brief @@ -103,7 +103,7 @@ namespace SHADE * @return * True if the point is inside the sphere. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; /** * @brief @@ -114,7 +114,7 @@ namespace SHADE * An object holding the results of the raycast.
* See the corresponding header for the contents of the object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; /** * @brief @@ -124,11 +124,23 @@ namespace SHADE * @return * The inertia tensor of the sphere. */ - [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; - [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; + /** + * @brief + * Computes the transformation matrix of the sphere. + * @return + * The transformation matrix of the sphere. + */ + [[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override; - [[nodiscard]] SHAABB ComputeAABB () 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: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 7d7d1a60..4ce819ac 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -332,6 +332,60 @@ namespace SHADE return static_cast(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(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(NEW_INDEX) + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); + + if (rigidBody) + rigidBody->ComputeMassData(); + + return static_cast(NEW_INDEX); + } + + void SHCollider::RemoveCollisionShape(int index) { if (!shapeFactory) diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 51b33cfb..3d80118e 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -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.
+ * 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.
- * 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); + 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.
+ * 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 @@ -146,13 +161,13 @@ namespace SHADE * @throws * Invalid argument for out-of-range indices. */ - void RemoveCollisionShape (int index); + void RemoveCollisionShape (int index); /** * @brief * Recomputes the transforms for all shapes in this composite collider. */ - void RecomputeShapes () noexcept; + void RecomputeShapes () noexcept; protected: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index 8aad19f5..f4a72f82 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -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); } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 9940ad20..f0add8f2 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -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: diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 59ee532a..909aa665 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -132,8 +132,8 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - //const auto* BOX = reinterpret_cast(rhs.GetShape()); - //node[HalfExtents] = BOX->GetRelativeExtents(); + const auto& BOX = dynamic_cast(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(&rhs); + box->SetRelativeExtents(node[HalfExtents].as()); + } } break; case SHCollisionShape::Type::SPHERE: diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 3dd1446e..79140d2b 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -137,12 +137,12 @@ namespace SHADE } Vector3 BoxCollider::HalfExtents::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + //return Convert::ToCLI(getNativeCollisionShape().GetExtents()); return Vector3::Zero; } void BoxCollider::HalfExtents::set(Vector3 value) { - //getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); + //getNativeCollisionShape().SetExtents(Convert::ToNative(value)); } Vector3 BoxCollider::Min::get() { -- 2.40.1 From b14ddac1e692cb5a1edf4ee80003e5794b54a3c5 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:42:10 +0800 Subject: [PATCH 34/84] Added missing serialisation for box colliders --- SHADE_Engine/src/Serialization/SHYAMLConverters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 909aa665..8584c3fe 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -249,7 +249,7 @@ namespace YAML switch (colliderType) { case SHCollisionShape::Type::SPHERE: collider->AddSphereCollisionShape(1.0f); break; - case SHCollisionShape::Type::BOX: break; + case SHCollisionShape::Type::BOX: collider->AddBoxCollisionShape(SHVec3::One); break; case SHCollisionShape::Type::CAPSULE: break; default:; } -- 2.40.1 From 8ead885d0df7d661643e186289a7bf461fad6810 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:44:08 +0800 Subject: [PATCH 35/84] Renamed CollisionShapeFactory to CollisionShapeLibrary --- .../CollisionShapes/SHBoxCollisionShape.h | 2 +- .../CollisionShapes/SHCollisionShape.h | 4 +- ...actory.cpp => SHCollisionShapeLibrary.cpp} | 47 ++++++++++++++++--- ...apeFactory.h => SHCollisionShapeLibrary.h} | 23 +++++---- .../CollisionShapes/SHSphereCollisionShape.h | 2 +- .../src/Physics/Collision/SHCollider.cpp | 40 ++++++++-------- .../src/Physics/Collision/SHCollider.h | 6 +-- .../PhysicsObject/SHPhysicsObjectManager.cpp | 6 ++- .../PhysicsObject/SHPhysicsObjectManager.h | 4 +- 9 files changed, 89 insertions(+), 45 deletions(-) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHCollisionShapeFactory.cpp => SHCollisionShapeLibrary.cpp} (71%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHCollisionShapeFactory.h => SHCollisionShapeLibrary.h} (81%) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h index 35da5e6e..0cb925f2 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h @@ -49,7 +49,7 @@ namespace SHADE friend class SHCollider; friend class SHCollision; friend class SHCompositeCollider; - friend class SHCollisionShapeFactory; + friend class SHCollisionShapeLibrary; public: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 61f2b43c..6a2e81e4 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -42,7 +42,7 @@ namespace SHADE friend class SHCollider; friend class SHColliderComponent; - friend class SHCollisionShapeFactory; + friend class SHCollisionShapeLibrary; friend class SHCollisionSpace; friend struct SHManifold; @@ -65,7 +65,7 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionShape (SHCollisionShapeID id, Type colliderType = Type::BOX); + SHCollisionShape (SHCollisionShapeID id, Type colliderType = Type::SPHERE); SHCollisionShape (const SHCollisionShape& rhs) noexcept = default; SHCollisionShape (SHCollisionShape&& rhs) noexcept = default; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp similarity index 71% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index 97409cf0..6d2fdc06 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHCollisionShapeFactory.cpp + * \file SHCollisionShapeLibrary.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Implementation for a Collison Shape Factory Class. * @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHCollisionShapeFactory.h" +#include "SHCollisionShapeLibrary.h" namespace SHADE { @@ -19,7 +19,12 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollisionShapeFactory::~SHCollisionShapeFactory() noexcept + SHCollisionShapeLibrary::SHCollisionShapeLibrary() noexcept + { + createBoxPolyhedron(); + } + + SHCollisionShapeLibrary::~SHCollisionShapeLibrary() noexcept { // Free all shapes in each container for (auto* sphereCollisionShape : spheres | std::views::values) @@ -34,7 +39,7 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHSphereCollisionShape* SHCollisionShapeFactory::CreateSphere(SHCollisionShapeID id, const SHSphereCreateInfo& createInfo) + SHSphereCollisionShape* SHCollisionShapeLibrary::CreateSphere(SHCollisionShapeID id, const SHSphereCreateInfo& createInfo) { const auto RESULT = spheres.emplace(id, new SHSphereCollisionShape{ id }); if (RESULT.second) @@ -52,7 +57,7 @@ namespace SHADE return spheres.find(id)->second; } - SHBoxCollisionShape* SHCollisionShapeFactory::CreateBox(SHCollisionShapeID id, const SHBoxCreateInfo& createInfo) + SHBoxCollisionShape* SHCollisionShapeLibrary::CreateBox(SHCollisionShapeID id, const SHBoxCreateInfo& createInfo) { const auto RESULT = boxes.emplace(id, new SHBoxCollisionShape{ id }); if (RESULT.second) @@ -72,7 +77,7 @@ namespace SHADE } - void SHCollisionShapeFactory::DestroyShape(SHCollisionShape* shape) + void SHCollisionShapeLibrary::DestroyShape(SHCollisionShape* shape) { switch (shape->GetType()) { @@ -97,4 +102,34 @@ namespace SHADE default: break; } } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollisionShapeLibrary::createBoxPolyhedron() noexcept + { + /* + * Vertices (Front/Back Face): + * + * 3/7 ---------- 2/6 + * | | + * | | + * | | + * 0/4 ---------- 1/5 + * + * Faces: + * + * Front: 0 (0,1,2,3) + * Right: 1 (1,5,6,2) + * Back: 2 (5,4,7,6) + * Left: 3 (4,0,3,7) + * Top: 4 (3,2,6,7) + * Bottom: 5 (4,5,1,0) + * + */ + + // Create face data + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h similarity index 81% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h index c82d7e26..e5958f96 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollisionShapeFactory.h + * \file SHCollisionShapeLibrary.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Collison Shape Factory Class. + * \brief Interface for a Collison Shape Library. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -24,19 +24,18 @@ namespace SHADE /** * @brief - * Encapsulates a class for Creating and Destroying Collision Shapes.
- * All memory for collision shapes are handled in this factory class.
- * TODO: Support instancing of shapes + * Encapsulates a class for Creating, Storing and Destroying Collision Shapes.
+ * All memory for collision shapes are stored in this factory class.
*/ - class SH_API SHCollisionShapeFactory final + class SH_API SHCollisionShapeLibrary final { public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionShapeFactory () noexcept = default; - ~SHCollisionShapeFactory () noexcept; + SHCollisionShapeLibrary () noexcept; + ~SHCollisionShapeLibrary () noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -92,10 +91,18 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ + + SHConvexPolyhedron boxPolyhedron; Spheres spheres; Boxes boxes; // TODO: Add capsules and hulls + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void createBoxPolyhedron() noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index a1ebf6a3..75492505 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -48,7 +48,7 @@ namespace SHADE friend class SHCollider; friend class SHCollision; friend class SHCompositeCollider; - friend class SHCollisionShapeFactory; + friend class SHCollisionShapeLibrary; public: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 4ce819ac..021605c7 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -33,7 +33,7 @@ namespace SHADE , debugDraw { false } , hasMoved { true } , rigidBody { nullptr } - , shapeFactory { nullptr } + , shapeLibrary { nullptr } , broadphase { nullptr } , transform { worldTransform } {} @@ -44,11 +44,11 @@ namespace SHADE , debugDraw { rhs.debugDraw } , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } - , shapeFactory { rhs.shapeFactory } + , shapeLibrary { rhs.shapeLibrary } , broadphase { rhs.broadphase } , transform { rhs.transform } { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) return; @@ -63,11 +63,11 @@ namespace SHADE , debugDraw { rhs.debugDraw } , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } - , shapeFactory { rhs.shapeFactory } + , shapeLibrary { rhs.shapeLibrary } , broadphase { rhs.broadphase } , transform { rhs.transform } { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) return; @@ -78,14 +78,14 @@ namespace SHADE SHCollider::~SHCollider() noexcept { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add destroy collider!", entityID) return; } for (auto* shape : shapes) - shapeFactory->DestroyShape(shape); + shapeLibrary->DestroyShape(shape); } /*-----------------------------------------------------------------------------------*/ @@ -97,7 +97,7 @@ namespace SHADE if (this == &rhs) return *this; - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) return *this; @@ -108,7 +108,7 @@ namespace SHADE debugDraw = rhs.debugDraw; hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; - shapeFactory = rhs.shapeFactory; + shapeLibrary = rhs.shapeLibrary; broadphase = rhs.broadphase; transform = rhs.transform; @@ -119,7 +119,7 @@ namespace SHADE SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) return *this; @@ -130,7 +130,7 @@ namespace SHADE debugDraw = rhs.debugDraw; hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; - shapeFactory = rhs.shapeFactory; + shapeLibrary = rhs.shapeLibrary; broadphase = rhs.broadphase; transform = rhs.transform; @@ -263,9 +263,9 @@ namespace SHADE transform.scale = newScale; } - void SHCollider::SetFactory(SHCollisionShapeFactory* factory) noexcept + void SHCollider::SetFactory(SHCollisionShapeLibrary* factory) noexcept { - shapeFactory = factory; + shapeLibrary = factory; } /*-----------------------------------------------------------------------------------*/ @@ -279,7 +279,7 @@ namespace SHADE int SHCollider::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add new shape!", entityID) return -1; @@ -304,7 +304,7 @@ namespace SHADE const uint32_t NEW_INDEX = static_cast(shapes.size()); const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + SHSphereCollisionShape* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); // Set offsets sphere->collider = this; @@ -334,7 +334,7 @@ namespace SHADE int SHCollider::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset) { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add new shape!", entityID) return -1; @@ -357,7 +357,7 @@ namespace SHADE const uint32_t NEW_INDEX = static_cast(shapes.size()); const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - SHBoxCollisionShape* box = shapeFactory->CreateBox(NEW_SHAPE_ID, BOX_CREATE_INFO); + SHBoxCollisionShape* box = shapeLibrary->CreateBox(NEW_SHAPE_ID, BOX_CREATE_INFO); // Set offsets box->collider = this; @@ -388,7 +388,7 @@ namespace SHADE void SHCollider::RemoveCollisionShape(int index) { - if (!shapeFactory) + if (!shapeLibrary) { SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add remove shape!", entityID) return; @@ -417,7 +417,7 @@ namespace SHADE if (broadphase) broadphase->Remove((*shape)->id); - shapeFactory->DestroyShape(*shape); + shapeLibrary->DestroyShape(*shape); *shape = nullptr; // Remove the shape from the container to prevent accessing a nullptr @@ -473,7 +473,7 @@ namespace SHADE const uint32_t NEW_INDEX = static_cast(shapes.size()); const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - SHSphereCollisionShape* sphere = shapeFactory->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + SHSphereCollisionShape* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); *sphere = *RHS_SPHERE; shapes.emplace_back(sphere); diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 3d80118e..c4a4ad17 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -13,7 +13,7 @@ // Project Headers #include "ECS_Base/Entity/SHEntity.h" #include "Math/Transform/SHTransform.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h" namespace SHADE { @@ -106,7 +106,7 @@ namespace SHADE void SetOrientation (const SHQuaternion& newOrientation) noexcept; void SetScale (const SHVec3& newScale) noexcept; - void SetFactory (SHCollisionShapeFactory* factory) noexcept; + void SetFactory (SHCollisionShapeLibrary* factory) noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ @@ -181,7 +181,7 @@ namespace SHADE bool hasMoved; SHRigidBody* rigidBody; - SHCollisionShapeFactory* shapeFactory; + SHCollisionShapeLibrary* shapeLibrary; SHAABBTree* broadphase; SHTransform transform; diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp index 61a77f28..81fb25e1 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp @@ -67,15 +67,17 @@ namespace SHADE auto* rigidBody = physicsObject->CreateRigidBody(RIGID_BODY_TYPE); SHVec3 worldPos = SHVec3::Zero; - // TODO: Force orientation + SHQuaternion worldRot = SHQuaternion::Identity; if (const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); TRANSFORM_COMPONENT) { worldPos = TRANSFORM_COMPONENT->GetWorldPosition(); + worldRot = TRANSFORM_COMPONENT->GetWorldOrientation(); } SHMotionState& motionState = rigidBody->GetMotionState(); motionState.ForcePosition(worldPos); + motionState.ForceOrientation(worldRot); // Link with the component rigidBodyComponent->SetRigidBody(rigidBody); @@ -115,7 +117,7 @@ namespace SHADE // Create a new composite collider in the physics object physicsObject->CreateCollider(worldTransform); - physicsObject->collider->SetFactory(&shapeFactory); + physicsObject->collider->SetFactory(&shapeLibrary); // Link with the component colliderComponent->SetCollider(physicsObject->collider); diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h index ca260a02..11818316 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h @@ -14,7 +14,7 @@ // Project Headers #include "SHPhysicsObject.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShapeFactory.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h" namespace SHADE { @@ -100,7 +100,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ EntityObjectMap physicsObjects; - SHCollisionShapeFactory shapeFactory; + SHCollisionShapeLibrary shapeLibrary; /*-----------------------------------------------------------------------------------*/ /* Member Functions */ -- 2.40.1 From ea1dd57996bf684e8d954feebb3161079a03efd2 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:45:01 +0800 Subject: [PATCH 36/84] Added stub functions for collision detection algorithms --- .../Narrowphase/SHCapsuleVsCapsule.cpp | 35 +++++++++++ .../Narrowphase/SHCapsuleVsConvex.cpp | 49 +++++++++++++++ .../Collision/Narrowphase/SHCollision.h | 47 +++++++++++++- .../Narrowphase/SHCollisionDispatch.cpp | 14 ++--- .../Narrowphase/SHConvexVsConvex.cpp | 62 +++++++++++++++++++ .../Narrowphase/SHSphereVsCapsule.cpp | 48 ++++++++++++++ .../Narrowphase/SHSphereVsConvex.cpp | 58 +++++++++++++++++ 7 files changed, 302 insertions(+), 11 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp new file mode 100644 index 00000000..c75437cb --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp @@ -0,0 +1,35 @@ +/**************************************************************************************** + * \file SHCapsuleVsCapsule.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Detecting Collisions between two capsules + * + * \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 + +// Primary Header +#include "SHCollision.h" + +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollision::CapsuleVsCapsule(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::CapsuleVsCapsule(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp new file mode 100644 index 00000000..1b03feab --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp @@ -0,0 +1,49 @@ +/**************************************************************************************** + * \file SHCapsuleVsConvex.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Detecting Collisions between a capsule and a convex + * polyhedron. + * + * \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 + +// Primary Header +#include "SHCollision.h" + +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Physics/Collision/CollisionShapes/SHBoxCollisionShape.h" + +// TODO + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollision::CapsuleVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::ConvexVsCapsule(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return CapsuleVsConvex(B, A); + } + + bool SHCollision::CapsuleVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::ConvexVsCapsule(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return CapsuleVsConvex(manifold, B, A); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index a64c101c..b99cc202 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -35,18 +35,59 @@ namespace SHADE /* Spheres VS X */ - [[nodiscard]] static bool SphereVsSphere (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; - [[nodiscard]] static bool SphereVsSphere (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; - + [[nodiscard]] static bool SphereVsSphere (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool SphereVsSphere (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + [[nodiscard]] static bool SphereVsCapsule (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool SphereVsCapsule (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + [[nodiscard]] static bool SphereVsConvex (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool SphereVsConvex (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; /* Capsule VS X */ + [[nodiscard]] static bool CapsuleVsSphere (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool CapsuleVsSphere (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + [[nodiscard]] static bool CapsuleVsCapsule (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool CapsuleVsCapsule (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + [[nodiscard]] static bool CapsuleVsConvex (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool CapsuleVsConvex (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + /* Polygon VS X */ + [[nodiscard]] static bool ConvexVsSphere (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool ConvexVsSphere (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + [[nodiscard]] static bool ConvexVsCapsule (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool ConvexVsCapsule (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + + [[nodiscard]] static bool ConvexVsConvex (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + [[nodiscard]] static bool ConvexVsConvex (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + private: /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ + static bool isMinkowskiFace(const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; + + // TODO: buildMinkowskiFace, queryEdgeDirection, distanceBetweenTwoEdges, + + /* + * TODO: + * static FaceQuery queryFaceDirections (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + * static EdgeQuery queryEdgeDirections (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; + * static bool buildMinkowskiFace (const SHHalfEdge& edgeA, const SHHalfEdge& edgeB) noexcept; + * static float distanceBetweenEdges(const SHHalfEdge& edgeA, const SHHalfEdge& edgeB, SHCollisionShape& poly) noexcept; + * static uint32_t clip + * + * ! References + * https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf + * https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp + */ + + }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp index c06e30ae..4a949d77 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp @@ -26,22 +26,20 @@ namespace SHADE const SHCollisionDispatcher::ManifoldCollide SHCollisionDispatcher::manifoldCollide[NUM_SHAPES][NUM_SHAPES] { - // TODO // vs Sphere / Box / Capsule - { SHCollision::SphereVsSphere, nullptr, nullptr } // Sphere - , { nullptr, nullptr, nullptr } // Box - , { nullptr, nullptr, nullptr } // Capsule + { SHCollision::SphereVsSphere, SHCollision::SphereVsConvex, SHCollision::SphereVsCapsule } // Sphere + , { SHCollision::ConvexVsSphere, SHCollision::ConvexVsConvex, SHCollision::ConvexVsCapsule } // Box + , { SHCollision::CapsuleVsSphere, SHCollision::CapsuleVsConvex, SHCollision::CapsuleVsCapsule } // Capsule }; const SHCollisionDispatcher::TriggerCollide SHCollisionDispatcher::triggerCollide[NUM_SHAPES][NUM_SHAPES] { - // TODO // vs Sphere / Box / Capsule - { SHCollision::SphereVsSphere, nullptr, nullptr } // Sphere - , { nullptr, nullptr, nullptr } // Box - , { nullptr, nullptr, nullptr } // Capsule + { SHCollision::SphereVsSphere, SHCollision::SphereVsConvex, SHCollision::SphereVsCapsule } // Sphere + , { SHCollision::ConvexVsSphere, SHCollision::ConvexVsConvex, SHCollision::ConvexVsCapsule } // Box + , { SHCollision::CapsuleVsSphere, SHCollision::CapsuleVsConvex, SHCollision::CapsuleVsCapsule } // Capsule }; const bool SHCollisionDispatcher::collisionTable[NUM_TYPES][NUM_TYPES] diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp new file mode 100644 index 00000000..d73097bb --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -0,0 +1,62 @@ +/**************************************************************************************** + * \file SHConvexVsConvex.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Detecting Collisions between two convex polyhedrons. + * + * \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 + +// Primary Header +#include "SHCollision.h" + +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollision::ConvexVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + /* + * TODO: + * + * 1. Query face directiosn of a to b. Exit early if separation found. + * 2. query face directions of b to a. Exit early if separation found. + * 3. Query edge directions of a & b. Exit early if separation found. + */ + + return false; + } + + bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + /* + * TODO: + * + * 1. Query face directions of a to b. Exit early if separation found. + * 2. Query face directions of b to a. Exit early if separation found. + * 3. Query edge directions of a & b. Exit early if separation found. + * + * (*)!! Apply weight to improve frame coherence of normal directions. DONT FORGET FLIP FLOP! + * 4. From above, save the axis of minimum penetration (reference face) + * 5. Find the most anti-parallel face on other shape (incident face) + * 6. Clip incident face against side planes of reference face. (Sutherland-Hodgeman Clipping). + * Keep all vertices below reference face. + * 7. Reduce manifold to 4 contact points. We only need 4 contact points for a stable manifold. + * + * Remember to save IDs in queries. + * During generation of incident face, store IDs of face. + * + */ + + return false; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp new file mode 100644 index 00000000..3e308aed --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp @@ -0,0 +1,48 @@ +/**************************************************************************************** + * \file SHSphereVsCapsule.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Detecting Collisions between a sphere and a capsule. + * + * \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 + +// Primary Header +#include "SHCollision.h" + +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" + +// TODO + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollision::SphereVsCapsule(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::CapsuleVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return SphereVsCapsule(B, A); + } + + bool SHCollision::SphereVsCapsule(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::CapsuleVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return SphereVsCapsule(manifold, B, A); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp new file mode 100644 index 00000000..a8a9cd48 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -0,0 +1,58 @@ +/**************************************************************************************** + * \file SHSphereVsConvex.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Detecting Collisions between a sphere and a convex + * polyhedron. + * + * \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 + +// Primary Header +#include "SHCollision.h" + +// Project Headers +#include "Math/SHMathHelpers.h" +#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHBoxCollisionShape.h" + +// When testing against convex polyhedrons, we do not care so much as whether it is a box +// or something else. We only need the vertices to build half edge structures for use +// with a gauss map. Regardless, we still cast it to the type just to get vertices +// since spheres and capsules do not implement the same method. + +// I did consider having another base class that encapsulates methods that convex polyhedrons +// would implement, but for the sake of my sanity, I won't do that. + +// TODO + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Public Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollision::SphereVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::ConvexVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return SphereVsConvex(B, A); + } + + bool SHCollision::SphereVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return false; + } + + bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return SphereVsConvex(manifold, B, A); + } + +} // namespace SHADE \ No newline at end of file -- 2.40.1 From 400cbb35d9b43685f02a79c651b89e4be4583f11 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:45:37 +0800 Subject: [PATCH 37/84] Partial implementation of a generic convex polyhedron object --- Assets/Scenes/PhysicsSandbox.shade | 1 + .../CollisionShapes/SHBoxCollisionShape.cpp | 18 ++ .../CollisionShapes/SHBoxCollisionShape.h | 24 +- .../CollisionShapes/SHConvexPolyhedron.cpp | 216 ++++++++++++++++++ .../CollisionShapes/SHConvexPolyhedron.h | 144 ++++++++++++ 5 files changed, 392 insertions(+), 11 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index e001867a..67d35bb5 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -131,6 +131,7 @@ Colliders: - Is Trigger: false Type: Box + Half Extents: {x: 1, y: 1, z: 1} Friction: 0.400000006 Bounciness: 0 Density: 1 diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp index 67e497a8..6d7308da 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -18,6 +18,19 @@ #include "Math/SHMatrix.h" #include "Physics/Collision/SHCollider.h" +/* + * Local box vertices, faces & half-edges + * + * Vertices (Front/Back Face): + * + * 3/7 ---------- 2/6 + * | | + * | | + * | | + * 0/4 ---------- 1/5 + * + */ + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -29,6 +42,7 @@ namespace SHADE , SHBox () , relativeExtents { SHVec3::One } , scale { SHVec3::One } + , polyhedron { nullptr } {} SHBoxCollisionShape::SHBoxCollisionShape(const SHBoxCollisionShape& rhs) noexcept @@ -36,6 +50,7 @@ namespace SHADE , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) , relativeExtents { rhs.relativeExtents } , scale { rhs.scale } + , polyhedron { rhs.polyhedron } { material = rhs.material; @@ -52,6 +67,7 @@ namespace SHADE , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) , relativeExtents { rhs.relativeExtents } , scale { rhs.scale } + , polyhedron { rhs.polyhedron } { material = rhs.material; @@ -93,6 +109,7 @@ namespace SHADE relativeExtents = rhs.relativeExtents; scale = rhs.scale; + polyhedron = rhs.polyhedron; return *this; } @@ -120,6 +137,7 @@ namespace SHADE relativeExtents = rhs.relativeExtents; scale = rhs.scale; + polyhedron = rhs.polyhedron; return *this; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h index 0cb925f2..142858e0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h @@ -13,6 +13,7 @@ // Project Headers #include "Math/Geometry/SHBox.h" #include "SHCollisionShape.h" +#include "SHConvexPolyhedron.h" namespace SHADE { @@ -73,20 +74,20 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + [[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; + 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 */ @@ -150,8 +151,9 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHVec3 relativeExtents; - SHVec3 scale; // Intended to be passed in by the base collider. + SHVec3 relativeExtents; + SHVec3 scale; // Intended to be passed in by the base collider. + SHConvexPolyhedron* polyhedron; // Defines the polyhedron by it's half edges. }; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp new file mode 100644 index 00000000..cb5fad76 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp @@ -0,0 +1,216 @@ +/**************************************************************************************** + * \file SHConvexPolyhedron.cpps + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a convex polyhedron structure. + * + * \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 + +// Primary Header +#include "SHConvexPolyhedron.h" + +// Helper Macros + +#define BUILD_UINT64_FROM_UINT32S(a, b) (uint64_t)a << 32 | b + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHConvexPolyhedron::HalfEdge::HalfEdge() noexcept + : tailVertexIndex { -1 } + , headVertexIndex { -1 } + , edgeIndex { -1 } + , twinEdgeIndex { -1 } + , faceIndex { -1 } + {} + + SHConvexPolyhedron::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept + : tailVertexIndex { rhs.tailVertexIndex } + , headVertexIndex { rhs.headVertexIndex } + , edgeIndex { rhs.edgeIndex } + , twinEdgeIndex { rhs.twinEdgeIndex } + , faceIndex { rhs.faceIndex } + {} + + SHConvexPolyhedron::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept + : tailVertexIndex { rhs.tailVertexIndex } + , headVertexIndex { rhs.headVertexIndex } + , edgeIndex { rhs.edgeIndex } + , twinEdgeIndex { rhs.twinEdgeIndex } + , faceIndex { rhs.faceIndex } + {} + + SHConvexPolyhedron::Face::Face(const Face& rhs) noexcept + : normal { rhs.normal } + { + std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); + } + + SHConvexPolyhedron::Face::Face(Face&& rhs) noexcept + : normal { rhs.normal } + { + std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::HalfEdge::operator=(const HalfEdge& rhs) noexcept + { + if (this == &rhs) + return *this; + + tailVertexIndex = rhs.tailVertexIndex; + headVertexIndex = rhs.headVertexIndex; + edgeIndex = rhs.edgeIndex ; + twinEdgeIndex = rhs.twinEdgeIndex ; + faceIndex = rhs.faceIndex ; + + return *this; + } + + SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::HalfEdge::operator=(HalfEdge&& rhs) noexcept + { + tailVertexIndex = rhs.tailVertexIndex; + headVertexIndex = rhs.headVertexIndex; + edgeIndex = rhs.edgeIndex ; + twinEdgeIndex = rhs.twinEdgeIndex ; + faceIndex = rhs.faceIndex ; + + return *this; + } + + SHConvexPolyhedron::Face& SHConvexPolyhedron::Face::operator=(const Face& rhs) noexcept + { + if (this == &rhs) + return *this; + + normal = rhs.normal; + + vertexIndices.clear(); + std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); + + return *this; + } + + SHConvexPolyhedron::Face& SHConvexPolyhedron::Face::operator=(Face&& rhs) noexcept + { + normal = rhs.normal; + + vertexIndices.clear(); + std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + int32_t SHConvexPolyhedron::GetFaceCount() const noexcept + { + return static_cast(faces.size()); + } + + int32_t SHConvexPolyhedron::GetHalfEdgeCount() const noexcept + { + return static_cast(halfEdges.size()); + } + + const SHConvexPolyhedron::Face& SHConvexPolyhedron::GetFace(int32_t index) const + { + if (index < 0 || index >= static_cast(faces.size())) + throw std::invalid_argument("Index out-of-range!"); + + return faces[index]; + } + + const SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::GetHalfEdge(int32_t index) const + { + if (index < 0 || index >= static_cast(halfEdges.size())) + throw std::invalid_argument("Index out-of-range!"); + + return halfEdges[index]; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHConvexPolyhedron::AddFace(const Face& face) + { + faces.emplace_back(face); + } + + void SHConvexPolyhedron::BuildPolyhedron() noexcept + { + // We use the pair of vertex IDs on a half-edge to prevent duplicates + std::unordered_map edgeMap; + edgeMap.clear(); + + if (faces.empty()) + { + SHLOGV_CRITICAL("Unable to build convex polyhedron, no faces have been added!") + return; + } + + // For each face, build half edges + for (size_t i = 0; i < faces.size(); ++i) + { + const Face& FACE = faces[i]; + + // Iterate through vertices and build half-edges + for (size_t j = 0; j < FACE.vertexIndices.size(); ++j) + { + const int32_t TAIL = FACE.vertexIndices[j]; + const int32_t HEAD = (TAIL + 1) > FACE.vertexIndices.back() ? FACE.vertexIndices.front() : TAIL + 1; // Wrap around + + const uint64_t NEW_EDGE_ID = BUILD_UINT64_FROM_UINT32S(TAIL, HEAD); + const uint64_t TWIN_EDGE_ID = BUILD_UINT64_FROM_UINT32S(HEAD, TAIL); + + // Check if the half-edge has already been inserted + auto newEdgeIter = edgeMap.find(NEW_EDGE_ID); + if (newEdgeIter == edgeMap.end()) + { + // Reuse the iterator for mapping with the twin + newEdgeIter = edgeMap.emplace(NEW_EDGE_ID, HalfEdge{}).first; + + HalfEdge& newHalfEdge = newEdgeIter->second; + newHalfEdge.tailVertexIndex = TAIL; + newHalfEdge.headVertexIndex = HEAD; + newHalfEdge.faceIndex = static_cast(i); + + // Set edge index of the newly inserted edge as the size of the map - 1 + // Since it is an unordered map, it will just be at the back + newHalfEdge.edgeIndex = static_cast(edgeMap.size()) - 1; + } + + // Find twin edge if one exists + auto twinEdgeIter = edgeMap.find(TWIN_EDGE_ID); + if (twinEdgeIter != edgeMap.end()) + { + // Set the twin index of both the edges + HalfEdge& newHalfEdge = newEdgeIter->second; + HalfEdge& twinHalfEdge = twinEdgeIter->second; + + newHalfEdge.twinEdgeIndex = twinHalfEdge.edgeIndex; + twinHalfEdge.twinEdgeIndex = newHalfEdge.edgeIndex; + } + } + } + + // Copy all half edges into the vector + // At this point, no duplicates should be in the map and all edges should be linked. + for (auto& halfEdge : edgeMap | std::views::values) + halfEdges.emplace_back(halfEdge); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h new file mode 100644 index 00000000..762368a3 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h @@ -0,0 +1,144 @@ +/**************************************************************************************** + * \file SHConvexPolyhedron.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a convex polyhedron structure. + * + * \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 + +// Project Headers +#include "Math/Vector/SHVec3.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates data for a convex polyhedron's geometry represented as faces & half edges. + */ + class SH_API SHConvexPolyhedron + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct HalfEdge + { + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + //Head and tail forms the edge. + //Head <----- Tail + int32_t tailVertexIndex; + + // Head is also tail of the next edge. + int32_t headVertexIndex; + + int32_t edgeIndex; + // Other half of the edge on a different face. + // Important for extrapolating face normals. + int32_t twinEdgeIndex; + + // Adjacent face of this edge. + int32_t faceIndex; + + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + HalfEdge () noexcept; + HalfEdge (const HalfEdge& rhs) noexcept; + HalfEdge (HalfEdge&& rhs) noexcept; + ~HalfEdge () noexcept = default; + + /*-------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*-------------------------------------------------------------------------------*/ + + HalfEdge& operator= (const HalfEdge& rhs) noexcept; + HalfEdge& operator= (HalfEdge&& rhs) noexcept; + }; + + struct Face + { + public: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + SHVec3 normal; + std::vector vertexIndices; // Must be in CCW order + + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + Face () noexcept = default; + Face (const Face& rhs) noexcept; + Face (Face&& rhs) noexcept; + ~Face () noexcept = default; + + /*-------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*-------------------------------------------------------------------------------*/ + + Face& operator= (const Face& rhs) noexcept; + Face& operator= (Face&& rhs) noexcept; + }; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] int32_t GetFaceCount () const noexcept; + [[nodiscard]] int32_t GetHalfEdgeCount () const noexcept; + + [[nodiscard]] const Face& GetFace (int32_t index) const; + [[nodiscard]] const HalfEdge& GetHalfEdge (int32_t index) const; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Adds a face to the polyhedron. The face must be constructed outside the polyhedron. + * @param face + * The face to insert. + */ + void AddFace (const Face& face); + + /** + * @brief + * Builds the half-edges of the polyhedron using the faces.
+ * Before this method is invoked, there must be some faces. + * @return + */ + void BuildPolyhedron() noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + float radius = 0.2f; // Default Radius is 2 cm + + // Store the faces and half-edges + + std::vector faces; + std::vector halfEdges; + + }; + +} // namespace SHADE -- 2.40.1 From fba338eaef197eb2e0abeae46de86a52cb9ed62f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 01:14:40 +0800 Subject: [PATCH 38/84] Fixed half edge builder and built box polyhedron --- .../SHCollisionShapeLibrary.cpp | 51 ++++++++++++++++--- .../CollisionShapes/SHConvexPolyhedron.cpp | 8 ++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index 6d2fdc06..ad5e3c44 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -70,6 +70,9 @@ namespace SHADE box->Orientation = createInfo.Orientation; box->scale = createInfo.Scale; + // Set convex polyhedron for the box + box->polyhedron = &boxPolyhedron; + return box; } @@ -109,6 +112,9 @@ namespace SHADE void SHCollisionShapeLibrary::createBoxPolyhedron() noexcept { + static constexpr int NUM_VERTICES_PER_FACE = 4; + static constexpr int NUM_FACES = 6; + /* * Vertices (Front/Back Face): * @@ -120,16 +126,49 @@ namespace SHADE * * Faces: * - * Front: 0 (0,1,2,3) - * Right: 1 (1,5,6,2) - * Back: 2 (5,4,7,6) - * Left: 3 (4,0,3,7) - * Top: 4 (3,2,6,7) - * Bottom: 5 (4,5,1,0) + * Front: 0 (0,1,2,3) Normal: Z + * Right: 1 (1,5,6,2) Normal: X + * Back: 2 (5,4,7,6) Normal: -Z + * Left: 3 (4,0,3,7) Normal: -X + * Top: 4 (3,2,6,7) Normal: Y + * Bottom: 5 (4,5,1,0) Normal: -Y * */ // Create face data + + const SHVec3 FACE_NORMALS[NUM_FACES] + { + -SHVec3::UnitZ + , SHVec3::UnitX + , SHVec3::UnitZ + , -SHVec3::UnitX + , SHVec3::UnitY + , -SHVec3::UnitY + }; + + const int32_t FACE_VERTICES[NUM_FACES][NUM_VERTICES_PER_FACE] + { + { 0, 1, 2, 3 } + , { 1, 5, 6, 2 } + , { 5, 4, 7, 6 } + , { 4, 0, 3, 7 } + , { 3, 2, 6, 7 } + , { 4, 5, 1, 0 } + }; + + for (int i = 0; i < NUM_FACES; ++i) + { + SHConvexPolyhedron::Face newFace; + newFace.normal = FACE_NORMALS[i]; + + for (int j = 0; j < NUM_VERTICES_PER_FACE; ++j) + newFace.vertexIndices.emplace_back(FACE_VERTICES[i][j]); + + boxPolyhedron.AddFace(newFace); + } + + boxPolyhedron.BuildPolyhedron(); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp index cb5fad76..ca049ebb 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp @@ -167,11 +167,17 @@ namespace SHADE { const Face& FACE = faces[i]; + if (FACE.vertexIndices.empty()) + { + SHLOGV_CRITICAL("Unable to build convex polyhedron, no vertices have been added to face {}!", i) + return; + } + // Iterate through vertices and build half-edges for (size_t j = 0; j < FACE.vertexIndices.size(); ++j) { const int32_t TAIL = FACE.vertexIndices[j]; - const int32_t HEAD = (TAIL + 1) > FACE.vertexIndices.back() ? FACE.vertexIndices.front() : TAIL + 1; // Wrap around + const int32_t HEAD = j + 1 < FACE.vertexIndices.size() ? FACE.vertexIndices[j + 1] : FACE.vertexIndices[0]; const uint64_t NEW_EDGE_ID = BUILD_UINT64_FROM_UINT32S(TAIL, HEAD); const uint64_t TWIN_EDGE_ID = BUILD_UINT64_FROM_UINT32S(HEAD, TAIL); -- 2.40.1 From 6bab419428fa6ef5d16c890882210156a153c21e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 01:23:14 +0800 Subject: [PATCH 39/84] Fixed collision tag bugs --- .../Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp | 2 +- .../src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp | 2 +- SHADE_Engine/src/Serialization/SHYAMLConverters.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp index 8169aa5c..9a04b812 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp @@ -1,7 +1,7 @@ #include "SHpch.h" #include "SHColliderTagPanel.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Editor/SHEditorWidgets.hpp" namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 3f7c36b7..6117dfe8 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -18,7 +18,7 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Reflection/SHReflectionMetadata.h" #include "Resource/SHResourceManager.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" namespace SHADE { template diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index ed25104a..9a76a87f 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -12,7 +12,7 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h" -#include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" namespace YAML { -- 2.40.1 From 7b1b4873ec52a986ac47440810ea169d4afb71fd Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 01:27:31 +0800 Subject: [PATCH 40/84] dumb dumb energy --- .../Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp index ca049ebb..0291de15 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp @@ -177,7 +177,7 @@ namespace SHADE for (size_t j = 0; j < FACE.vertexIndices.size(); ++j) { const int32_t TAIL = FACE.vertexIndices[j]; - const int32_t HEAD = j + 1 < FACE.vertexIndices.size() ? FACE.vertexIndices[j + 1] : FACE.vertexIndices[0]; + const int32_t HEAD = FACE.vertexIndices[(j + 1) % FACE.vertexIndices.size()]; const uint64_t NEW_EDGE_ID = BUILD_UINT64_FROM_UINT32S(TAIL, HEAD); const uint64_t TWIN_EDGE_ID = BUILD_UINT64_FROM_UINT32S(HEAD, TAIL); -- 2.40.1 From 50e3ddf0dd5d77681141a582b1a4fcf5b2549a0d Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 17:59:59 +0800 Subject: [PATCH 41/84] Fixed box inertia tensor calculation --- Assets/Scenes/PhysicsSandbox.shade | 5 ++++- .../CollisionShapes/SHBoxCollisionShape.cpp | 14 +++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 67d35bb5..4e5e40c2 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -19,7 +19,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -29,6 +29,7 @@ DrawColliders: false Colliders: - Is Trigger: false + Collision Tag: 1 Type: Sphere Radius: 1 Friction: 0.400000006 @@ -90,6 +91,7 @@ DrawColliders: false Colliders: - Is Trigger: false + Collision Tag: 1 Type: Sphere Radius: 2.5 Friction: 0.400000006 @@ -130,6 +132,7 @@ DrawColliders: false Colliders: - Is Trigger: false + Collision Tag: 1 Type: Box Half Extents: {x: 1, y: 1, z: 1} Friction: 0.400000006 diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp index 6d7308da..f94e850f 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -236,9 +236,17 @@ namespace SHADE { 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; + const float WIDTH = 2.0f * Extents.x; + const float HEIGHT = 2.0f * Extents.y; + const float DEPTH = 2.0f * Extents.z; + + const float WIDTH_SQUARED = WIDTH * WIDTH; + const float HEIGHT_SQUARED = HEIGHT * HEIGHT; + const float DEPTH_SQUARED = DEPTH * DEPTH; + + const float H2_PLUS_D2 = HEIGHT_SQUARED + DEPTH_SQUARED; + const float W2_PLUS_H2 = WIDTH_SQUARED + HEIGHT_SQUARED; + const float W2_PLUS_D2 = WIDTH_SQUARED + DEPTH_SQUARED; SHMatrix result; result.m[0][0] = ONE_OVER_TWELVE * mass * H2_PLUS_D2; -- 2.40.1 From a36d03b03bb2b1164faaa4e58efb5c60a1361d78 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 21:42:44 +0800 Subject: [PATCH 42/84] Contacts now draw normals --- SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp | 10 +++++++++- SHADE_Engine/src/Physics/Dynamics/SHContactManager.h | 8 +++++++- .../System/Routines/SHPhysicsDebugDrawRoutine.cpp | 3 ++- .../src/Physics/System/SHPhysicsDebugDrawSystem.cpp | 5 ----- .../src/Physics/System/SHPhysicsDebugDrawSystem.h | 1 - 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 83047635..c8bd2abe 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -73,7 +73,15 @@ namespace SHADE continue; for (uint32_t i = 0; i < manifold.numContacts; ++i) - contactPoints.emplace_back(manifold.contacts[i].position); + { + const ContactInfo INFO + { + .position = manifold.contacts[i].position + , .normal = manifold.normal + }; + + contactPoints.emplace_back(INFO); + } } return contactPoints; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h index c2433345..81f37146 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -42,9 +42,15 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ + struct ContactInfo + { + SHVec3 position; + SHVec3 normal; + }; + using TriggerEvents = std::vector; using CollisionEvents = std::vector; - using ContactPoints = std::vector; + using ContactPoints = std::vector; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index f4a72f82..3d1b7ba0 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -79,8 +79,9 @@ namespace SHADE const auto& CONTACT_POINTS = physicsSystem->physicsWorld->GetContactPoints(); for (auto& contactPoint : CONTACT_POINTS) { - const SHMatrix TRS = SHMatrix::Transform(contactPoint, SHQuaternion::Identity, SHVec3{ 0.1f }); + const SHMatrix TRS = SHMatrix::Transform(contactPoint.position, SHQuaternion::Identity, SHVec3{ 0.1f }); debugDrawSystem->DrawCube(TRS, CONTACT_COLOUR); + debugDrawSystem->DrawLine(contactPoint.position, contactPoint.position + contactPoint.normal * 0.3f, CONTACT_COLOUR, true); } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index f0add8f2..6d69181c 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -149,11 +149,6 @@ namespace SHADE } } - void SHPhysicsDebugDrawSystem::drawContact(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept - { - static const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)]; - } - void SHPhysicsDebugDrawSystem::drawRaycast(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept { static const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)]; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index 14f86364..3b4552a5 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -141,7 +141,6 @@ namespace SHADE SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; - static void drawContact (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Contact& contactInfo) noexcept; static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; }; -- 2.40.1 From d98d6a9e06a978150b35e20066f9075b417085b3 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 21:43:06 +0800 Subject: [PATCH 43/84] Refactored polyhedron and half-edge structures --- .../CollisionShapes/SHBoxCollisionShape.cpp | 149 +++++++++--------- .../CollisionShapes/SHBoxCollisionShape.h | 27 ++-- .../SHCollisionShapeLibrary.cpp | 20 +-- .../CollisionShapes/SHCollisionShapeLibrary.h | 6 +- .../SHConvexPolyhedronCollisionShape.cpp | 100 ++++++++++++ .../SHConvexPolyhedronCollisionShape.h | 78 +++++++++ ...HConvexPolyhedron.cpp => SHHalfEdgeDS.cpp} | 36 ++--- .../{SHConvexPolyhedron.h => SHHalfEdgeDS.h} | 8 +- .../CollisionShapes/SHSphereCollisionShape.h | 3 +- 9 files changed, 304 insertions(+), 123 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHConvexPolyhedron.cpp => SHHalfEdgeDS.cpp} (83%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHConvexPolyhedron.h => SHHalfEdgeDS.h} (97%) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp index f94e850f..7abd6067 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -18,19 +18,6 @@ #include "Math/SHMatrix.h" #include "Physics/Collision/SHCollider.h" -/* - * Local box vertices, faces & half-edges - * - * Vertices (Front/Back Face): - * - * 3/7 ---------- 2/6 - * | | - * | | - * | | - * 0/4 ---------- 1/5 - * - */ - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -38,45 +25,44 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHBoxCollisionShape::SHBoxCollisionShape(SHCollisionShapeID id) noexcept - : SHCollisionShape (id, SHCollisionShape::Type::BOX) - , SHBox () - , relativeExtents { SHVec3::One } - , scale { SHVec3::One } - , polyhedron { nullptr } + : SHConvexPolyhedronCollisionShape (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 } - , polyhedron { rhs.polyhedron } + : SHConvexPolyhedronCollisionShape (rhs.id, SHCollisionShape::Type::BOX) + , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) + , relativeExtents { rhs.relativeExtents } + , scale { rhs.scale } { + halfEdgeStructure = rhs.halfEdgeStructure; - material = rhs.material; - collider = rhs.collider; - transform = rhs.transform; - rotationOffset = rhs.rotationOffset; - flags = rhs.flags; + 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; + 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 } - , polyhedron { rhs.polyhedron } + : SHConvexPolyhedronCollisionShape (rhs.id, SHCollisionShape::Type::BOX) + , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) + , relativeExtents { rhs.relativeExtents } + , scale { rhs.scale } { + halfEdgeStructure = rhs.halfEdgeStructure; - material = rhs.material; - collider = rhs.collider; - transform = rhs.transform; - rotationOffset = rhs.rotationOffset; - flags = rhs.flags; + 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; + collisionTag = rhs.collisionTag; } /*-----------------------------------------------------------------------------------*/ @@ -90,26 +76,26 @@ namespace SHADE // Collision Shape Properties - id = rhs.id; - material = rhs.material; - collider = rhs.collider; - transform = rhs.transform; - rotationOffset = rhs.rotationOffset; - flags = rhs.flags; + 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; + collisionTag = rhs.collisionTag; // Box Properties - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; // Local Properties - relativeExtents = rhs.relativeExtents; - scale = rhs.scale; - polyhedron = rhs.polyhedron; + relativeExtents = rhs.relativeExtents; + scale = rhs.scale; + halfEdgeStructure = rhs.halfEdgeStructure; return *this; } @@ -118,26 +104,26 @@ namespace SHADE { // Collision Shape Properties - id = rhs.id; - material = rhs.material; - collider = rhs.collider; - transform = rhs.transform; - rotationOffset = rhs.rotationOffset; - flags = rhs.flags; + 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; + collisionTag = rhs.collisionTag; // Box Properties - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; // Local Properties - relativeExtents = rhs.relativeExtents; - scale = rhs.scale; - polyhedron = rhs.polyhedron; + relativeExtents = rhs.relativeExtents; + scale = rhs.scale; + halfEdgeStructure = rhs.halfEdgeStructure; return *this; } @@ -166,6 +152,28 @@ namespace SHADE return Orientation; } + SHVec3 SHBoxCollisionShape::GetVertex(int index) const + { + static constexpr int NUM_VERTICES = 8; + + if (index < 0 || index >= NUM_VERTICES) + throw std::invalid_argument("Index out-of-range!"); + + // DirectX already puts vertex 0 - 4 on the front face for our case. + // Otherwise, it would need to be wrapped around for the correct vertex. + return GetVertices()[index]; + } + + SHVec3 SHBoxCollisionShape::GetNormal(int faceIndex) const + { + // Get local normal + const SHVec3& LOCAL_NORMAL = halfEdgeStructure->GetFace(faceIndex).normal; + + // Rotate normal into world space + return SHVec3::Rotate(LOCAL_NORMAL, Orientation); + + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -191,12 +199,6 @@ namespace SHADE 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); @@ -219,7 +221,8 @@ namespace SHADE 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); + Orientation = FINAL_ROT; + Center = SHVec3::Transform(transform.position, TRS); } bool SHBoxCollisionShape::TestPoint(const SHVec3& point) const noexcept diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h index 142858e0..f34870f5 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h @@ -12,8 +12,7 @@ // Project Headers #include "Math/Geometry/SHBox.h" -#include "SHCollisionShape.h" -#include "SHConvexPolyhedron.h" +#include "SHConvexPolyhedronCollisionShape.h" namespace SHADE { @@ -37,9 +36,9 @@ namespace SHADE /** * @brief - * Encapsulate a Box Collision Shape used for Physics Simulations. + * Encapsulate a Box Shape used for Physics Simulations. */ - class SH_API SHBoxCollisionShape final : public SHCollisionShape + class SH_API SHBoxCollisionShape final : public SHConvexPolyhedronCollisionShape , private SHBox { private: @@ -49,7 +48,6 @@ namespace SHADE friend class SHCollider; friend class SHCollision; - friend class SHCompositeCollider; friend class SHCollisionShapeLibrary; public: @@ -57,7 +55,7 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHBoxCollisionShape (SHCollisionShapeID id) noexcept; + SHBoxCollisionShape (SHCollisionShapeID id) noexcept; SHBoxCollisionShape (const SHBoxCollisionShape& rhs) noexcept; SHBoxCollisionShape (SHBoxCollisionShape&& rhs) noexcept; @@ -74,10 +72,13 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + [[nodiscard]] SHVec3 GetCenter () const noexcept; + [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; + [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + + [[nodiscard]] SHVec3 GetVertex (int index) const override; + [[nodiscard]] SHVec3 GetNormal (int faceIndex) const override; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ @@ -86,7 +87,6 @@ namespace SHADE 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; /*---------------------------------------------------------------------------------*/ @@ -151,9 +151,8 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHVec3 relativeExtents; - SHVec3 scale; // Intended to be passed in by the base collider. - SHConvexPolyhedron* polyhedron; // Defines the polyhedron by it's half edges. + SHVec3 relativeExtents; + SHVec3 scale; // Intended to be passed in by the base collider. }; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index ad5e3c44..e9832f9c 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -64,14 +64,14 @@ namespace SHADE { 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; + box->Center = createInfo.Center; + box->Extents = createInfo.Extents; + box->relativeExtents = createInfo.RelativeExtents; + box->Orientation = createInfo.Orientation; + box->scale = createInfo.Scale; - // Set convex polyhedron for the box - box->polyhedron = &boxPolyhedron; + // Set halfEdge data structure for the box + box->halfEdgeStructure = &boxHalfEdgeDS; return box; } @@ -159,16 +159,16 @@ namespace SHADE for (int i = 0; i < NUM_FACES; ++i) { - SHConvexPolyhedron::Face newFace; + SHHalfEdgeDS::Face newFace; newFace.normal = FACE_NORMALS[i]; for (int j = 0; j < NUM_VERTICES_PER_FACE; ++j) newFace.vertexIndices.emplace_back(FACE_VERTICES[i][j]); - boxPolyhedron.AddFace(newFace); + boxHalfEdgeDS.AddFace(newFace); } - boxPolyhedron.BuildPolyhedron(); + boxHalfEdgeDS.BuildPolyhedron(); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h index e5958f96..b20abb7f 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h @@ -92,10 +92,10 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHConvexPolyhedron boxPolyhedron; + SHHalfEdgeDS boxHalfEdgeDS; - Spheres spheres; - Boxes boxes; + Spheres spheres; + Boxes boxes; // TODO: Add capsules and hulls /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp new file mode 100644 index 00000000..586d67f4 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp @@ -0,0 +1,100 @@ +/**************************************************************************************** + * \file SHConvexPolyhedronCollisionShape.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a convex polyhedron 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 + +// Primary Header +#include "SHConvexPolyhedronCollisionShape.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHConvexPolyhedronCollisionShape::SHConvexPolyhedronCollisionShape(SHCollisionShapeID id,Type polyhedronType) noexcept + : SHCollisionShape (id, polyhedronType) + , halfEdgeStructure { nullptr } + {} + + SHConvexPolyhedronCollisionShape::SHConvexPolyhedronCollisionShape(const SHConvexPolyhedronCollisionShape& rhs) noexcept + : SHCollisionShape (rhs.id, rhs.GetType()) + , halfEdgeStructure { nullptr } + { + 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; + } + + SHConvexPolyhedronCollisionShape::SHConvexPolyhedronCollisionShape(SHConvexPolyhedronCollisionShape&& rhs) noexcept + : SHCollisionShape (rhs.id, rhs.GetType()) + , halfEdgeStructure { nullptr } + { + 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 */ + /*-----------------------------------------------------------------------------------*/ + + SHConvexPolyhedronCollisionShape& SHConvexPolyhedronCollisionShape::operator=(const SHConvexPolyhedronCollisionShape& rhs) noexcept + { + if (this == &rhs) + return *this; + + 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; + + // Local Properties + halfEdgeStructure = rhs.halfEdgeStructure; + + return *this; + } + + SHConvexPolyhedronCollisionShape& SHConvexPolyhedronCollisionShape::operator=(SHConvexPolyhedronCollisionShape&& rhs) noexcept + { + 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; + + // Local Properties + halfEdgeStructure = rhs.halfEdgeStructure; + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHHalfEdgeDS* SHConvexPolyhedronCollisionShape::GetHalfEdgeStructure() const noexcept + { + return halfEdgeStructure; + } +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h new file mode 100644 index 00000000..6748793c --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h @@ -0,0 +1,78 @@ +/**************************************************************************************** + * \file SHConvexPolyhedronCollisionShape.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a convex polyhedron 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 "SHCollisionShape.h" +#include "SHHalfEdgeDS.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a convex polyhedron shape used for Physics Simulations.. + */ + class SH_API SHConvexPolyhedronCollisionShape : public SHCollisionShape + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHCollider; + friend class SHCollision; + friend class SHCollisionShapeLibrary; + + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr float RADIUS = 0.1f; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHConvexPolyhedronCollisionShape (SHCollisionShapeID id, Type polyhedronType) noexcept; + SHConvexPolyhedronCollisionShape (const SHConvexPolyhedronCollisionShape& rhs) noexcept; + SHConvexPolyhedronCollisionShape (SHConvexPolyhedronCollisionShape&& rhs) noexcept; + + ~SHConvexPolyhedronCollisionShape () override = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHConvexPolyhedronCollisionShape& operator=(const SHConvexPolyhedronCollisionShape& rhs) noexcept; + SHConvexPolyhedronCollisionShape& operator=(SHConvexPolyhedronCollisionShape&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const SHHalfEdgeDS* GetHalfEdgeStructure () const noexcept; + [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; + [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; + + protected: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHHalfEdgeDS* halfEdgeStructure; // Defines the polyhedron by it's half edges. + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.cpp similarity index 83% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.cpp index 0291de15..3bf48608 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHConvexPolyhedron.cpps + * \file SHHalfEdgeDS.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a convex polyhedron structure. + * \brief Implementation for a half-edge data structure to represent polyhedra. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHConvexPolyhedron.h" +#include "SHHalfEdgeDS.h" // Helper Macros @@ -23,7 +23,7 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHConvexPolyhedron::HalfEdge::HalfEdge() noexcept + SHHalfEdgeDS::HalfEdge::HalfEdge() noexcept : tailVertexIndex { -1 } , headVertexIndex { -1 } , edgeIndex { -1 } @@ -31,7 +31,7 @@ namespace SHADE , faceIndex { -1 } {} - SHConvexPolyhedron::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept + SHHalfEdgeDS::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept : tailVertexIndex { rhs.tailVertexIndex } , headVertexIndex { rhs.headVertexIndex } , edgeIndex { rhs.edgeIndex } @@ -39,7 +39,7 @@ namespace SHADE , faceIndex { rhs.faceIndex } {} - SHConvexPolyhedron::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept + SHHalfEdgeDS::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept : tailVertexIndex { rhs.tailVertexIndex } , headVertexIndex { rhs.headVertexIndex } , edgeIndex { rhs.edgeIndex } @@ -47,13 +47,13 @@ namespace SHADE , faceIndex { rhs.faceIndex } {} - SHConvexPolyhedron::Face::Face(const Face& rhs) noexcept + SHHalfEdgeDS::Face::Face(const Face& rhs) noexcept : normal { rhs.normal } { std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); } - SHConvexPolyhedron::Face::Face(Face&& rhs) noexcept + SHHalfEdgeDS::Face::Face(Face&& rhs) noexcept : normal { rhs.normal } { std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); @@ -63,7 +63,7 @@ namespace SHADE /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::HalfEdge::operator=(const HalfEdge& rhs) noexcept + SHHalfEdgeDS::HalfEdge& SHHalfEdgeDS::HalfEdge::operator=(const HalfEdge& rhs) noexcept { if (this == &rhs) return *this; @@ -77,7 +77,7 @@ namespace SHADE return *this; } - SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::HalfEdge::operator=(HalfEdge&& rhs) noexcept + SHHalfEdgeDS::HalfEdge& SHHalfEdgeDS::HalfEdge::operator=(HalfEdge&& rhs) noexcept { tailVertexIndex = rhs.tailVertexIndex; headVertexIndex = rhs.headVertexIndex; @@ -88,7 +88,7 @@ namespace SHADE return *this; } - SHConvexPolyhedron::Face& SHConvexPolyhedron::Face::operator=(const Face& rhs) noexcept + SHHalfEdgeDS::Face& SHHalfEdgeDS::Face::operator=(const Face& rhs) noexcept { if (this == &rhs) return *this; @@ -101,7 +101,7 @@ namespace SHADE return *this; } - SHConvexPolyhedron::Face& SHConvexPolyhedron::Face::operator=(Face&& rhs) noexcept + SHHalfEdgeDS::Face& SHHalfEdgeDS::Face::operator=(Face&& rhs) noexcept { normal = rhs.normal; @@ -115,17 +115,17 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - int32_t SHConvexPolyhedron::GetFaceCount() const noexcept + int32_t SHHalfEdgeDS::GetFaceCount() const noexcept { return static_cast(faces.size()); } - int32_t SHConvexPolyhedron::GetHalfEdgeCount() const noexcept + int32_t SHHalfEdgeDS::GetHalfEdgeCount() const noexcept { return static_cast(halfEdges.size()); } - const SHConvexPolyhedron::Face& SHConvexPolyhedron::GetFace(int32_t index) const + const SHHalfEdgeDS::Face& SHHalfEdgeDS::GetFace(int32_t index) const { if (index < 0 || index >= static_cast(faces.size())) throw std::invalid_argument("Index out-of-range!"); @@ -133,7 +133,7 @@ namespace SHADE return faces[index]; } - const SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::GetHalfEdge(int32_t index) const + const SHHalfEdgeDS::HalfEdge& SHHalfEdgeDS::GetHalfEdge(int32_t index) const { if (index < 0 || index >= static_cast(halfEdges.size())) throw std::invalid_argument("Index out-of-range!"); @@ -145,12 +145,12 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHConvexPolyhedron::AddFace(const Face& face) + void SHHalfEdgeDS::AddFace(const Face& face) { faces.emplace_back(face); } - void SHConvexPolyhedron::BuildPolyhedron() noexcept + void SHHalfEdgeDS::BuildPolyhedron() noexcept { // We use the pair of vertex IDs on a half-edge to prevent duplicates std::unordered_map edgeMap; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.h similarity index 97% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.h index 762368a3..272d893c 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHConvexPolyhedron.h + * \file SHHalfEdgeDS.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a convex polyhedron structure. + * \brief Interface for a half-edge data structure to represent polyhedra. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -25,7 +25,7 @@ namespace SHADE * @brief * Encapsulates data for a convex polyhedron's geometry represented as faces & half edges. */ - class SH_API SHConvexPolyhedron + class SH_API SHHalfEdgeDS { public: /*---------------------------------------------------------------------------------*/ @@ -77,6 +77,8 @@ namespace SHADE /* Data Members */ /*-------------------------------------------------------------------------------*/ + // TODO: Store face offset + SHVec3 normal; std::vector vertexIndices; // Must be in CCW order diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 75492505..54e04fe6 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -35,7 +35,7 @@ namespace SHADE /** * @brief - * Encapsulate a Sphere Collision Shape used for Physics Simulations. + * Encapsulate a Sphere Shape used for Physics Simulations. */ class SH_API SHSphereCollisionShape final : public SHCollisionShape , private SHSphere @@ -47,7 +47,6 @@ namespace SHADE friend class SHCollider; friend class SHCollision; - friend class SHCompositeCollider; friend class SHCollisionShapeLibrary; public: -- 2.40.1 From 3586c7ffdc675f7d5a244fc6716948fc729929ad Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 21:43:22 +0800 Subject: [PATCH 44/84] Added mostly working sphere vs convex polyhedron collision detection --- Assets/Scenes/PhysicsSandbox.shade | 20 +-- .../Narrowphase/SHSphereVsConvex.cpp | 170 ++++++++++++++++++ .../Narrowphase/SHSphereVsSphere.cpp | 10 +- 3 files changed, 185 insertions(+), 15 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 4e5e40c2..cd74173e 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,7 +4,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.0700113177, y: 2.5, z: 0} + Translate: {x: 0, y: 2.5, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -30,8 +30,8 @@ Colliders: - Is Trigger: false Collision Tag: 1 - Type: Sphere - Radius: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} Friction: 0.400000006 Bounciness: 0 Density: 1 @@ -49,9 +49,9 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 0.5, z: 5} + Position: {x: 3, y: 4, z: 0} Pitch: 0 - Yaw: 0 + Yaw: 90 Roll: 0 Width: 1920 Height: 1080 @@ -107,8 +107,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 5, z: 0} - Rotate: {x: -0, y: 0, z: 0} + Translate: {x: 0, y: 5, z: 0.834425449} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: @@ -122,7 +122,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -133,8 +133,8 @@ Colliders: - Is Trigger: false Collision Tag: 1 - Type: Box - Half Extents: {x: 1, y: 1, z: 1} + Type: Sphere + Radius: 1 Friction: 0.400000006 Bounciness: 0 Density: 1 diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index a8a9cd48..8f12475a 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -47,6 +47,176 @@ namespace SHADE bool SHCollision::SphereVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { + // Convert to underlying types + // For the convex, we only need the convex polyhedron shape since the get vertex is pure virtual. + const SHSphereCollisionShape& SPHERE = dynamic_cast(A); + const SHConvexPolyhedronCollisionShape& CONVEX = dynamic_cast(B); + + // Ensure a gap between A & B + const float TOTAL_RADIUS = SPHERE.GetWorldRadius() + CONVEX.RADIUS; + + // Find closest face of polygon to circle + + int32_t closestFaceIndex = -1; + int32_t closestPointIndex = -1; + float bestDistance = std::numeric_limits::lowest(); + + const SHHalfEdgeDS* HALF_EDGE_STRUCTURE = CONVEX.GetHalfEdgeStructure(); + + /* + * Test against each face + * + * TODO: + * This check is now O(n^2) because we find the closest point. + * It can be optimised to O(n) by utilising the following steps: + * 1. Rotate sphere into polyhedron's space + * 2. Build a plane equation from the face in point-normal form. We need the plane's offset from the origin. + * 3. Compute distance to the face. + */ + for (int32_t i = 0; i < HALF_EDGE_STRUCTURE->GetFaceCount(); ++i) + { + const SHHalfEdgeDS::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(i); + + // TODO: Remove and optimise + // Find the closest point on the face to the sphere + const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); + for (int32_t j = 0; j < NUM_VERTICES; ++j) + { + // Get vector from center to a vertex on the face + const SHVec3 A_TO_B = SPHERE.GetCenter() - CONVEX.GetVertex(FACE.vertexIndices[j]); + + const float PROJECTION = SHVec3::Dot(A_TO_B, FACE.normal); + + // Early out + if (PROJECTION > TOTAL_RADIUS) + return false; + + if (PROJECTION > bestDistance) + { + bestDistance = PROJECTION; + closestFaceIndex = i; + closestPointIndex = j; + } + } + } + + uint32_t numContacts = 0; + const float penetration = TOTAL_RADIUS - bestDistance; + + // Rotate the normal into the world space + const SHVec3& BEST_NORMAL = CONVEX.GetNormal(closestFaceIndex); + + // Check if center is inside polyhedron (below the face) + if (bestDistance < SHMath::EPSILON) + { + SHContact newContact; + newContact.penetration = penetration; + newContact.position = SPHERE.GetCenter(); + newContact.featurePair.key = 0; + + manifold.contacts[numContacts++] = newContact; + manifold.normal = BEST_NORMAL; + + manifold.numContacts = numContacts; + return true; + } + + // Check against voronoi regions of the face to determine the type of the intersection test + // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center + // If none of these are true, the sphere is above the face but not separating + + const SHHalfEdgeDS::Face& CLOSEST_FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); + const int32_t NUM_VERTICES_ON_FACE = static_cast(CLOSEST_FACE.vertexIndices.size()); + + const SHVec3& CLOSEST_POINT = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[closestPointIndex]); + const SHVec3 CP_TO_CENTER = SPHERE.GetCenter() - CLOSEST_POINT; + + // Check closest point -> prev point + { + const int32_t PREV_POINT_INDEX = closestPointIndex == 0 ? NUM_VERTICES_ON_FACE - 1 : closestPointIndex - 1; + const SHVec3& PREV_POINT = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[PREV_POINT_INDEX]); + + const SHVec3 CP_TO_PREV = SHVec3::Normalise(PREV_POINT - CLOSEST_POINT); + + float projection = SHVec3::Dot(CP_TO_CENTER, CP_TO_PREV); + if (projection >= 0.0f) + { + // Sphere is inside this region, check if distance from center is lesser than radius + if (penetration >= TOTAL_RADIUS) + return false; + + SHContact newContact; + newContact.penetration = penetration; + newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; + newContact.featurePair.key = 0; + + manifold.contacts[numContacts++] = newContact; + manifold.normal = BEST_NORMAL; + + manifold.numContacts = numContacts; + return true; + } + } + + // Check closest point -> next point + { + const int32_t NEXT_POINT_INDEX = closestPointIndex + 1 % NUM_VERTICES_ON_FACE; + const SHVec3& NEXT_POINT = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[NEXT_POINT_INDEX]); + + const SHVec3 CP_TO_NEXT = SHVec3::Normalise(NEXT_POINT - CLOSEST_POINT); + + float projection = SHVec3::Dot(CP_TO_CENTER, CP_TO_NEXT); + if (projection >= 0.0f) + { + // Sphere is inside this region, check if distance from center is lesser than radius + if (penetration >= TOTAL_RADIUS) + return false; + + SHContact newContact; + newContact.penetration = penetration; + newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; + newContact.featurePair.key = 0; + + manifold.contacts[numContacts++] = newContact; + manifold.normal = BEST_NORMAL; + + manifold.numContacts = numContacts; + return true; + } + } + + // Check if it hit the closest point + { + if (CP_TO_CENTER.LengthSquared() < TOTAL_RADIUS * TOTAL_RADIUS) + { + SHContact newContact; + newContact.penetration = penetration; + newContact.position = CLOSEST_POINT; + newContact.featurePair.key = 0; + + manifold.contacts[numContacts++] = newContact; + manifold.normal = SHVec3::Normalise(CP_TO_CENTER); + + manifold.numContacts = numContacts; + return true; + } + } + + // It is above the closest face + if (penetration <= TOTAL_RADIUS) + { + SHContact newContact; + newContact.penetration = penetration; + newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; + newContact.featurePair.key = 0; + + manifold.contacts[numContacts++] = newContact; + manifold.normal = BEST_NORMAL; + + manifold.numContacts = numContacts; + return true; + } + return false; } diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp index 8b529241..07b6c9a6 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp @@ -25,17 +25,17 @@ namespace SHADE bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - const SHSphereCollisionShape& SPHERE_A = reinterpret_cast(A); - const SHSphereCollisionShape& SPHERE_B = reinterpret_cast(B); + const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); + const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); return SHSphere::Intersect(SPHERE_A, SPHERE_B); } bool SHCollision::SphereVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - // Convert to spheres - const SHSphereCollisionShape& SPHERE_A = reinterpret_cast(A); - const SHSphereCollisionShape& SPHERE_B = reinterpret_cast(B); + // Convert to underlying types + const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); + const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); const SHVec3 A_TO_B = SPHERE_B.GetCenter() - SPHERE_A.GetCenter(); const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared(); -- 2.40.1 From 82d46fce9962d6e2e0b5610014376f296c6c3a4a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 23:53:45 +0800 Subject: [PATCH 45/84] Fixed voronoi region tests for sphere vs convex polyhedron --- Assets/Scenes/PhysicsSandbox.shade | 28 ++-- .../CollisionShapes/SHBoxCollisionShape.cpp | 2 - .../Narrowphase/SHSphereVsConvex.cpp | 121 +++++++++--------- .../Routines/SHPhysicsDebugDrawRoutine.cpp | 2 +- 4 files changed, 77 insertions(+), 76 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index cd74173e..7360d543 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,22 +4,22 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 2.5, z: 0} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 1, y: 1, z: 1} + Translate: {x: -1.80977702, y: 3, z: 0} + Rotate: {x: -0, y: 0, z: -0.506194055} + Scale: {x: 3.27252102, y: 0.999997199, z: 1} IsActive: true RigidBody Component: - Type: Dynamic + Type: Static Auto Mass: false - Mass: 10 - Drag: 1 - Angular Drag: 1 + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 Use Gravity: true Gravity Scale: 1 Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -49,9 +49,9 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 3, y: 4, z: 0} + Position: {x: 0, y: 4, z: 5} Pitch: 0 - Yaw: 90 + Yaw: 0 Roll: 0 Width: 1920 Height: 1080 @@ -107,7 +107,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 5, z: 0.834425449} + Translate: {x: -1.97624588, y: 5, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -115,14 +115,14 @@ Type: Dynamic Auto Mass: false Mass: 1 - Drag: 1 - Angular Drag: 1 + Drag: 0.00999999978 + Angular Drag: 0.00999999978 Use Gravity: true Gravity Scale: 1 Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp index 7abd6067..0fa8c861 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -159,8 +159,6 @@ namespace SHADE if (index < 0 || index >= NUM_VERTICES) throw std::invalid_argument("Index out-of-range!"); - // DirectX already puts vertex 0 - 4 on the front face for our case. - // Otherwise, it would need to be wrapped around for the correct vertex. return GetVertices()[index]; } diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 8f12475a..034e4d57 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -101,22 +101,22 @@ namespace SHADE } uint32_t numContacts = 0; - const float penetration = TOTAL_RADIUS - bestDistance; // Rotate the normal into the world space const SHVec3& BEST_NORMAL = CONVEX.GetNormal(closestFaceIndex); + const float PENETRATION = TOTAL_RADIUS - bestDistance; // Check if center is inside polyhedron (below the face) if (bestDistance < SHMath::EPSILON) { + manifold.normal = -BEST_NORMAL; + SHContact newContact; - newContact.penetration = penetration; - newContact.position = SPHERE.GetCenter(); + newContact.penetration = PENETRATION; + newContact.position = SPHERE.GetCenter() - BEST_NORMAL * PENETRATION; newContact.featurePair.key = 0; manifold.contacts[numContacts++] = newContact; - manifold.normal = BEST_NORMAL; - manifold.numContacts = numContacts; return true; } @@ -125,95 +125,98 @@ namespace SHADE // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center // If none of these are true, the sphere is above the face but not separating + /* + * | A + * _ _ _ _ _ _ | _ _ _ + * / / + * | / | / regionA + * |/ _ _ _ _ _|/ _ _ _ + * B/ regionB /C + * / / regionC + */ + const SHHalfEdgeDS::Face& CLOSEST_FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); const int32_t NUM_VERTICES_ON_FACE = static_cast(CLOSEST_FACE.vertexIndices.size()); - const SHVec3& CLOSEST_POINT = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[closestPointIndex]); - const SHVec3 CP_TO_CENTER = SPHERE.GetCenter() - CLOSEST_POINT; + const SHVec3 C = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[closestPointIndex]); + const SHVec3 C_TO_CENTER = SPHERE.GetCenter() - C; - // Check closest point -> prev point + const int32_t INDEX_A = (closestPointIndex + 1) % NUM_VERTICES_ON_FACE; + const int32_t INDEX_B = closestPointIndex == 0 ? NUM_VERTICES_ON_FACE - 1 : closestPointIndex - 1; + + const SHVec3 POINTS[2] = { - const int32_t PREV_POINT_INDEX = closestPointIndex == 0 ? NUM_VERTICES_ON_FACE - 1 : closestPointIndex - 1; - const SHVec3& PREV_POINT = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[PREV_POINT_INDEX]); + CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[INDEX_A]) // A + , CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[INDEX_B]) // B + }; - const SHVec3 CP_TO_PREV = SHVec3::Normalise(PREV_POINT - CLOSEST_POINT); + // To be inside either region A or B, 2 conditions must be satisfied + // 1. Same side as tangent + // 2. Same side as normal from edge to sphere - float projection = SHVec3::Dot(CP_TO_CENTER, CP_TO_PREV); + // Check in regions A & B + for (int i = 0; i < 2; ++i) + { + const SHVec3 TANGENT = SHVec3::Normalise(POINTS[i] - C); + + float projection = SHVec3::Dot(C_TO_CENTER, TANGENT); if (projection >= 0.0f) { - // Sphere is inside this region, check if distance from center is lesser than radius - if (penetration >= TOTAL_RADIUS) - return false; + // Check 2nd condition + // Find closest point + const SHVec3 CP = C + projection * TANGENT; + const SHVec3 CP_TO_CENTER = SHVec3::Normalise(C - CP); - SHContact newContact; - newContact.penetration = penetration; - newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; - newContact.featurePair.key = 0; + projection = SHVec3::Dot(C_TO_CENTER, CP_TO_CENTER); + if (projection >= 0.0f) + { + // Sphere Within region A + manifold.normal = CP_TO_CENTER; - manifold.contacts[numContacts++] = newContact; - manifold.normal = BEST_NORMAL; + SHContact newContact; + newContact.penetration = TOTAL_RADIUS - projection; + newContact.position = CP; + newContact.featurePair.key = 0; - manifold.numContacts = numContacts; - return true; + manifold.contacts[numContacts++] = newContact; + manifold.numContacts = numContacts; + + return true; + } } } - // Check closest point -> next point + // Check region C (closest point) { - const int32_t NEXT_POINT_INDEX = closestPointIndex + 1 % NUM_VERTICES_ON_FACE; - const SHVec3& NEXT_POINT = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[NEXT_POINT_INDEX]); - - const SHVec3 CP_TO_NEXT = SHVec3::Normalise(NEXT_POINT - CLOSEST_POINT); - - float projection = SHVec3::Dot(CP_TO_CENTER, CP_TO_NEXT); - if (projection >= 0.0f) + if (C_TO_CENTER.LengthSquared() < TOTAL_RADIUS * TOTAL_RADIUS) { - // Sphere is inside this region, check if distance from center is lesser than radius - if (penetration >= TOTAL_RADIUS) - return false; + manifold.normal = SHVec3::Normalise(C_TO_CENTER); SHContact newContact; - newContact.penetration = penetration; - newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; + newContact.penetration = PENETRATION; + newContact.position = C; newContact.featurePair.key = 0; manifold.contacts[numContacts++] = newContact; - manifold.normal = BEST_NORMAL; - manifold.numContacts = numContacts; + return true; } } - // Check if it hit the closest point + // Region D + if (PENETRATION <= TOTAL_RADIUS) { - if (CP_TO_CENTER.LengthSquared() < TOTAL_RADIUS * TOTAL_RADIUS) - { - SHContact newContact; - newContact.penetration = penetration; - newContact.position = CLOSEST_POINT; - newContact.featurePair.key = 0; + manifold.normal = -BEST_NORMAL; - manifold.contacts[numContacts++] = newContact; - manifold.normal = SHVec3::Normalise(CP_TO_CENTER); - - manifold.numContacts = numContacts; - return true; - } - } - - // It is above the closest face - if (penetration <= TOTAL_RADIUS) - { SHContact newContact; - newContact.penetration = penetration; + newContact.penetration = PENETRATION; newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; newContact.featurePair.key = 0; manifold.contacts[numContacts++] = newContact; - manifold.normal = BEST_NORMAL; - manifold.numContacts = numContacts; + return true; } diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index 3d1b7ba0..b1de5851 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -81,7 +81,7 @@ namespace SHADE { const SHMatrix TRS = SHMatrix::Transform(contactPoint.position, SHQuaternion::Identity, SHVec3{ 0.1f }); debugDrawSystem->DrawCube(TRS, CONTACT_COLOUR); - debugDrawSystem->DrawLine(contactPoint.position, contactPoint.position + contactPoint.normal * 0.3f, CONTACT_COLOUR, true); + debugDrawSystem->DrawLine(contactPoint.position, contactPoint.position + contactPoint.normal * 0.5f, CONTACT_COLOUR, true); } } -- 2.40.1 From 896b47c1a01e28fb98ebc4fe6a9ecbcb577f7e9f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:11:03 +0800 Subject: [PATCH 46/84] Fixed and optimised sphere vs convex polyhedron Improved sphere vs convex polyhedron from O(n^2) to O(n). Math is amazing. --- Assets/Scenes/PhysicsSandbox.shade | 231 ++++++++++++++---- .../CollisionShapes/SHBoxCollisionShape.cpp | 35 +++ .../SHCollisionShapeLibrary.cpp | 4 +- .../Narrowphase/SHSphereVsConvex.cpp | 92 +++---- .../src/Physics/Dynamics/SHContactManager.cpp | 1 - 5 files changed, 272 insertions(+), 91 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 7360d543..f93d0cc8 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,9 +4,9 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.80977702, y: 3, z: 0} - Rotate: {x: -0, y: 0, z: -0.506194055} - Scale: {x: 3.27252102, y: 0.999997199, z: 1} + Translate: {x: 2.58071685, y: 0.456140399, z: 0} + Rotate: {x: -0, y: 0, z: 0.469853699} + Scale: {x: 4.61071014, y: 0.999995053, z: 1} IsActive: true RigidBody Component: Type: Static @@ -19,7 +19,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -60,54 +60,13 @@ Perspective: true IsActive: true Scripts: ~ -- EID: 2 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 1, y: 1, z: 1} - IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: false - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: false - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true - Collider Component: - DrawColliders: false - Colliders: - - Is Trigger: false - Collision Tag: 1 - Type: Sphere - Radius: 2.5 - Friction: 0.400000006 - Bounciness: 0 - Density: 1 - Position Offset: {x: 0, y: 0, z: 0} - Rotation Offset: {x: 0, y: 0, z: 0} - IsActive: true - Scripts: ~ - EID: 3 Name: Default IsActive: true NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.97624588, y: 5, z: 0} + Translate: {x: -2.24715948, y: 6.47200441, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -141,6 +100,186 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 500 +- EID: 2 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 4.09544182, z: 0} + Rotate: {x: -0, y: 0, z: -0.437829614} + Scale: {x: 4.61071014, y: 0.999995887, z: 1} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: true + Freeze Position Y: true + Freeze Position Z: true + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: false + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 500 +- EID: 4 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: -1.74209237, z: 0} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 10, y: 0.5, z: 10} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: true + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: false + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 500 +- EID: 5 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -4.80025721, y: 3, z: 0} + Rotate: {x: -0, y: 0, z: 1.57079601} + Scale: {x: 9.99975109, y: 0.499992192, z: 10} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: true + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: false + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 500 +- EID: 6 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 4.80000019, y: 3, z: 0} + Rotate: {x: -0, y: 0, z: 1.57079601} + Scale: {x: 9.99975109, y: 0.499992192, z: 10} + IsActive: true + RigidBody Component: + Type: Static + Auto Mass: false + Mass: .inf + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: true + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: false + Colliders: + - Is Trigger: false + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true Scripts: - Type: PhysicsTestObj Enabled: true diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp index 0fa8c861..621b560b 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -160,6 +160,41 @@ namespace SHADE throw std::invalid_argument("Index out-of-range!"); return GetVertices()[index]; + + //// Rotate half extents + //const SHVec3 ROTATED_EXTENTS = SHVec3::Rotate(Extents, Orientation); + //const SHVec3 CENTER { Center }; + + ///* + // * Front: -Z + // * + // * 3 _____ 2 + // * | | + // * | | + // * |_____| + // * 0 1 + // * + // * Back: +Z + // * + // * 7 _____ 6 + // * | | + // * | | + // * |_____| + // * 4 5 + // * + // */ + + //switch (index) + //{ + // case 0: return CENTER + SHVec3 { -ROTATED_EXTENTS.x, -ROTATED_EXTENTS.y, -ROTATED_EXTENTS.z } + // case 1: return CENTER + SHVec3 { + // case 2: return CENTER + SHVec3 { + // case 3: return CENTER + SHVec3 { + // case 4: return CENTER + SHVec3 { + // case 5: return CENTER + SHVec3 { + // case 6: return CENTER + SHVec3 { + // case 7: return CENTER + SHVec3 { + //} } SHVec3 SHBoxCollisionShape::GetNormal(int faceIndex) const diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index e9832f9c..58af5dc4 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -126,9 +126,9 @@ namespace SHADE * * Faces: * - * Front: 0 (0,1,2,3) Normal: Z + * Front: 0 (0,1,2,3) Normal: -Z * Right: 1 (1,5,6,2) Normal: X - * Back: 2 (5,4,7,6) Normal: -Z + * Back: 2 (5,4,7,6) Normal: Z * Left: 3 (4,0,3,7) Normal: -X * Top: 4 (3,2,6,7) Normal: Y * Bottom: 5 (4,5,1,0) Normal: -Y diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 034e4d57..152c9460 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -52,8 +52,8 @@ namespace SHADE const SHSphereCollisionShape& SPHERE = dynamic_cast(A); const SHConvexPolyhedronCollisionShape& CONVEX = dynamic_cast(B); - // Ensure a gap between A & B - const float TOTAL_RADIUS = SPHERE.GetWorldRadius() + CONVEX.RADIUS; + const SHVec3 CENTER = SPHERE.GetCenter(); + const float TOTAL_RADIUS = SPHERE.GetWorldRadius() + SHConvexPolyhedronCollisionShape::RADIUS; // Find closest face of polygon to circle @@ -64,56 +64,49 @@ namespace SHADE const SHHalfEdgeDS* HALF_EDGE_STRUCTURE = CONVEX.GetHalfEdgeStructure(); /* - * Test against each face + * Test against each face. * - * TODO: - * This check is now O(n^2) because we find the closest point. - * It can be optimised to O(n) by utilising the following steps: - * 1. Rotate sphere into polyhedron's space - * 2. Build a plane equation from the face in point-normal form. We need the plane's offset from the origin. - * 3. Compute distance to the face. + * 1. For each face, build a plane in point-normal form. + * 2. Find the signed distance from plane to center of sphere. + * 3. Save best distance and face. */ for (int32_t i = 0; i < HALF_EDGE_STRUCTURE->GetFaceCount(); ++i) { const SHHalfEdgeDS::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(i); - // TODO: Remove and optimise - // Find the closest point on the face to the sphere - const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); - for (int32_t j = 0; j < NUM_VERTICES; ++j) + // Build plane equation + + const SHVec3 POINT = CONVEX.GetVertex(FACE.vertexIndices[0]); // use the first vertex to build a plane + const SHVec3& NORMAL = CONVEX.GetNormal(i); + const float D = -SHVec3::Dot(NORMAL, POINT); + + // Find signed distance of center to plane + const float SIGNED_DIST = SHVec3::Dot(NORMAL, CENTER) + D; + + // Early out: + // If face is facing away from center, signed dist is negative. + // Therefore signed distance is only positive when sphere is in front of the face. + if (SIGNED_DIST > TOTAL_RADIUS) + return false; + + if (SIGNED_DIST > bestDistance) { - // Get vector from center to a vertex on the face - const SHVec3 A_TO_B = SPHERE.GetCenter() - CONVEX.GetVertex(FACE.vertexIndices[j]); - - const float PROJECTION = SHVec3::Dot(A_TO_B, FACE.normal); - - // Early out - if (PROJECTION > TOTAL_RADIUS) - return false; - - if (PROJECTION > bestDistance) - { - bestDistance = PROJECTION; - closestFaceIndex = i; - closestPointIndex = j; - } + bestDistance = SIGNED_DIST; + closestFaceIndex = i; } } uint32_t numContacts = 0; - - // Rotate the normal into the world space - const SHVec3& BEST_NORMAL = CONVEX.GetNormal(closestFaceIndex); const float PENETRATION = TOTAL_RADIUS - bestDistance; // Check if center is inside polyhedron (below the face) if (bestDistance < SHMath::EPSILON) { - manifold.normal = -BEST_NORMAL; + manifold.normal = CONVEX.GetNormal(closestFaceIndex); SHContact newContact; newContact.penetration = PENETRATION; - newContact.position = SPHERE.GetCenter() - BEST_NORMAL * PENETRATION; + newContact.position = SPHERE.GetCenter(); newContact.featurePair.key = 0; manifold.contacts[numContacts++] = newContact; @@ -135,10 +128,25 @@ namespace SHADE * / / regionC */ - const SHHalfEdgeDS::Face& CLOSEST_FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); - const int32_t NUM_VERTICES_ON_FACE = static_cast(CLOSEST_FACE.vertexIndices.size()); + const SHHalfEdgeDS::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); + const SHVec3& NORMAL = CONVEX.GetNormal(closestFaceIndex); - const SHVec3 C = CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[closestPointIndex]); + const int32_t NUM_VERTICES_ON_FACE = static_cast(FACE.vertexIndices.size()); + + // Find closest point on face + closestPointIndex = 0; + float smallestDist = SHVec3::Dot(CENTER - CONVEX.GetVertex(FACE.vertexIndices[0]), NORMAL); + + for (int32_t i = 1; i < NUM_VERTICES_ON_FACE; ++i) + { + const SHVec3 POINT = CONVEX.GetVertex(FACE.vertexIndices[i]); + const float PROJECTION = SHVec3::Dot(CENTER - POINT, NORMAL); + + if (PROJECTION < smallestDist) + closestPointIndex = i; + } + + const SHVec3 C = CONVEX.GetVertex(FACE.vertexIndices[closestPointIndex]); const SHVec3 C_TO_CENTER = SPHERE.GetCenter() - C; const int32_t INDEX_A = (closestPointIndex + 1) % NUM_VERTICES_ON_FACE; @@ -146,8 +154,8 @@ namespace SHADE const SHVec3 POINTS[2] = { - CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[INDEX_A]) // A - , CONVEX.GetVertex(CLOSEST_FACE.vertexIndices[INDEX_B]) // B + CONVEX.GetVertex(FACE.vertexIndices[INDEX_A]) // A + , CONVEX.GetVertex(FACE.vertexIndices[INDEX_B]) // B }; // To be inside either region A or B, 2 conditions must be satisfied @@ -170,7 +178,7 @@ namespace SHADE projection = SHVec3::Dot(C_TO_CENTER, CP_TO_CENTER); if (projection >= 0.0f) { - // Sphere Within region A + // Sphere Within region manifold.normal = CP_TO_CENTER; SHContact newContact; @@ -190,7 +198,7 @@ namespace SHADE { if (C_TO_CENTER.LengthSquared() < TOTAL_RADIUS * TOTAL_RADIUS) { - manifold.normal = SHVec3::Normalise(C_TO_CENTER); + manifold.normal = -SHVec3::Normalise(C_TO_CENTER); SHContact newContact; newContact.penetration = PENETRATION; @@ -207,11 +215,11 @@ namespace SHADE // Region D if (PENETRATION <= TOTAL_RADIUS) { - manifold.normal = -BEST_NORMAL; + manifold.normal = -NORMAL; SHContact newContact; newContact.penetration = PENETRATION; - newContact.position = SPHERE.GetCenter() - BEST_NORMAL * TOTAL_RADIUS; + newContact.position = SPHERE.GetCenter() - NORMAL * TOTAL_RADIUS; newContact.featurePair.key = 0; manifold.contacts[numContacts++] = newContact; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index c8bd2abe..34e3dabf 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -63,7 +63,6 @@ namespace SHADE const SHContactManager::ContactPoints& SHContactManager::GetContactPoints() const noexcept { static ContactPoints contactPoints; - contactPoints.clear(); for (auto& manifold : manifolds | std::views::values) -- 2.40.1 From 987a1fa515fbad167de0f7c5a27a2c6926547f98 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:18:35 +0800 Subject: [PATCH 47/84] Fixed false positives with convex polyhedron radii --- .../SHConvexPolyhedronCollisionShape.h | 6 ------ .../Collision/Narrowphase/SHSphereVsConvex.cpp | 16 ++++++++-------- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 1 - 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h index 6748793c..f459e87e 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h @@ -36,12 +36,6 @@ namespace SHADE friend class SHCollisionShapeLibrary; public: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - static constexpr float RADIUS = 0.1f; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 152c9460..d7813d85 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -52,8 +52,8 @@ namespace SHADE const SHSphereCollisionShape& SPHERE = dynamic_cast(A); const SHConvexPolyhedronCollisionShape& CONVEX = dynamic_cast(B); - const SHVec3 CENTER = SPHERE.GetCenter(); - const float TOTAL_RADIUS = SPHERE.GetWorldRadius() + SHConvexPolyhedronCollisionShape::RADIUS; + const SHVec3 CENTER = SPHERE.GetCenter(); + const float RADIUS = SPHERE.GetWorldRadius(); // Find closest face of polygon to circle @@ -86,7 +86,7 @@ namespace SHADE // Early out: // If face is facing away from center, signed dist is negative. // Therefore signed distance is only positive when sphere is in front of the face. - if (SIGNED_DIST > TOTAL_RADIUS) + if (SIGNED_DIST > RADIUS) return false; if (SIGNED_DIST > bestDistance) @@ -97,7 +97,7 @@ namespace SHADE } uint32_t numContacts = 0; - const float PENETRATION = TOTAL_RADIUS - bestDistance; + const float PENETRATION = RADIUS - bestDistance; // Check if center is inside polyhedron (below the face) if (bestDistance < SHMath::EPSILON) @@ -182,7 +182,7 @@ namespace SHADE manifold.normal = CP_TO_CENTER; SHContact newContact; - newContact.penetration = TOTAL_RADIUS - projection; + newContact.penetration = RADIUS - projection; newContact.position = CP; newContact.featurePair.key = 0; @@ -196,7 +196,7 @@ namespace SHADE // Check region C (closest point) { - if (C_TO_CENTER.LengthSquared() < TOTAL_RADIUS * TOTAL_RADIUS) + if (C_TO_CENTER.LengthSquared() < RADIUS * RADIUS) { manifold.normal = -SHVec3::Normalise(C_TO_CENTER); @@ -213,13 +213,13 @@ namespace SHADE } // Region D - if (PENETRATION <= TOTAL_RADIUS) + if (PENETRATION <= RADIUS) { manifold.normal = -NORMAL; SHContact newContact; newContact.penetration = PENETRATION; - newContact.position = SPHERE.GetCenter() - NORMAL * TOTAL_RADIUS; + newContact.position = SPHERE.GetCenter() - NORMAL * RADIUS; newContact.featurePair.key = 0; manifold.contacts[numContacts++] = newContact; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 4e6e8165..d5c9b029 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -108,7 +108,6 @@ namespace SHADE /* - * TODO: A lot of this needs to be cleaned up. * Resolve Contacts */ -- 2.40.1 From 6451ca5e954bcb53e6a6ef161b317d73dd6888d8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:40:28 +0800 Subject: [PATCH 48/84] forgot to flip a normal --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index f93d0cc8..731df7ce 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -2.24715948, y: 6.47200441, z: 0} + Translate: {x: -1.98839664, y: 7.7662077, z: 0} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index d7813d85..314e3ff9 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -102,7 +102,7 @@ namespace SHADE // Check if center is inside polyhedron (below the face) if (bestDistance < SHMath::EPSILON) { - manifold.normal = CONVEX.GetNormal(closestFaceIndex); + manifold.normal = -CONVEX.GetNormal(closestFaceIndex); SHContact newContact; newContact.penetration = PENETRATION; @@ -179,7 +179,7 @@ namespace SHADE if (projection >= 0.0f) { // Sphere Within region - manifold.normal = CP_TO_CENTER; + manifold.normal = -CP_TO_CENTER; SHContact newContact; newContact.penetration = RADIUS - projection; -- 2.40.1 From 136b7e7bfcb07f90b251d8d5f915d09845a6701a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:47:42 +0800 Subject: [PATCH 49/84] Renamed HalfEdgeDS to HalfEdgeStructure for clarity do not abbreviate. abbreviation are usually bad!! --- .../CollisionShapes/SHCollisionShape.h | 2 +- .../SHCollisionShapeLibrary.cpp | 4 +-- .../CollisionShapes/SHCollisionShapeLibrary.h | 2 +- .../SHConvexPolyhedronCollisionShape.cpp | 2 +- .../SHConvexPolyhedronCollisionShape.h | 10 +++--- ...HalfEdgeDS.cpp => SHHalfEdgeStructure.cpp} | 34 +++++++++---------- .../{SHHalfEdgeDS.h => SHHalfEdgeStructure.h} | 6 ++-- .../Narrowphase/SHSphereVsConvex.cpp | 8 ++--- 8 files changed, 34 insertions(+), 34 deletions(-) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHHalfEdgeDS.cpp => SHHalfEdgeStructure.cpp} (84%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHHalfEdgeDS.h => SHHalfEdgeStructure.h} (98%) diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 6a2e81e4..0a320444 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -131,7 +131,7 @@ namespace SHADE virtual void ComputeTransforms () noexcept = 0; [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; - [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; + [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index 58af5dc4..338083c7 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -159,7 +159,7 @@ namespace SHADE for (int i = 0; i < NUM_FACES; ++i) { - SHHalfEdgeDS::Face newFace; + SHHalfEdgeStructure::Face newFace; newFace.normal = FACE_NORMALS[i]; for (int j = 0; j < NUM_VERTICES_PER_FACE; ++j) @@ -168,7 +168,7 @@ namespace SHADE boxHalfEdgeDS.AddFace(newFace); } - boxHalfEdgeDS.BuildPolyhedron(); + boxHalfEdgeDS.Build(); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h index b20abb7f..bb9c2807 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h @@ -92,7 +92,7 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHHalfEdgeDS boxHalfEdgeDS; + SHHalfEdgeStructure boxHalfEdgeDS; Spheres spheres; Boxes boxes; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp index 586d67f4..db6d3621 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp @@ -93,7 +93,7 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHHalfEdgeDS* SHConvexPolyhedronCollisionShape::GetHalfEdgeStructure() const noexcept + const SHHalfEdgeStructure* SHConvexPolyhedronCollisionShape::GetHalfEdgeStructure() const noexcept { return halfEdgeStructure; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h index f459e87e..7a0f6df0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h @@ -12,7 +12,7 @@ // Project Headers #include "SHCollisionShape.h" -#include "SHHalfEdgeDS.h" +#include "SHHalfEdgeStructure.h" namespace SHADE { @@ -57,16 +57,16 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] const SHHalfEdgeDS* GetHalfEdgeStructure () const noexcept; - [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; - [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; + [[nodiscard]] const SHHalfEdgeStructure* GetHalfEdgeStructure () const noexcept; + [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; + [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; protected: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHHalfEdgeDS* halfEdgeStructure; // Defines the polyhedron by it's half edges. + SHHalfEdgeStructure* halfEdgeStructure; // Defines the polyhedron by it's half edges. }; } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp similarity index 84% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp index 3bf48608..4c9304c4 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHHalfEdgeDS.cpp + * \file SHHalfEdgeStructure.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Implementation for a half-edge data structure to represent polyhedra. * @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHHalfEdgeDS.h" +#include "SHHalfEdgeStructure.h" // Helper Macros @@ -23,7 +23,7 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHHalfEdgeDS::HalfEdge::HalfEdge() noexcept + SHHalfEdgeStructure::HalfEdge::HalfEdge() noexcept : tailVertexIndex { -1 } , headVertexIndex { -1 } , edgeIndex { -1 } @@ -31,7 +31,7 @@ namespace SHADE , faceIndex { -1 } {} - SHHalfEdgeDS::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept + SHHalfEdgeStructure::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept : tailVertexIndex { rhs.tailVertexIndex } , headVertexIndex { rhs.headVertexIndex } , edgeIndex { rhs.edgeIndex } @@ -39,7 +39,7 @@ namespace SHADE , faceIndex { rhs.faceIndex } {} - SHHalfEdgeDS::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept + SHHalfEdgeStructure::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept : tailVertexIndex { rhs.tailVertexIndex } , headVertexIndex { rhs.headVertexIndex } , edgeIndex { rhs.edgeIndex } @@ -47,13 +47,13 @@ namespace SHADE , faceIndex { rhs.faceIndex } {} - SHHalfEdgeDS::Face::Face(const Face& rhs) noexcept + SHHalfEdgeStructure::Face::Face(const Face& rhs) noexcept : normal { rhs.normal } { std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); } - SHHalfEdgeDS::Face::Face(Face&& rhs) noexcept + SHHalfEdgeStructure::Face::Face(Face&& rhs) noexcept : normal { rhs.normal } { std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); @@ -63,7 +63,7 @@ namespace SHADE /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHHalfEdgeDS::HalfEdge& SHHalfEdgeDS::HalfEdge::operator=(const HalfEdge& rhs) noexcept + SHHalfEdgeStructure::HalfEdge& SHHalfEdgeStructure::HalfEdge::operator=(const HalfEdge& rhs) noexcept { if (this == &rhs) return *this; @@ -77,7 +77,7 @@ namespace SHADE return *this; } - SHHalfEdgeDS::HalfEdge& SHHalfEdgeDS::HalfEdge::operator=(HalfEdge&& rhs) noexcept + SHHalfEdgeStructure::HalfEdge& SHHalfEdgeStructure::HalfEdge::operator=(HalfEdge&& rhs) noexcept { tailVertexIndex = rhs.tailVertexIndex; headVertexIndex = rhs.headVertexIndex; @@ -88,7 +88,7 @@ namespace SHADE return *this; } - SHHalfEdgeDS::Face& SHHalfEdgeDS::Face::operator=(const Face& rhs) noexcept + SHHalfEdgeStructure::Face& SHHalfEdgeStructure::Face::operator=(const Face& rhs) noexcept { if (this == &rhs) return *this; @@ -101,7 +101,7 @@ namespace SHADE return *this; } - SHHalfEdgeDS::Face& SHHalfEdgeDS::Face::operator=(Face&& rhs) noexcept + SHHalfEdgeStructure::Face& SHHalfEdgeStructure::Face::operator=(Face&& rhs) noexcept { normal = rhs.normal; @@ -115,17 +115,17 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - int32_t SHHalfEdgeDS::GetFaceCount() const noexcept + int32_t SHHalfEdgeStructure::GetFaceCount() const noexcept { return static_cast(faces.size()); } - int32_t SHHalfEdgeDS::GetHalfEdgeCount() const noexcept + int32_t SHHalfEdgeStructure::GetHalfEdgeCount() const noexcept { return static_cast(halfEdges.size()); } - const SHHalfEdgeDS::Face& SHHalfEdgeDS::GetFace(int32_t index) const + const SHHalfEdgeStructure::Face& SHHalfEdgeStructure::GetFace(int32_t index) const { if (index < 0 || index >= static_cast(faces.size())) throw std::invalid_argument("Index out-of-range!"); @@ -133,7 +133,7 @@ namespace SHADE return faces[index]; } - const SHHalfEdgeDS::HalfEdge& SHHalfEdgeDS::GetHalfEdge(int32_t index) const + const SHHalfEdgeStructure::HalfEdge& SHHalfEdgeStructure::GetHalfEdge(int32_t index) const { if (index < 0 || index >= static_cast(halfEdges.size())) throw std::invalid_argument("Index out-of-range!"); @@ -145,12 +145,12 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHHalfEdgeDS::AddFace(const Face& face) + void SHHalfEdgeStructure::AddFace(const Face& face) { faces.emplace_back(face); } - void SHHalfEdgeDS::BuildPolyhedron() noexcept + void SHHalfEdgeStructure::Build() noexcept { // We use the pair of vertex IDs on a half-edge to prevent duplicates std::unordered_map edgeMap; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h similarity index 98% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h index 272d893c..c08803ce 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeDS.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHHalfEdgeDS.h + * \file SHHalfEdgeStructure.h * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Interface for a half-edge data structure to represent polyhedra. * @@ -25,7 +25,7 @@ namespace SHADE * @brief * Encapsulates data for a convex polyhedron's geometry represented as faces & half edges. */ - class SH_API SHHalfEdgeDS + class SH_API SHHalfEdgeStructure { public: /*---------------------------------------------------------------------------------*/ @@ -127,7 +127,7 @@ namespace SHADE * Before this method is invoked, there must be some faces. * @return */ - void BuildPolyhedron() noexcept; + void Build() noexcept; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 314e3ff9..e62bc241 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -61,7 +61,7 @@ namespace SHADE int32_t closestPointIndex = -1; float bestDistance = std::numeric_limits::lowest(); - const SHHalfEdgeDS* HALF_EDGE_STRUCTURE = CONVEX.GetHalfEdgeStructure(); + const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = CONVEX.GetHalfEdgeStructure(); /* * Test against each face. @@ -72,7 +72,7 @@ namespace SHADE */ for (int32_t i = 0; i < HALF_EDGE_STRUCTURE->GetFaceCount(); ++i) { - const SHHalfEdgeDS::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(i); + const SHHalfEdgeStructure::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(i); // Build plane equation @@ -128,8 +128,8 @@ namespace SHADE * / / regionC */ - const SHHalfEdgeDS::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); - const SHVec3& NORMAL = CONVEX.GetNormal(closestFaceIndex); + const SHHalfEdgeStructure::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); + const SHVec3& NORMAL = CONVEX.GetNormal(closestFaceIndex); const int32_t NUM_VERTICES_ON_FACE = static_cast(FACE.vertexIndices.size()); -- 2.40.1 From 3a7336fe15d918ec281252f833da001040811bd4 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 18:43:46 +0800 Subject: [PATCH 50/84] Improved stability of sphere vs convex polyhedron except for one edge case --- Assets/Scenes/PhysicsSandbox.shade | 10 +- .../SHCollisionShapeLibrary.cpp | 6 +- .../CollisionShapes/SHCollisionShapeLibrary.h | 6 +- .../CollisionShapes/SHHalfEdgeStructure.cpp | 68 +-- .../CollisionShapes/SHHalfEdgeStructure.h | 53 ++- .../Collision/Narrowphase/SHCollision.h | 16 + .../Narrowphase/SHSphereVsConvex.cpp | 391 +++++++++++------- .../src/Physics/Collision/SHPhysicsMaterial.h | 4 + 8 files changed, 304 insertions(+), 250 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 731df7ce..4230dcb8 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -4,9 +4,9 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 2.58071685, y: 0.456140399, z: 0} - Rotate: {x: -0, y: 0, z: 0.469853699} - Scale: {x: 4.61071014, y: 0.999995053, z: 1} + Translate: {x: 2.72256827, y: 0.501797795, z: -0.0273017883} + Rotate: {x: -1.48352849, y: -4.78713309e-06, z: 0.469859391} + Scale: {x: 4.61070776, y: 0.99999392, z: 0.999996722} IsActive: true RigidBody Component: Type: Static @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.98839664, y: 7.7662077, z: 0} + Translate: {x: -2.49145222, y: 6.17996597, z: 0.811235607} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -112,7 +112,7 @@ Components: Transform Component: Translate: {x: 0, y: 4.09544182, z: 0} - Rotate: {x: -0, y: 0, z: -0.437829614} + Rotate: {x: -0, y: 0, z: 0} Scale: {x: 4.61071014, y: 0.999995887, z: 1} IsActive: true RigidBody Component: diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index 338083c7..46adb47b 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -71,7 +71,7 @@ namespace SHADE box->scale = createInfo.Scale; // Set halfEdge data structure for the box - box->halfEdgeStructure = &boxHalfEdgeDS; + box->halfEdgeStructure = &boxHalfEdgeStructure; return box; } @@ -165,10 +165,10 @@ namespace SHADE for (int j = 0; j < NUM_VERTICES_PER_FACE; ++j) newFace.vertexIndices.emplace_back(FACE_VERTICES[i][j]); - boxHalfEdgeDS.AddFace(newFace); + boxHalfEdgeStructure.AddFace(newFace); } - boxHalfEdgeDS.Build(); + boxHalfEdgeStructure.Build(); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h index bb9c2807..dbfc4fc7 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h @@ -92,10 +92,10 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHHalfEdgeStructure boxHalfEdgeDS; + SHHalfEdgeStructure boxHalfEdgeStructure; - Spheres spheres; - Boxes boxes; + Spheres spheres; + Boxes boxes; // TODO: Add capsules and hulls /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp index 4c9304c4..a25b5b8b 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp @@ -23,30 +23,6 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHHalfEdgeStructure::HalfEdge::HalfEdge() noexcept - : tailVertexIndex { -1 } - , headVertexIndex { -1 } - , edgeIndex { -1 } - , twinEdgeIndex { -1 } - , faceIndex { -1 } - {} - - SHHalfEdgeStructure::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept - : tailVertexIndex { rhs.tailVertexIndex } - , headVertexIndex { rhs.headVertexIndex } - , edgeIndex { rhs.edgeIndex } - , twinEdgeIndex { rhs.twinEdgeIndex } - , faceIndex { rhs.faceIndex } - {} - - SHHalfEdgeStructure::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept - : tailVertexIndex { rhs.tailVertexIndex } - , headVertexIndex { rhs.headVertexIndex } - , edgeIndex { rhs.edgeIndex } - , twinEdgeIndex { rhs.twinEdgeIndex } - , faceIndex { rhs.faceIndex } - {} - SHHalfEdgeStructure::Face::Face(const Face& rhs) noexcept : normal { rhs.normal } { @@ -63,31 +39,6 @@ namespace SHADE /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHHalfEdgeStructure::HalfEdge& SHHalfEdgeStructure::HalfEdge::operator=(const HalfEdge& rhs) noexcept - { - if (this == &rhs) - return *this; - - tailVertexIndex = rhs.tailVertexIndex; - headVertexIndex = rhs.headVertexIndex; - edgeIndex = rhs.edgeIndex ; - twinEdgeIndex = rhs.twinEdgeIndex ; - faceIndex = rhs.faceIndex ; - - return *this; - } - - SHHalfEdgeStructure::HalfEdge& SHHalfEdgeStructure::HalfEdge::operator=(HalfEdge&& rhs) noexcept - { - tailVertexIndex = rhs.tailVertexIndex; - headVertexIndex = rhs.headVertexIndex; - edgeIndex = rhs.edgeIndex ; - twinEdgeIndex = rhs.twinEdgeIndex ; - faceIndex = rhs.faceIndex ; - - return *this; - } - SHHalfEdgeStructure::Face& SHHalfEdgeStructure::Face::operator=(const Face& rhs) noexcept { if (this == &rhs) @@ -165,19 +116,19 @@ namespace SHADE // For each face, build half edges for (size_t i = 0; i < faces.size(); ++i) { - const Face& FACE = faces[i]; + Face& face = faces[i]; - if (FACE.vertexIndices.empty()) + if (face.vertexIndices.empty()) { SHLOGV_CRITICAL("Unable to build convex polyhedron, no vertices have been added to face {}!", i) return; } // Iterate through vertices and build half-edges - for (size_t j = 0; j < FACE.vertexIndices.size(); ++j) + for (size_t j = 0; j < face.vertexIndices.size(); ++j) { - const int32_t TAIL = FACE.vertexIndices[j]; - const int32_t HEAD = FACE.vertexIndices[(j + 1) % FACE.vertexIndices.size()]; + const int32_t TAIL = face.vertexIndices[j].index; + const int32_t HEAD = face.vertexIndices[(j + 1) % face.vertexIndices.size()].index; const uint64_t NEW_EDGE_ID = BUILD_UINT64_FROM_UINT32S(TAIL, HEAD); const uint64_t TWIN_EDGE_ID = BUILD_UINT64_FROM_UINT32S(HEAD, TAIL); @@ -197,6 +148,9 @@ namespace SHADE // Set edge index of the newly inserted edge as the size of the map - 1 // Since it is an unordered map, it will just be at the back newHalfEdge.edgeIndex = static_cast(edgeMap.size()) - 1; + + // Map vertex to this edge index + face.vertexIndices[j].edgeIndex = newHalfEdge.edgeIndex; } // Find twin edge if one exists @@ -217,6 +171,12 @@ namespace SHADE // At this point, no duplicates should be in the map and all edges should be linked. for (auto& halfEdge : edgeMap | std::views::values) halfEdges.emplace_back(halfEdge); + + // Sort based on edge indices + std::ranges::sort(halfEdges.begin(), halfEdges.end(), [](const HalfEdge& lhs, const HalfEdge& rhs) + { + return lhs.edgeIndex < rhs.edgeIndex; + }); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h index c08803ce..8982ae23 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h @@ -32,6 +32,10 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates the data half edge of a face on a polyhedron. + */ struct HalfEdge { /*-------------------------------------------------------------------------------*/ @@ -40,36 +44,35 @@ namespace SHADE //Head and tail forms the edge. //Head <----- Tail - int32_t tailVertexIndex; + int32_t tailVertexIndex = -1; // Head is also tail of the next edge. - int32_t headVertexIndex; + int32_t headVertexIndex = -1; - int32_t edgeIndex; + int32_t edgeIndex = -1; // Other half of the edge on a different face. // Important for extrapolating face normals. - int32_t twinEdgeIndex; + int32_t twinEdgeIndex = -1; // Adjacent face of this edge. - int32_t faceIndex; - - /*-------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-------------------------------------------------------------------------------*/ - - HalfEdge () noexcept; - HalfEdge (const HalfEdge& rhs) noexcept; - HalfEdge (HalfEdge&& rhs) noexcept; - ~HalfEdge () noexcept = default; - - /*-------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*-------------------------------------------------------------------------------*/ - - HalfEdge& operator= (const HalfEdge& rhs) noexcept; - HalfEdge& operator= (HalfEdge&& rhs) noexcept; + int32_t faceIndex = -1; }; + struct Vertex + { + public: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + int32_t index = -1; + int32_t edgeIndex = -1; // the half-edge that this vertex is a tail of. + }; + + /** + * @brief + * Encapsulates the data of a face on a polyhedron. + */ struct Face { public: @@ -77,10 +80,8 @@ namespace SHADE /* Data Members */ /*-------------------------------------------------------------------------------*/ - // TODO: Store face offset - SHVec3 normal; - std::vector vertexIndices; // Must be in CCW order + std::vector vertexIndices; // Must be in CCW order /*-------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -133,10 +134,6 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - - float radius = 0.2f; // Default Radius is 2 cm - - // Store the faces and half-edges std::vector faces; std::vector halfEdges; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index b99cc202..942c6919 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -67,10 +67,26 @@ namespace SHADE [[nodiscard]] static bool ConvexVsConvex (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct FaceQuery + { + bool colliding = false; + int32_t closestFace = -1; + float bestDistance = std::numeric_limits::lowest(); + }; + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ + // Sphere VS Convex + + static FaceQuery findClosestFace (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept; + static int32_t findClosestPoint (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept; + static bool isMinkowskiFace(const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; // TODO: buildMinkowskiFace, queryEdgeDirection, distanceBetweenTwoEdges, diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index e62bc241..e84bd16b 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -19,16 +19,6 @@ #include "Physics/Collision/CollisionShapes/SHCollisionShape.h" #include "Physics/Collision/CollisionShapes/SHBoxCollisionShape.h" -// When testing against convex polyhedrons, we do not care so much as whether it is a box -// or something else. We only need the vertices to build half edge structures for use -// with a gauss map. Regardless, we still cast it to the type just to get vertices -// since spheres and capsules do not implement the same method. - -// I did consider having another base class that encapsulates methods that convex polyhedrons -// would implement, but for the sake of my sanity, I won't do that. - -// TODO - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -37,6 +27,21 @@ namespace SHADE bool SHCollision::SphereVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept { + const SHSphereCollisionShape& SPHERE = dynamic_cast(A); + const SHConvexPolyhedronCollisionShape& POLYHEDRON = dynamic_cast(B); + + const SHVec3 CENTER = SPHERE.GetCenter(); + const float RADIUS = SPHERE.GetWorldRadius(); + + const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = POLYHEDRON.GetHalfEdgeStructure(); + + const FaceQuery FACE_QUERY = findClosestFace(SPHERE, POLYHEDRON); + if (!FACE_QUERY.colliding) + return false; + + if (FACE_QUERY.bestDistance < SHMath::EPSILON) + return true; + return false; } @@ -49,19 +54,197 @@ namespace SHADE { // Convert to underlying types // For the convex, we only need the convex polyhedron shape since the get vertex is pure virtual. - const SHSphereCollisionShape& SPHERE = dynamic_cast(A); - const SHConvexPolyhedronCollisionShape& CONVEX = dynamic_cast(B); + const SHSphereCollisionShape& SPHERE = dynamic_cast(A); + const SHConvexPolyhedronCollisionShape& POLYHEDRON = dynamic_cast(B); const SHVec3 CENTER = SPHERE.GetCenter(); const float RADIUS = SPHERE.GetWorldRadius(); + const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = POLYHEDRON.GetHalfEdgeStructure(); + + const FaceQuery FACE_QUERY = findClosestFace(SPHERE, POLYHEDRON); + if (!FACE_QUERY.colliding) + return false; + + uint32_t numContacts = 0; + const float PENETRATION = RADIUS - FACE_QUERY.bestDistance; + + SHContact contact; + contact.featurePair.key = 0; + + // Check if center is inside polyhedron (below the face) + if (FACE_QUERY.bestDistance < SHMath::EPSILON) + { + manifold.normal = -POLYHEDRON.GetNormal(FACE_QUERY.closestFace); + + contact.penetration = PENETRATION; + contact.position = SPHERE.GetCenter(); + + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; + return true; + } + // Find closest face of polygon to circle + const int32_t CLOSEST_POINT = findClosestPoint(SPHERE, POLYHEDRON, FACE_QUERY.closestFace); - int32_t closestFaceIndex = -1; - int32_t closestPointIndex = -1; - float bestDistance = std::numeric_limits::lowest(); + const SHHalfEdgeStructure::Face& FACE = POLYHEDRON.GetHalfEdgeStructure()->GetFace(FACE_QUERY.closestFace); - const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = CONVEX.GetHalfEdgeStructure(); + const SHVec3& FACE_NORMAL = POLYHEDRON.GetNormal(FACE_QUERY.closestFace); + const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); + + // Check against voronoi regions of the face to determine the type of the intersection test + // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center + // If none of these are true, the sphere is above the face but not separating + + /* + * | 2 + * _ _ _ _ _ _ | _ _ _ + * / / + * | / regionD | / regionA + * |/ _ _ _ _ _|/ _ _ _ + * 3/ regionB /1 + * / / regionC + * + */ + + const SHVec3 P1 = POLYHEDRON.GetVertex(FACE.vertexIndices[CLOSEST_POINT].index); + const SHVec3 P1_TO_CENTER = CENTER - P1; + + // To be inside either region A or B, 2 conditions must be satisfied + // 1. Same side as tangent + // 2. Same side as adjacent normal + + // Check in regions A + { + const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; + const SHVec3 P2 = POLYHEDRON.GetVertex(FACE.vertexIndices[P2_INDEX].index); + + const SHVec3 TANGENT = SHVec3::Normalise(P2 - P1); + + float projection = SHVec3::Dot(P1_TO_CENTER, TANGENT); + + if (projection >= 0.0f) + { + // Find closest point + const SHVec3 CP = P1 + projection * TANGENT; + + // Check 2nd condition + // Get adjacent normal from twin half edge + const int32_t EDGE_INDEX = FACE.vertexIndices[CLOSEST_POINT].edgeIndex; + const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + + const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; + const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + + projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); + if (projection >= 0.0f) + { + // Must be smaller than radius + if (projection >= RADIUS) + return false; + + const SHVec3 CP_TO_CENTER = CENTER - CP; + + manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); + + contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); + contact.position = CP; + + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; + + return true; + } + } + } + + // Check in region B + { + const int32_t P3_INDEX = CLOSEST_POINT == 0 ? NUM_VERTICES - 1 : CLOSEST_POINT - 1; + const SHVec3 P3 = POLYHEDRON.GetVertex(FACE.vertexIndices[P3_INDEX].index); + + const SHVec3 TANGENT = SHVec3::Normalise(P3 - P1); + + float projection = SHVec3::Dot(P1_TO_CENTER, TANGENT); + + if (projection >= 0.0f) + { + // Find closest point + const SHVec3 CP = P1 + projection * TANGENT; + + // Check 2nd condition + // Get adjacent normal from twin half edge + const int32_t EDGE_INDEX = FACE.vertexIndices[P3_INDEX].edgeIndex; + const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + + const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; + const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + + projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); + if (projection >= 0.0f) + { + // Must be smaller than radius + if (projection >= RADIUS) + return false; + + const SHVec3 CP_TO_CENTER = CENTER - CP; + + manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); + + contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); + contact.position = CP; + + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; + + return true; + } + } + } + + // Either region C or D. Take whichever depth is smaller + + const float C_PENETRATION = RADIUS - P1_TO_CENTER.Length(); + + if (std::fabs(C_PENETRATION) < RADIUS && std::fabs(C_PENETRATION) < PENETRATION) + { + manifold.normal = -SHVec3::Normalise(P1_TO_CENTER); + + contact.penetration = C_PENETRATION; + contact.position = P1; + } + else + { + manifold.normal = -FACE_NORMAL; + + contact.penetration = PENETRATION; + contact.position = CENTER - FACE_NORMAL * RADIUS; + } + + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; + + return true; + } + + bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + { + return SphereVsConvex(manifold, B, A); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollision::FaceQuery SHCollision::findClosestFace(const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept + { + FaceQuery faceQuery; + + const SHVec3 CENTER = sphere.GetCenter(); + const float RADIUS = sphere.GetWorldRadius(); + + const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = polyhedron.GetHalfEdgeStructure(); /* * Test against each face. @@ -76,8 +259,8 @@ namespace SHADE // Build plane equation - const SHVec3 POINT = CONVEX.GetVertex(FACE.vertexIndices[0]); // use the first vertex to build a plane - const SHVec3& NORMAL = CONVEX.GetNormal(i); + const SHVec3 POINT = polyhedron.GetVertex(FACE.vertexIndices[0].index); // use the first vertex to build a plane + const SHVec3& NORMAL = polyhedron.GetNormal(i); const float D = -SHVec3::Dot(NORMAL, POINT); // Find signed distance of center to plane @@ -87,153 +270,47 @@ namespace SHADE // If face is facing away from center, signed dist is negative. // Therefore signed distance is only positive when sphere is in front of the face. if (SIGNED_DIST > RADIUS) - return false; + return faceQuery; - if (SIGNED_DIST > bestDistance) + if (SIGNED_DIST > faceQuery.bestDistance) { - bestDistance = SIGNED_DIST; - closestFaceIndex = i; + faceQuery.bestDistance = SIGNED_DIST; + faceQuery.closestFace = i; } } - uint32_t numContacts = 0; - const float PENETRATION = RADIUS - bestDistance; - - // Check if center is inside polyhedron (below the face) - if (bestDistance < SHMath::EPSILON) - { - manifold.normal = -CONVEX.GetNormal(closestFaceIndex); - - SHContact newContact; - newContact.penetration = PENETRATION; - newContact.position = SPHERE.GetCenter(); - newContact.featurePair.key = 0; - - manifold.contacts[numContacts++] = newContact; - manifold.numContacts = numContacts; - return true; - } - - // Check against voronoi regions of the face to determine the type of the intersection test - // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center - // If none of these are true, the sphere is above the face but not separating - - /* - * | A - * _ _ _ _ _ _ | _ _ _ - * / / - * | / | / regionA - * |/ _ _ _ _ _|/ _ _ _ - * B/ regionB /C - * / / regionC - */ - - const SHHalfEdgeStructure::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(closestFaceIndex); - const SHVec3& NORMAL = CONVEX.GetNormal(closestFaceIndex); - - const int32_t NUM_VERTICES_ON_FACE = static_cast(FACE.vertexIndices.size()); - - // Find closest point on face - closestPointIndex = 0; - float smallestDist = SHVec3::Dot(CENTER - CONVEX.GetVertex(FACE.vertexIndices[0]), NORMAL); - - for (int32_t i = 1; i < NUM_VERTICES_ON_FACE; ++i) - { - const SHVec3 POINT = CONVEX.GetVertex(FACE.vertexIndices[i]); - const float PROJECTION = SHVec3::Dot(CENTER - POINT, NORMAL); - - if (PROJECTION < smallestDist) - closestPointIndex = i; - } - - const SHVec3 C = CONVEX.GetVertex(FACE.vertexIndices[closestPointIndex]); - const SHVec3 C_TO_CENTER = SPHERE.GetCenter() - C; - - const int32_t INDEX_A = (closestPointIndex + 1) % NUM_VERTICES_ON_FACE; - const int32_t INDEX_B = closestPointIndex == 0 ? NUM_VERTICES_ON_FACE - 1 : closestPointIndex - 1; - - const SHVec3 POINTS[2] = - { - CONVEX.GetVertex(FACE.vertexIndices[INDEX_A]) // A - , CONVEX.GetVertex(FACE.vertexIndices[INDEX_B]) // B - }; - - // To be inside either region A or B, 2 conditions must be satisfied - // 1. Same side as tangent - // 2. Same side as normal from edge to sphere - - // Check in regions A & B - for (int i = 0; i < 2; ++i) - { - const SHVec3 TANGENT = SHVec3::Normalise(POINTS[i] - C); - - float projection = SHVec3::Dot(C_TO_CENTER, TANGENT); - if (projection >= 0.0f) - { - // Check 2nd condition - // Find closest point - const SHVec3 CP = C + projection * TANGENT; - const SHVec3 CP_TO_CENTER = SHVec3::Normalise(C - CP); - - projection = SHVec3::Dot(C_TO_CENTER, CP_TO_CENTER); - if (projection >= 0.0f) - { - // Sphere Within region - manifold.normal = -CP_TO_CENTER; - - SHContact newContact; - newContact.penetration = RADIUS - projection; - newContact.position = CP; - newContact.featurePair.key = 0; - - manifold.contacts[numContacts++] = newContact; - manifold.numContacts = numContacts; - - return true; - } - } - } - - // Check region C (closest point) - { - if (C_TO_CENTER.LengthSquared() < RADIUS * RADIUS) - { - manifold.normal = -SHVec3::Normalise(C_TO_CENTER); - - SHContact newContact; - newContact.penetration = PENETRATION; - newContact.position = C; - newContact.featurePair.key = 0; - - manifold.contacts[numContacts++] = newContact; - manifold.numContacts = numContacts; - - return true; - } - } - - // Region D - if (PENETRATION <= RADIUS) - { - manifold.normal = -NORMAL; - - SHContact newContact; - newContact.penetration = PENETRATION; - newContact.position = SPHERE.GetCenter() - NORMAL * RADIUS; - newContact.featurePair.key = 0; - - manifold.contacts[numContacts++] = newContact; - manifold.numContacts = numContacts; - - return true; - } - - return false; + faceQuery.colliding = true; + return faceQuery; } - bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + int32_t SHCollision::findClosestPoint(const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept { - return SphereVsConvex(manifold, B, A); + // Find closest point on face + int32_t closestPointIndex = -1; + + const SHVec3 CENTER = sphere.GetCenter(); + const float RADIUS = sphere.GetWorldRadius(); + + const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = polyhedron.GetHalfEdgeStructure(); + + + const SHHalfEdgeStructure::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(faceIndex); + const int32_t NUM_VERITICES = static_cast(FACE.vertexIndices.size()); + + float smallestDist = std::numeric_limits::max(); + for (int32_t i = 0; i < NUM_VERITICES; ++i) + { + const SHVec3 POINT = polyhedron.GetVertex(FACE.vertexIndices[i].index); + const float DIST = SHVec3::DistanceSquared(CENTER, POINT); + + if (DIST < smallestDist) + { + smallestDist = DIST; + closestPointIndex = i; + } + } + + return closestPointIndex; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h index b3db1655..773ac4c1 100644 --- a/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h +++ b/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h @@ -19,6 +19,10 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates the data of a physics material for physics simulations. + */ class SH_API SHPhysicsMaterial { public: -- 2.40.1 From 00f8726e465303d1d12e7a139ae443206803fa06 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 02:42:44 +0800 Subject: [PATCH 51/84] Solved edge case for sphere vs convex polyhedron --- Assets/Scenes/PhysicsSandbox.shade | 6 +- .../Narrowphase/SHSphereVsConvex.cpp | 138 +++++++++--------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 4230dcb8..632dd485 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -5,7 +5,7 @@ Components: Transform Component: Translate: {x: 2.72256827, y: 0.501797795, z: -0.0273017883} - Rotate: {x: -1.48352849, y: -4.78713309e-06, z: 0.469859391} + Rotate: {x: 0, y: 0, z: 0.436332315} Scale: {x: 4.61070776, y: 0.99999392, z: 0.999996722} IsActive: true RigidBody Component: @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -2.49145222, y: 6.17996597, z: 0.811235607} + Translate: {x: -2.01111817, y: 7, z: 0.695722342} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -112,7 +112,7 @@ Components: Transform Component: Translate: {x: 0, y: 4.09544182, z: 0} - Rotate: {x: -0, y: 0, z: 0} + Rotate: {x: -0, y: 0, z: -0.436332315} Scale: {x: 4.61071014, y: 0.999995887, z: 1} IsActive: true RigidBody Component: diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index e84bd16b..568d33a3 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -73,6 +73,7 @@ namespace SHADE contact.featurePair.key = 0; // Check if center is inside polyhedron (below the face) + // TODO: Change to a point in polygon test. if (FACE_QUERY.bestDistance < SHMath::EPSILON) { manifold.normal = -POLYHEDRON.GetNormal(FACE_QUERY.closestFace); @@ -116,112 +117,111 @@ namespace SHADE // 2. Same side as adjacent normal // Check in regions A + const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; + const SHVec3 P2 = POLYHEDRON.GetVertex(FACE.vertexIndices[P2_INDEX].index); + + SHVec3 tangent = SHVec3::Normalise(P2 - P1); + + float projection = SHVec3::Dot(P1_TO_CENTER, tangent); + + if (projection >= 0.0f) { - const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; - const SHVec3 P2 = POLYHEDRON.GetVertex(FACE.vertexIndices[P2_INDEX].index); + // Find closest point + const SHVec3 CP = P1 + projection * tangent; - const SHVec3 TANGENT = SHVec3::Normalise(P2 - P1); + // Check 2nd condition + // Get adjacent normal from twin half edge + const int32_t EDGE_INDEX = FACE.vertexIndices[CLOSEST_POINT].edgeIndex; + const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; - float projection = SHVec3::Dot(P1_TO_CENTER, TANGENT); + const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; + const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); if (projection >= 0.0f) { - // Find closest point - const SHVec3 CP = P1 + projection * TANGENT; + // Must be smaller than radius + if (projection >= RADIUS) + return false; - // Check 2nd condition - // Get adjacent normal from twin half edge - const int32_t EDGE_INDEX = FACE.vertexIndices[CLOSEST_POINT].edgeIndex; - const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + const SHVec3 CP_TO_CENTER = CENTER - CP; - const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; - const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); - projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); - if (projection >= 0.0f) - { - // Must be smaller than radius - if (projection >= RADIUS) - return false; + contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); + contact.position = CP; - const SHVec3 CP_TO_CENTER = CENTER - CP; + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; - manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); - - contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); - contact.position = CP; - - manifold.contacts[numContacts++] = contact; - manifold.numContacts = numContacts; - - return true; - } + return true; } } // Check in region B + const int32_t P3_INDEX = CLOSEST_POINT == 0 ? NUM_VERTICES - 1 : CLOSEST_POINT - 1; + const SHVec3 P3 = POLYHEDRON.GetVertex(FACE.vertexIndices[P3_INDEX].index); + + tangent = SHVec3::Normalise(P3 - P1); + + projection = SHVec3::Dot(P1_TO_CENTER, tangent); + + if (projection >= 0.0f) { - const int32_t P3_INDEX = CLOSEST_POINT == 0 ? NUM_VERTICES - 1 : CLOSEST_POINT - 1; - const SHVec3 P3 = POLYHEDRON.GetVertex(FACE.vertexIndices[P3_INDEX].index); + // Find closest point + const SHVec3 CP = P1 + projection * tangent; - const SHVec3 TANGENT = SHVec3::Normalise(P3 - P1); + // Check 2nd condition + // Get adjacent normal from twin half edge + const int32_t EDGE_INDEX = FACE.vertexIndices[P3_INDEX].edgeIndex; + const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; - float projection = SHVec3::Dot(P1_TO_CENTER, TANGENT); + const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; + const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); if (projection >= 0.0f) { - // Find closest point - const SHVec3 CP = P1 + projection * TANGENT; + // Must be smaller than radius + if (projection >= RADIUS) + return false; - // Check 2nd condition - // Get adjacent normal from twin half edge - const int32_t EDGE_INDEX = FACE.vertexIndices[P3_INDEX].edgeIndex; - const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + const SHVec3 CP_TO_CENTER = CENTER - CP; - const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; - const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); - projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); - if (projection >= 0.0f) - { - // Must be smaller than radius - if (projection >= RADIUS) - return false; + contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); + contact.position = CP; - const SHVec3 CP_TO_CENTER = CENTER - CP; + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; - manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); - - contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); - contact.position = CP; - - manifold.contacts[numContacts++] = contact; - manifold.numContacts = numContacts; - - return true; - } + return true; } } - // Either region C or D. Take whichever depth is smaller + // Region C has a negative dot product with any of the tangents. - const float C_PENETRATION = RADIUS - P1_TO_CENTER.Length(); - - if (std::fabs(C_PENETRATION) < RADIUS && std::fabs(C_PENETRATION) < PENETRATION) + projection = SHVec3::Dot(P1_TO_CENTER, tangent); + if (projection < 0) { manifold.normal = -SHVec3::Normalise(P1_TO_CENTER); - contact.penetration = C_PENETRATION; + contact.penetration = RADIUS - P1_TO_CENTER.Length(); contact.position = P1; - } - else - { - manifold.normal = -FACE_NORMAL; - contact.penetration = PENETRATION; - contact.position = CENTER - FACE_NORMAL * RADIUS; + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; + + return true; } + // Region D + manifold.normal = -FACE_NORMAL; + + contact.penetration = PENETRATION; + contact.position = CENTER - FACE_NORMAL * RADIUS; + manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; -- 2.40.1 From 67907b1ca98a4355a8f9708b994be9ed7ca38ab1 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 02:48:02 +0800 Subject: [PATCH 52/84] Replaced twin-edge dependency on sphere vs convex polyhedron --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../Narrowphase/SHSphereVsConvex.cpp | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 632dd485..266447e3 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -2.01111817, y: 7, z: 0.695722342} + Translate: {x: -0.903104782, y: 7, z: -0.782080948} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 568d33a3..4523fc5b 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -130,12 +130,12 @@ namespace SHADE const SHVec3 CP = P1 + projection * tangent; // Check 2nd condition - // Get adjacent normal from twin half edge - const int32_t EDGE_INDEX = FACE.vertexIndices[CLOSEST_POINT].edgeIndex; - const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + // Get adjacent normal from the cross product (tangent x normal) + //const int32_t EDGE_INDEX = FACE.vertexIndices[CLOSEST_POINT].edgeIndex; + //const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; - const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; - const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + //const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; + const SHVec3 ADJ_NORMAL = SHVec3::Cross(tangent, FACE_NORMAL); projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); if (projection >= 0.0f) @@ -172,12 +172,14 @@ namespace SHADE const SHVec3 CP = P1 + projection * tangent; // Check 2nd condition - // Get adjacent normal from twin half edge - const int32_t EDGE_INDEX = FACE.vertexIndices[P3_INDEX].edgeIndex; - const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + // Get adjacent normal from the cross product (normal x tangent) + //const int32_t EDGE_INDEX = FACE.vertexIndices[P3_INDEX].edgeIndex; + //const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; + + //const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; + //const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); + const SHVec3 ADJ_NORMAL = SHVec3::Cross(FACE_NORMAL, tangent); - const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; - const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); if (projection >= 0.0f) -- 2.40.1 From f3c0bdbcfd45872ebbc4aa5666017db2be18ce10 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 03:24:34 +0800 Subject: [PATCH 53/84] Clean up --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../SHConvexPolyhedronCollisionShape.cpp | 24 ++ .../SHConvexPolyhedronCollisionShape.h | 11 +- .../Collision/Narrowphase/SHCollision.h | 1 + .../Narrowphase/SHSphereVsConvex.cpp | 239 ++++++++---------- 5 files changed, 144 insertions(+), 133 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 266447e3..a8730476 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -0.903104782, y: 7, z: -0.782080948} + Translate: {x: -1.96328545, y: 7, z: 0.743723333} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp index db6d3621..51d4e684 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp @@ -97,4 +97,28 @@ namespace SHADE { return halfEdgeStructure; } + + int32_t SHConvexPolyhedronCollisionShape::GetFaceCount() const noexcept + { + return halfEdgeStructure->GetFaceCount(); + } + + int32_t SHConvexPolyhedronCollisionShape::GetHalfEdgeCount() const noexcept + { + return halfEdgeStructure->GetHalfEdgeCount(); + } + + const SHHalfEdgeStructure::Face& SHConvexPolyhedronCollisionShape::GetFace(int index) const + { + // Assume it has already been initialised + return halfEdgeStructure->GetFace(index); + } + + const SHHalfEdgeStructure::HalfEdge& SHConvexPolyhedronCollisionShape::GetHalfEdge(int index) const + { + // Assume it has already been initialised + return halfEdgeStructure->GetHalfEdge(index); + } + + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h index 7a0f6df0..6095cbca 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h @@ -57,9 +57,14 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] const SHHalfEdgeStructure* GetHalfEdgeStructure () const noexcept; - [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; - [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; + [[nodiscard]] const SHHalfEdgeStructure* GetHalfEdgeStructure () const noexcept; + [[nodiscard]] int32_t GetFaceCount () const noexcept; + [[nodiscard]] const SHHalfEdgeStructure::Face& GetFace (int index) const; + [[nodiscard]] int32_t GetHalfEdgeCount () const noexcept; + [[nodiscard]] const SHHalfEdgeStructure::HalfEdge& GetHalfEdge (int index) const; + + [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; + [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; protected: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 942c6919..4db1fc68 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -86,6 +86,7 @@ namespace SHADE static FaceQuery findClosestFace (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept; static int32_t findClosestPoint (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept; + static int32_t findVoronoiRegion (const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; static bool isMinkowskiFace(const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 4523fc5b..9ee6f4b9 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -33,8 +33,6 @@ namespace SHADE const SHVec3 CENTER = SPHERE.GetCenter(); const float RADIUS = SPHERE.GetWorldRadius(); - const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = POLYHEDRON.GetHalfEdgeStructure(); - const FaceQuery FACE_QUERY = findClosestFace(SPHERE, POLYHEDRON); if (!FACE_QUERY.colliding) return false; @@ -60,8 +58,6 @@ namespace SHADE const SHVec3 CENTER = SPHERE.GetCenter(); const float RADIUS = SPHERE.GetWorldRadius(); - const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = POLYHEDRON.GetHalfEdgeStructure(); - const FaceQuery FACE_QUERY = findClosestFace(SPHERE, POLYHEDRON); if (!FACE_QUERY.colliding) return false; @@ -83,147 +79,75 @@ namespace SHADE manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; + return true; } // Find closest face of polygon to circle const int32_t CLOSEST_POINT = findClosestPoint(SPHERE, POLYHEDRON, FACE_QUERY.closestFace); - const SHHalfEdgeStructure::Face& FACE = POLYHEDRON.GetHalfEdgeStructure()->GetFace(FACE_QUERY.closestFace); + const SHHalfEdgeStructure::Face& FACE = POLYHEDRON.GetFace(FACE_QUERY.closestFace); - const SHVec3& FACE_NORMAL = POLYHEDRON.GetNormal(FACE_QUERY.closestFace); - const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); + const SHVec3& FACE_NORMAL = POLYHEDRON.GetNormal(FACE_QUERY.closestFace); + const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); - // Check against voronoi regions of the face to determine the type of the intersection test - // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center - // If none of these are true, the sphere is above the face but not separating - - /* - * | 2 - * _ _ _ _ _ _ | _ _ _ - * / / - * | / regionD | / regionA - * |/ _ _ _ _ _|/ _ _ _ - * 3/ regionB /1 - * / / regionC - * - */ + // Get points and build tangents + const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; + const int32_t P3_INDEX = CLOSEST_POINT == 0 ? NUM_VERTICES - 1 : CLOSEST_POINT - 1; const SHVec3 P1 = POLYHEDRON.GetVertex(FACE.vertexIndices[CLOSEST_POINT].index); - const SHVec3 P1_TO_CENTER = CENTER - P1; - - // To be inside either region A or B, 2 conditions must be satisfied - // 1. Same side as tangent - // 2. Same side as adjacent normal - - // Check in regions A - const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; const SHVec3 P2 = POLYHEDRON.GetVertex(FACE.vertexIndices[P2_INDEX].index); - - SHVec3 tangent = SHVec3::Normalise(P2 - P1); - - float projection = SHVec3::Dot(P1_TO_CENTER, tangent); - - if (projection >= 0.0f) - { - // Find closest point - const SHVec3 CP = P1 + projection * tangent; - - // Check 2nd condition - // Get adjacent normal from the cross product (tangent x normal) - //const int32_t EDGE_INDEX = FACE.vertexIndices[CLOSEST_POINT].edgeIndex; - //const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; - - //const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; - const SHVec3 ADJ_NORMAL = SHVec3::Cross(tangent, FACE_NORMAL); - - projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); - if (projection >= 0.0f) - { - // Must be smaller than radius - if (projection >= RADIUS) - return false; - - const SHVec3 CP_TO_CENTER = CENTER - CP; - - manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); - - contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); - contact.position = CP; - - manifold.contacts[numContacts++] = contact; - manifold.numContacts = numContacts; - - return true; - } - } - - // Check in region B - const int32_t P3_INDEX = CLOSEST_POINT == 0 ? NUM_VERTICES - 1 : CLOSEST_POINT - 1; const SHVec3 P3 = POLYHEDRON.GetVertex(FACE.vertexIndices[P3_INDEX].index); - tangent = SHVec3::Normalise(P3 - P1); + const SHVec3 TANGENT_1 = SHVec3::Normalise(P2 - P1); + const SHVec3 TANGENT_2 = SHVec3::Normalise(P3 - P1); - projection = SHVec3::Dot(P1_TO_CENTER, tangent); + // Get the voronoi region it belongs in + const int32_t REGION = findVoronoiRegion(SPHERE, P1, FACE_NORMAL, TANGENT_1, TANGENT_2); + if (REGION == 0) + return false; - if (projection >= 0.0f) + // Create contact information based on region + + const SHVec3 P1_TO_CENTER = CENTER - P1; + switch (REGION) { - // Find closest point - const SHVec3 CP = P1 + projection * tangent; - - // Check 2nd condition - // Get adjacent normal from the cross product (normal x tangent) - //const int32_t EDGE_INDEX = FACE.vertexIndices[P3_INDEX].edgeIndex; - //const int32_t TWIN_EDGE = HALF_EDGE_STRUCTURE->GetHalfEdge(EDGE_INDEX).twinEdgeIndex; - - //const int32_t ADJ_FACE = HALF_EDGE_STRUCTURE->GetHalfEdge(TWIN_EDGE).faceIndex; - //const SHVec3& ADJ_NORMAL = POLYHEDRON.GetNormal(ADJ_FACE); - const SHVec3 ADJ_NORMAL = SHVec3::Cross(FACE_NORMAL, tangent); - - - projection = SHVec3::Dot(P1_TO_CENTER, ADJ_NORMAL); - if (projection >= 0.0f) + case 1: // Region A + case 2: // Region B { - // Must be smaller than radius - if (projection >= RADIUS) - return false; - + // Find closest point + const SHVec3& TANGENT = REGION == 1 ? TANGENT_1 : TANGENT_2; + const SHVec3 CP = P1 + TANGENT * SHVec3::Dot(P1_TO_CENTER, TANGENT); const SHVec3 CP_TO_CENTER = CENTER - CP; - manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); + manifold.normal = -SHVec3::Normalise(CP_TO_CENTER); contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); - contact.position = CP; + contact.position = CP; - manifold.contacts[numContacts++] = contact; - manifold.numContacts = numContacts; - - return true; + break; } + case 3: // Region C + { + manifold.normal = -SHVec3::Normalise(P1_TO_CENTER); + + contact.penetration = RADIUS - P1_TO_CENTER.Length(); + contact.position = P1; + + break; + } + case 4: // Region D + { + manifold.normal = -FACE_NORMAL; + + contact.penetration = PENETRATION; + contact.position = CENTER - FACE_NORMAL * RADIUS; + + break; + } + default: return false; // Should never happen } - // Region C has a negative dot product with any of the tangents. - - projection = SHVec3::Dot(P1_TO_CENTER, tangent); - if (projection < 0) - { - manifold.normal = -SHVec3::Normalise(P1_TO_CENTER); - - contact.penetration = RADIUS - P1_TO_CENTER.Length(); - contact.position = P1; - - manifold.contacts[numContacts++] = contact; - manifold.numContacts = numContacts; - - return true; - } - - // Region D - manifold.normal = -FACE_NORMAL; - - contact.penetration = PENETRATION; - contact.position = CENTER - FACE_NORMAL * RADIUS; - manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; @@ -246,8 +170,6 @@ namespace SHADE const SHVec3 CENTER = sphere.GetCenter(); const float RADIUS = sphere.GetWorldRadius(); - const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = polyhedron.GetHalfEdgeStructure(); - /* * Test against each face. * @@ -255,9 +177,9 @@ namespace SHADE * 2. Find the signed distance from plane to center of sphere. * 3. Save best distance and face. */ - for (int32_t i = 0; i < HALF_EDGE_STRUCTURE->GetFaceCount(); ++i) + for (int32_t i = 0; i < polyhedron.GetFaceCount(); ++i) { - const SHHalfEdgeStructure::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(i); + const SHHalfEdgeStructure::Face& FACE = polyhedron.GetFace(i); // Build plane equation @@ -291,12 +213,8 @@ namespace SHADE int32_t closestPointIndex = -1; const SHVec3 CENTER = sphere.GetCenter(); - const float RADIUS = sphere.GetWorldRadius(); - - const SHHalfEdgeStructure* HALF_EDGE_STRUCTURE = polyhedron.GetHalfEdgeStructure(); - - const SHHalfEdgeStructure::Face& FACE = HALF_EDGE_STRUCTURE->GetFace(faceIndex); + const SHHalfEdgeStructure::Face& FACE = polyhedron.GetFace(faceIndex); const int32_t NUM_VERITICES = static_cast(FACE.vertexIndices.size()); float smallestDist = std::numeric_limits::max(); @@ -315,4 +233,67 @@ namespace SHADE return closestPointIndex; } + int32_t SHCollision::findVoronoiRegion(const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept + { + static constexpr int NUM_TANGENTS = 2; + + // Check against voronoi regions of the face to determine the type of the intersection test + // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center + // If none of these are true, the sphere is above the face but not separating + + /* + * | 2 + * _ _ _ _ _ _ | _ _ _ + * / / + * | / regionD | / regionA + * |/ _ _ _ _ _|/ _ _ _ + * 3/ regionB /1 + * / / regionC + * + */ + + const SHVec3& CENTER = sphere.GetCenter(); + const float RADIUS = sphere.GetWorldRadius(); + + const SHVec3 TANGENTS [NUM_TANGENTS] { tangent1, tangent2 }; + const SHVec3 ADJACENT_NORMALS [NUM_TANGENTS] { SHVec3::Cross(tangent1, faceNormal), SHVec3::Cross(faceNormal, tangent2) }; + + const SHVec3 FACE_TO_CENTER = CENTER - faceVertex; + + // To be inside either region A or B, 2 conditions must be satisfied + // 1. Same side as tangent + // 2. Same side as adjacent normal + + // Check Region A & B + for (int i = 0; i < NUM_TANGENTS; ++i) + { + float projection = SHVec3::Dot(FACE_TO_CENTER, TANGENTS[i]); + if (projection >= 0.0f) + { + // Find closest point + const SHVec3 CLOSEST_POINT = faceVertex + projection * TANGENTS[i]; + + projection = SHVec3::Dot(FACE_TO_CENTER, ADJACENT_NORMALS[i]); + if (projection >= 0.0f) + { + if (projection > RADIUS) + return 0; + + // Region 1 or 2 ( A or B) + return i + 1; + } + } + } + + // Check Region C + // Face to vertex is in the opposite direction of any tangent. + const float PROJECTION = SHVec3::Dot(FACE_TO_CENTER, tangent1); + if (PROJECTION < 0) + return 3; + + // Belongs in region D by default + return 4; + } + + } // namespace SHADE \ No newline at end of file -- 2.40.1 From 38764e79b31cdcef31f5df8ae4eb2271f264387f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 03:32:59 +0800 Subject: [PATCH 54/84] Added trigger check for sphere vs convex polyhedron --- .../Narrowphase/SHSphereVsConvex.cpp | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 9ee6f4b9..bc1f5cf6 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -33,14 +33,37 @@ namespace SHADE const SHVec3 CENTER = SPHERE.GetCenter(); const float RADIUS = SPHERE.GetWorldRadius(); + // Find closest face const FaceQuery FACE_QUERY = findClosestFace(SPHERE, POLYHEDRON); if (!FACE_QUERY.colliding) return false; + // If center of sphere is inside the polyhedron (below the face) if (FACE_QUERY.bestDistance < SHMath::EPSILON) return true; - return false; + // Find closest face of polygon to circle + const int32_t CLOSEST_POINT = findClosestPoint(SPHERE, POLYHEDRON, FACE_QUERY.closestFace); + + const auto& FACE = POLYHEDRON.GetFace(FACE_QUERY.closestFace); + const SHVec3& FACE_NORMAL = POLYHEDRON.GetNormal(FACE_QUERY.closestFace); + const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); + + // Get points and build tangents + const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; + const int32_t P3_INDEX = CLOSEST_POINT == 0 ? NUM_VERTICES - 1 : CLOSEST_POINT - 1; + + const SHVec3 P1 = POLYHEDRON.GetVertex(FACE.vertexIndices[CLOSEST_POINT].index); + const SHVec3 P2 = POLYHEDRON.GetVertex(FACE.vertexIndices[P2_INDEX].index); + const SHVec3 P3 = POLYHEDRON.GetVertex(FACE.vertexIndices[P3_INDEX].index); + + const SHVec3 TANGENT_1 = SHVec3::Normalise(P2 - P1); + const SHVec3 TANGENT_2 = SHVec3::Normalise(P3 - P1); + + // Get the voronoi region it belongs in + const int32_t REGION = findVoronoiRegion(SPHERE, P1, FACE_NORMAL, TANGENT_1, TANGENT_2); + + return REGION > 0; } bool SHCollision::ConvexVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept @@ -69,13 +92,12 @@ namespace SHADE contact.featurePair.key = 0; // Check if center is inside polyhedron (below the face) - // TODO: Change to a point in polygon test. if (FACE_QUERY.bestDistance < SHMath::EPSILON) { manifold.normal = -POLYHEDRON.GetNormal(FACE_QUERY.closestFace); - contact.penetration = PENETRATION; - contact.position = SPHERE.GetCenter(); + contact.penetration = PENETRATION; + contact.position = SPHERE.GetCenter(); manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; @@ -86,10 +108,9 @@ namespace SHADE // Find closest face of polygon to circle const int32_t CLOSEST_POINT = findClosestPoint(SPHERE, POLYHEDRON, FACE_QUERY.closestFace); - const SHHalfEdgeStructure::Face& FACE = POLYHEDRON.GetFace(FACE_QUERY.closestFace); - - const SHVec3& FACE_NORMAL = POLYHEDRON.GetNormal(FACE_QUERY.closestFace); - const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); + const auto& FACE = POLYHEDRON.GetFace(FACE_QUERY.closestFace); + const SHVec3& FACE_NORMAL = POLYHEDRON.GetNormal(FACE_QUERY.closestFace); + const int32_t NUM_VERTICES = static_cast(FACE.vertexIndices.size()); // Get points and build tangents const int32_t P2_INDEX = (CLOSEST_POINT + 1) % NUM_VERTICES; @@ -238,7 +259,7 @@ namespace SHADE static constexpr int NUM_TANGENTS = 2; // Check against voronoi regions of the face to determine the type of the intersection test - // We have 3 voronoi regions to check: cp -> prev, cp -> next and cp -> center + // We have 3 voronoi regions to check: 1 -> 2, 1 -> 3 and 1 -> center // If none of these are true, the sphere is above the face but not separating /* -- 2.40.1 From 6f55f202b9a65608c6fe3cb82b8113619483e0ad Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 16:53:13 +0800 Subject: [PATCH 55/84] Added planes --- Assets/Scenes/PhysicsSandbox.shade | 2 +- SHADE_Engine/src/Math/Geometry/SHAABB.cpp | 39 ++--- SHADE_Engine/src/Math/Geometry/SHAABB.h | 11 +- SHADE_Engine/src/Math/Geometry/SHBox.cpp | 27 +--- SHADE_Engine/src/Math/Geometry/SHBox.h | 9 +- SHADE_Engine/src/Math/Geometry/SHPlane.cpp | 141 ++++++++++++++++++ SHADE_Engine/src/Math/Geometry/SHPlane.h | 121 +++++++++++++++ SHADE_Engine/src/Math/Geometry/SHShape.cpp | 35 ----- SHADE_Engine/src/Math/Geometry/SHShape.h | 49 +----- SHADE_Engine/src/Math/Geometry/SHSphere.cpp | 40 ++--- SHADE_Engine/src/Math/Geometry/SHSphere.h | 11 +- .../Narrowphase/SHSphereVsConvex.cpp | 9 +- 12 files changed, 320 insertions(+), 174 deletions(-) create mode 100644 SHADE_Engine/src/Math/Geometry/SHPlane.cpp create mode 100644 SHADE_Engine/src/Math/Geometry/SHPlane.h delete mode 100644 SHADE_Engine/src/Math/Geometry/SHShape.cpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index a8730476..95434172 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.96328545, y: 7, z: 0.743723333} + Translate: {x: -1.45715916, y: 7, z: 0.319963396} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp index 30683216..727ea993 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp @@ -26,14 +26,12 @@ namespace SHADE SHAABB::SHAABB() noexcept { - type = Type::AABB; + Extents = SHVec3::One * 0.5f; } SHAABB::SHAABB(const SHVec3& c, const SHVec3& hE) noexcept { - type = Type::AABB; - - Center = c; + Center = c; Extents = hE; } @@ -43,18 +41,14 @@ namespace SHADE if (this == &rhs) return; - type = Type::AABB; - - Center = rhs.Center; - Extents = rhs.Extents; + Center = rhs.Center; + Extents = rhs.Extents; } SHAABB::SHAABB(SHAABB&& rhs) noexcept { - type = Type::AABB; - - Center = rhs.Center; - Extents = rhs.Extents; + Center = rhs.Center; + Extents = rhs.Extents; } /*-----------------------------------------------------------------------------------*/ @@ -63,14 +57,10 @@ namespace SHADE SHAABB& SHAABB::operator=(const SHAABB& rhs) noexcept { - if (rhs.type != Type::AABB) + if (this != &rhs) { - SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") - } - else if (this != &rhs) - { - Center = rhs.Center; - Extents = rhs.Extents; + Center = rhs.Center; + Extents = rhs.Extents; } return *this; @@ -78,15 +68,8 @@ namespace SHADE SHAABB& SHAABB::operator=(SHAABB&& rhs) noexcept { - if (rhs.type != Type::AABB) - { - SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") - } - else - { - Center = rhs.Center; - Extents = rhs.Extents; - } + Center = rhs.Center; + Extents = rhs.Extents; return *this; } diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.h b/SHADE_Engine/src/Math/Geometry/SHAABB.h index 76e0b2b7..e6536fa5 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.h +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.h @@ -14,7 +14,6 @@ // Project Headers #include "SHShape.h" -#include "SH_API.h" namespace SHADE { @@ -22,7 +21,11 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SH_API SHAABB : public SHShape, + /** + * @brief + * Encapsulates a 3D Axis-Aligned Bounding Box. + */ + class SH_API SHAABB : public SHShape, private DirectX::BoundingBox { public: @@ -71,7 +74,7 @@ namespace SHADE void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Member Functions */ /*---------------------------------------------------------------------------------*/ /** @@ -118,7 +121,7 @@ namespace SHADE [[nodiscard]] float SurfaceArea () const noexcept; /*---------------------------------------------------------------------------------*/ - /* Static Function Members */ + /* Static Member Functions */ /*---------------------------------------------------------------------------------*/ /** diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp index 9dacc623..d79f932a 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHBox.cpp @@ -27,13 +27,11 @@ namespace SHADE SHBox::SHBox() noexcept { - type = Type::BOX; + Extents = SHVec3::One * 0.5f; } SHBox::SHBox(const SHVec3& c, const SHVec3& hE, const SHQuaternion& o) noexcept { - type = Type::BOX; - Center = c; Extents = hE; Orientation = o; @@ -45,8 +43,6 @@ namespace SHADE if (this == &rhs) return; - type = Type::BOX; - Center = rhs.Center; Extents = rhs.Extents; Orientation = rhs.Orientation; @@ -54,8 +50,6 @@ namespace SHADE SHBox::SHBox(SHBox&& rhs) noexcept { - type = Type::BOX; - Center = rhs.Center; Extents = rhs.Extents; Orientation = rhs.Orientation; @@ -67,11 +61,7 @@ namespace SHADE 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) + if (this != &rhs) { Center = rhs.Center; Extents = rhs.Extents; @@ -83,16 +73,9 @@ namespace SHADE 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; - } + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; return *this; } diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h index bb1098bc..7815ce2c 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.h +++ b/SHADE_Engine/src/Math/Geometry/SHBox.h @@ -14,7 +14,6 @@ // Project Headers #include "SHShape.h" -#include "SH_API.h" namespace SHADE { @@ -22,6 +21,10 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates a 3D-oriented bounding box. + */ class SH_API SHBox : public SHShape, public DirectX::BoundingOrientedBox { @@ -57,7 +60,7 @@ namespace SHADE [[nodiscard]] std::vector GetVertices () const noexcept; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Member Functions */ /*---------------------------------------------------------------------------------*/ /** @@ -104,7 +107,7 @@ namespace SHADE [[nodiscard]] float SurfaceArea () const noexcept; /*---------------------------------------------------------------------------------*/ - /* Static Function Members */ + /* Static Member Functions */ /*---------------------------------------------------------------------------------*/ /** diff --git a/SHADE_Engine/src/Math/Geometry/SHPlane.cpp b/SHADE_Engine/src/Math/Geometry/SHPlane.cpp new file mode 100644 index 00000000..1ffbfaba --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHPlane.cpp @@ -0,0 +1,141 @@ +/**************************************************************************************** + * \file SHPlane.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a plane. + * + * \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 + +#include + +// Primary Header +#include "SHPlane.h" + +#include "Input/SHInputManager.h" +#include "Math/SHMathHelpers.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPlane::SHPlane() noexcept + : planeEquation { SHVec3::One } + { + planeEquation.w = 0.0f; + } + + SHPlane::SHPlane(const SHVec3& point, const SHVec3& normal) noexcept + { + XMStoreFloat4(&planeEquation, XMPlaneFromPointNormal(point, normal)); + } + + SHPlane::SHPlane(float a, float b, float c, float d) noexcept + : planeEquation { a, b, c, d } + {} + + SHPlane::SHPlane(const SHVec3& normal, float distance) noexcept + : planeEquation { normal } + { + planeEquation.w = distance; + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHPlane::operator==(const SHPlane& rhs) const noexcept + { + return XMPlaneEqual(planeEquation, rhs.planeEquation); + } + + bool SHPlane::operator!=(const SHPlane& rhs) const noexcept + { + return XMPlaneNotEqual(planeEquation, rhs.planeEquation); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3 SHPlane::GetNormal() const noexcept + { + return SHVec3{ planeEquation.x, planeEquation.y, planeEquation.z }; + } + + float SHPlane::GetDistance() const noexcept + { + return planeEquation.w; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPlane::SetNormal(const SHVec3& normal) noexcept + { + planeEquation.x = normal.x; + planeEquation.y = normal.y; + planeEquation.z = normal.z; + } + + void SHPlane::SetDistance(float distance) noexcept + { + planeEquation.w = distance; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHPlane::TestPoint(const SHVec3& point) const noexcept + { + const float DISTANCE = SignedDistance(point); + return SHMath::CompareFloat(DISTANCE, 0.0f); + } + + SHRaycastResult SHPlane::Raycast(const SHRay& ray) const noexcept + { + SHRaycastResult result; + + const SHVec3 N = GetNormal(); + + // Check if ray is parallel to plane + const float N_DOT_D = N.Dot(ray.direction); + if (SHMath::CompareFloat(N_DOT_D, 0.0f)) + { + result.hit = false; + return result; + } + + const float DIST = (planeEquation.w - N.Dot(ray.position)) / N_DOT_D; + if (DIST < 0.0f || !SHMath::CompareFloat(DIST, 0.0f)) + { + result.hit = false; + return result; + } + + result.hit = true; + result.distance = DIST; + result.position = ray.position + ray.direction * DIST; + result.angle = SHVec3::Angle(ray.position, result.position); + + // The normal is either the plane's normal or the reverse if the ray came from below + result.normal = N_DOT_D < 0.0f ? -N : N; + + return result; + } + + float SHPlane::SignedDistance(const SHVec3& point) const noexcept + { + return XMVectorGetX(XMPlaneDotCoord(planeEquation, point)); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHPlane.h b/SHADE_Engine/src/Math/Geometry/SHPlane.h new file mode 100644 index 00000000..581b1c03 --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHPlane.h @@ -0,0 +1,121 @@ +/**************************************************************************************** + * \file SHPlane.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a plane. + * + * \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 "SHShape.h" +#include "Math/Vector/SHVec4.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Encapsulates a 3D plane in point-normal form. + */ + class SH_API SHPlane : public SHShape + { + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + ~SHPlane () override = default; + SHPlane (const SHPlane& rhs) noexcept = default; + SHPlane (SHPlane&& rhs) noexcept = default; + + SHPlane () noexcept; + SHPlane (const SHVec3& point, const SHVec3& normal) noexcept; + SHPlane (float a, float b, float c, float d) noexcept; + SHPlane (const SHVec3& normal, float distance) noexcept; + + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHPlane& operator= (const SHPlane& rhs) noexcept = default; + SHPlane& operator= (SHPlane&& rhs) noexcept = default; + + bool operator== (const SHPlane& rhs) const noexcept; + bool operator!= (const SHPlane& rhs) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHVec3 GetNormal () const noexcept; + [[nodiscard]] float GetDistance () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetNormal (const SHVec3& normal) noexcept; + void SetDistance (float distance) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Checks if a point is on the plane. + * @param point + * The point to check. + * @return + * True if the point is on the plane. + */ + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + + /** + * @brief + * Casts a ray against the plane. + * @param ray + * The ray to cast. + * @return + * The result of the raycast.
+ * See the corresponding header for the contents of the raycast result object. + */ + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + + /** + * @brief + * Gets the signed distance from a point to the plane. + * @param point + * The point to check. + * @return + * The signed distance of the point to a plane.
+ * If the signed distance is negative, the point is behind the plane.
+ * If the signed distance is zero, the point is on the plane.
+ * If the signed distance is positive, the point is in front of the plane.
+ */ + [[nodiscard]] float SignedDistance (const SHVec3& point) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Static Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /* + * TODO: + * Transform plane + * Intersection Tests + */ + + private: + + SHVec4 planeEquation; + }; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.cpp b/SHADE_Engine/src/Math/Geometry/SHShape.cpp deleted file mode 100644 index 2f869029..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHShape.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************************** - * \file SHShape.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a 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 - -// Primary Header -#include "SHShape.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHShape::SHShape() - : type { Type::NONE } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHShape::Type SHShape::GetType() const noexcept - { - return type; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h index 2b644917..7781a5a4 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -11,58 +11,26 @@ #pragma once // Project Headers -#include "SH_API.h" #include "Math/SHRay.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates a base class for any shape. + */ class SH_API SHShape { public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class Type - { - SPHERE - , AABB - , BOX - - , COUNT - , NONE = -1 - }; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - bool isIntersecting; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - virtual ~SHShape () = default; - - SHShape (const SHShape&) = default; - SHShape (SHShape&&) = default; - - SHShape& operator=(const SHShape&) = default; - SHShape& operator=(SHShape&&) = default; - - SHShape(); - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] Type GetType () const noexcept; + virtual ~SHShape () = default; /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -70,12 +38,5 @@ namespace SHADE [[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0; [[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0; - - protected: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - Type type; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp index 7dbc8f41..ab05188b 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHBoundingSphere.cpp + * \file SHSphere.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Implementation for a Bounding Sphere * @@ -26,13 +26,11 @@ namespace SHADE SHSphere::SHSphere() noexcept { - type = Type::SPHERE; + Radius = 0.5f; } SHSphere::SHSphere(const SHVec3& center, float radius) noexcept { - type = Type::SPHERE; - Center = center; Radius = radius; } @@ -42,18 +40,14 @@ namespace SHADE if (this == &rhs) return; - type = Type::SPHERE; - - Center = rhs.Center; - Radius = rhs.Radius; + Center = rhs.Center; + Radius = rhs.Radius; } SHSphere::SHSphere(SHSphere&& rhs) noexcept { - type = Type::SPHERE; - - Center = rhs.Center; - Radius = rhs.Radius; + Center = rhs.Center; + Radius = rhs.Radius; } /*-----------------------------------------------------------------------------------*/ @@ -62,14 +56,10 @@ namespace SHADE SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept { - if (rhs.type != Type::SPHERE) + if (this != &rhs) { - SHLOG_WARNING("Cannot assign a non-sphere to a sphere!") - } - else if (this != &rhs) - { - Center = rhs.Center; - Radius = rhs.Radius; + Center = rhs.Center; + Radius = rhs.Radius; } return *this; @@ -77,15 +67,9 @@ namespace SHADE SHSphere& SHSphere::operator=(SHSphere&& rhs) noexcept { - if (rhs.type != Type::SPHERE) - { - SHLOG_WARNING("Cannot assign a non-sphere to a sphere!") - } - else - { - Center = rhs.Center; - Radius = rhs.Radius; - } + + Center = rhs.Center; + Radius = rhs.Radius; return *this; } diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.h b/SHADE_Engine/src/Math/Geometry/SHSphere.h index 80a21aa4..3c534ac4 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.h +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.h @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHBoundingSphere.h + * \file SHSphere.h * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Interface for a Bounding Sphere. * @@ -14,7 +14,6 @@ // Project Headers #include "SHShape.h" -#include "SH_API.h" namespace SHADE { @@ -22,6 +21,10 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates a 3D Sphere. + */ class SH_API SHSphere : public SHShape, public DirectX::BoundingSphere { @@ -45,7 +48,7 @@ namespace SHADE SHSphere& operator= (SHSphere&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ - /* Function Members */ + /* Member Functions */ /*---------------------------------------------------------------------------------*/ /** @@ -93,7 +96,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ - /* Static Function Members */ + /* Static Member Functions */ /*---------------------------------------------------------------------------------*/ /** diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index bc1f5cf6..3827dc2f 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -15,6 +15,7 @@ #include "SHCollision.h" // Project Headers +#include "Math/Geometry/SHPlane.h" #include "Math/SHMathHelpers.h" #include "Physics/Collision/CollisionShapes/SHCollisionShape.h" #include "Physics/Collision/CollisionShapes/SHBoxCollisionShape.h" @@ -203,13 +204,11 @@ namespace SHADE const SHHalfEdgeStructure::Face& FACE = polyhedron.GetFace(i); // Build plane equation - - const SHVec3 POINT = polyhedron.GetVertex(FACE.vertexIndices[0].index); // use the first vertex to build a plane - const SHVec3& NORMAL = polyhedron.GetNormal(i); - const float D = -SHVec3::Dot(NORMAL, POINT); + // Use first vertex to build the plane + const SHPlane FACE_PLANE { polyhedron.GetVertex(FACE.vertexIndices[0].index), polyhedron.GetNormal(i) }; // Find signed distance of center to plane - const float SIGNED_DIST = SHVec3::Dot(NORMAL, CENTER) + D; + const float SIGNED_DIST = FACE_PLANE.SignedDistance(CENTER); // Early out: // If face is facing away from center, signed dist is negative. -- 2.40.1 From 50de3a8ef07a6acd515ab0292257eb64532a53d6 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 17:15:49 +0800 Subject: [PATCH 56/84] Added some todo comments --- .../Collision/Narrowphase/SHCollision.h | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 4db1fc68..9255a4bc 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -84,21 +84,54 @@ namespace SHADE // Sphere VS Convex - static FaceQuery findClosestFace (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept; - static int32_t findClosestPoint (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept; - static int32_t findVoronoiRegion (const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; + static FaceQuery findClosestFace + ( + const SHSphereCollisionShape& sphere + , const SHConvexPolyhedronCollisionShape& polyhedron - static bool isMinkowskiFace(const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; + ) noexcept; - // TODO: buildMinkowskiFace, queryEdgeDirection, distanceBetweenTwoEdges, + static int32_t findClosestPoint + ( + const SHSphereCollisionShape& sphere + , const SHConvexPolyhedronCollisionShape& polyhedron + , int32_t faceIndex + + ) noexcept; + + static int32_t findVoronoiRegion + ( + const SHSphereCollisionShape& sphere + , const SHVec3& faceVertex + , const SHVec3& faceNormal + , const SHVec3& tangent1 + , const SHVec3& tangent2 + + ) noexcept; + + // Capsule VS Convex + + // TODO: Capsule VS Convex uses the same gauss map optimisation as convex vs convex + + // Convex VS Convex + + static bool isMinkowskiFace + ( + const SHVec3& a + , const SHVec3& b + , const SHVec3& c + , const SHVec3& d + + ) noexcept; /* * TODO: - * static FaceQuery queryFaceDirections (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; - * static EdgeQuery queryEdgeDirections (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; - * static bool buildMinkowskiFace (const SHHalfEdge& edgeA, const SHHalfEdge& edgeB) noexcept; - * static float distanceBetweenEdges(const SHHalfEdge& edgeA, const SHHalfEdge& edgeB, SHCollisionShape& poly) noexcept; - * static uint32_t clip + * static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + * static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + * static bool buildMinkowskiFace (const SHConvexPolyhedron::HalfEdge& edgeA, const SHConvexPolyhedron::HalfEdge& edgeB) noexcept; + * static float distanceBetweenEdges(const SHConvexPolyhedron::HalfEdge& edgeA, const SHConvexPolyhedron::HalfEdge& edgeB, SHConvexPolyhedron& poly) noexcept; + * static int32_t findIncidentFace (SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; + * static uint32_t clip [sutherland-hodgemann clipping] * * ! References * https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf -- 2.40.1 From 7a92c2c86f09ed57abd980f1218962f070c7afb7 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 17:23:06 +0800 Subject: [PATCH 57/84] Reverted a change --- .../Collision/Narrowphase/SHCollision.h | 36 +++---------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 9255a4bc..14ff5509 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -84,30 +84,9 @@ namespace SHADE // Sphere VS Convex - static FaceQuery findClosestFace - ( - const SHSphereCollisionShape& sphere - , const SHConvexPolyhedronCollisionShape& polyhedron - - ) noexcept; - - static int32_t findClosestPoint - ( - const SHSphereCollisionShape& sphere - , const SHConvexPolyhedronCollisionShape& polyhedron - , int32_t faceIndex - - ) noexcept; - - static int32_t findVoronoiRegion - ( - const SHSphereCollisionShape& sphere - , const SHVec3& faceVertex - , const SHVec3& faceNormal - , const SHVec3& tangent1 - , const SHVec3& tangent2 - - ) noexcept; + static FaceQuery findClosestFace (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept; + static int32_t findClosestPoint (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept; + static int32_t findVoronoiRegion (const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; // Capsule VS Convex @@ -115,14 +94,7 @@ namespace SHADE // Convex VS Convex - static bool isMinkowskiFace - ( - const SHVec3& a - , const SHVec3& b - , const SHVec3& c - , const SHVec3& d - - ) noexcept; + static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; /* * TODO: -- 2.40.1 From ddfbc71400d176e14fd6d57d4222620ae04e8a82 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 19:39:16 +0800 Subject: [PATCH 58/84] Added implementation for raycasting into the collision space --- SHADE_Engine/src/Math/Geometry/SHAABB.cpp | 2 + SHADE_Engine/src/Math/Geometry/SHBox.cpp | 2 + SHADE_Engine/src/Math/Geometry/SHSphere.cpp | 2 + .../Broadphase/SHDynamicAABBTree.cpp | 28 ++++ .../CollisionShapes/SHCollisionShape.h | 9 +- .../Physics/Collision/SHCollisionSpace.cpp | 157 ++++++++++++++++++ .../src/Physics/Collision/SHCollisionSpace.h | 93 ++++++++++- 7 files changed, 281 insertions(+), 12 deletions(-) diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp index 727ea993..f5d9fd60 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.cpp @@ -159,6 +159,8 @@ namespace SHADE { result.position = ray.position + ray.direction * result.distance; result.angle = SHVec3::Angle(ray.position, result.position); + + // TODO: Compute normal } return result; diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp index d79f932a..bcdb7324 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBox.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHBox.cpp @@ -111,6 +111,8 @@ namespace SHADE { result.position = ray.position + ray.direction * result.distance; result.angle = SHVec3::Angle(ray.position, result.position); + + // TODO: Compute Normal } return result; diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp index ab05188b..9d7a7c68 100644 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp @@ -92,6 +92,8 @@ namespace SHADE { result.position = ray.position + ray.direction * result.distance; result.angle = SHVec3::Angle(ray.position, result.position); + + // TODO: Compute Normal } return result; diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index 127494cb..dc87d706 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -249,9 +249,37 @@ namespace SHADE const std::vector& SHAABBTree::Query(const SHRay& ray, float distance) const noexcept { static std::vector potentialHits; + static std::stack nodeIndices; potentialHits.clear(); + nodeIndices.push(root); + while (!nodeIndices.empty()) + { + const int32_t INDEX = nodeIndices.top(); + nodeIndices.pop(); + + if (INDEX == NULL_NODE) + continue; + + const Node& NODE = nodes[INDEX]; + + const auto& RESULT = NODE.AABB.Raycast(ray); + if (!RESULT || RESULT.distance > distance) + continue; + + if (isLeaf(INDEX)) + { + potentialHits.emplace_back(NODE.id); + } + else + { + // Non-leaf nodes need to be traversed further + nodeIndices.push(NODE.left); + nodeIndices.push(NODE.right); + } + } + return potentialHits; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 0a320444..729eecf7 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -19,6 +19,7 @@ #include "SHCollisionShapeID.h" #include "Math/Geometry/SHAABB.h" #include "Math/Transform/SHTransform.h" +#include "Physics/Collision/SHPhysicsRaycastResult.h" namespace SHADE { @@ -128,10 +129,10 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - virtual void ComputeTransforms () noexcept = 0; - [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; - [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; - [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; + virtual void ComputeTransforms () noexcept = 0; + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; + [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp index ab4520ee..cbca890e 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -160,6 +160,163 @@ namespace SHADE contactManager->Update(); } + const SHCollisionSpace::RaycastHits& SHCollisionSpace::Raycast(const SHRay& ray, float distance, uint16_t layer) noexcept + { + raycastHits.clear(); + + const auto& POTENTIAL_HITS = broadphase.Query(ray, distance); + if (POTENTIAL_HITS.empty()) + return raycastHits; + + // Test potential hits individually + // Cull entities that are on different layers + for (auto& shapeID : POTENTIAL_HITS) + { + // Get shape + const EntityID EID = shapeID.GetEntityID(); + const uint32_t IDX = shapeID.GetShapeIndex(); + + const auto* COLLIDER = colliders.find(EID)->second; + const auto* SHAPE = COLLIDER->GetCollisionShape(IDX); + + // Cull by layer + const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & layer; + if (!LAYER_MATCH) + continue; + + // Well this is awkward...I honestly don't have the mental capacity to solve this oversight right now. + // Cast the underlying shape to raycast. Convex hulls do not have an inherited raycast function + + SHRaycastResult result; + switch (SHAPE->GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + result = dynamic_cast(SHAPE)->Raycast(ray); + break; + } + case SHCollisionShape::Type::BOX: + { + result = dynamic_cast(SHAPE)->Raycast(ray); + break; + } + case SHCollisionShape::Type::CAPSULE: + { + // TODO + break; + } + default: break; + } + + // If distance is greater than specified, skip this result + if (!result || result.distance > distance) + continue; + + SHPhysicsRaycastResult physicsResult; + physicsResult.hit = result.hit; + physicsResult.distance = result.distance; + physicsResult.angle = result.angle; + physicsResult.position = result.position; + physicsResult.normal = result.normal; + physicsResult.entityHit = EID; + physicsResult.shapeIndex = IDX; + + raycastHits.emplace_back(physicsResult); + } + + // Sort by distance + std::ranges::sort(raycastHits.begin(), raycastHits.end(), [](const SHPhysicsRaycastResult& lhs, const SHPhysicsRaycastResult& rhs) + { + return lhs.distance < rhs.distance; + }); + + return raycastHits; + } + + const SHCollisionSpace::RaycastHits& SHCollisionSpace::Linecast(const SHVec3& start, const SHVec3& end, uint16_t layer) noexcept + { + // Create bounded ray and reuse the raycast function + const SHRay BOUNDED_RAY{ start, SHVec3::Normalise(end - start) }; + const float DISTANCE = SHVec3::Distance(end, start); + + return Raycast(BOUNDED_RAY, DISTANCE, layer); + } + + const SHCollisionSpace::RaycastHits& SHCollisionSpace::ColliderRaycast(EntityID colliderEID, const SHRay& ray, float distance, uint16_t layer) noexcept + { + raycastHits.clear(); + + const auto& POTENTIAL_HITS = broadphase.Query(ray, distance); + if (POTENTIAL_HITS.empty()) + return raycastHits; + + // Test potential hits individually + // Cull entities that are on different layers + for (auto& shapeID : POTENTIAL_HITS) + { + // Get shape + const EntityID EID = shapeID.GetEntityID(); + const auto* COLLIDER = colliders.find(EID)->second; + // Cull any shapes on the same entity + if (EID == colliderEID) + continue; + + const uint32_t IDX = shapeID.GetShapeIndex(); + const auto* SHAPE = COLLIDER->GetCollisionShape(IDX); + + // Cull by layer + const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & layer; + if (!LAYER_MATCH) + continue; + + // Well this is awkward...I honestly don't have the mental capacity to solve this oversight right now. + // Cast the underlying shape to raycast. Convex hulls do not have an inherited raycast function + + SHRaycastResult result; + switch (SHAPE->GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + result = dynamic_cast(SHAPE)->Raycast(ray); + break; + } + case SHCollisionShape::Type::BOX: + { + result = dynamic_cast(SHAPE)->Raycast(ray); + break; + } + case SHCollisionShape::Type::CAPSULE: + { + // TODO + break; + } + default: break; + } + + // If distance is greater than specified, skip this result + if (!result || result.distance > distance) + continue; + + SHPhysicsRaycastResult physicsResult; + physicsResult.hit = result.hit; + physicsResult.distance = result.distance; + physicsResult.angle = result.angle; + physicsResult.position = result.position; + physicsResult.normal = result.normal; + physicsResult.entityHit = EID; + physicsResult.shapeIndex = IDX; + + raycastHits.emplace_back(physicsResult); + } + + // Sort by distance + std::ranges::sort(raycastHits.begin(), raycastHits.end(), [](const SHPhysicsRaycastResult& lhs, const SHPhysicsRaycastResult& rhs) + { + return lhs.distance < rhs.distance; + }); + + return raycastHits; + } /*-----------------------------------------------------------------------------------*/ /* Private Member Functions Definitions */ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h index d89404dd..9d52a140 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h @@ -15,9 +15,10 @@ // Project Headers #include "Broadphase/SHDynamicAABBTree.h" -#include "Contacts/SHCollisionEvents.h" #include "Physics/Dynamics/SHContactManager.h" #include "SHCollider.h" +#include "SHPhysicsRaycastResult.h" +#include "CollisionTags/SHCollisionTags.h" namespace SHADE { @@ -33,6 +34,12 @@ namespace SHADE class SH_API SHCollisionSpace { public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using RaycastHits = std::vector; + /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ @@ -63,7 +70,7 @@ namespace SHADE * @param collider * A collider to add. Duplicates will be ignored. */ - void AddCollider (SHCollider* collider) noexcept; + void AddCollider (SHCollider* collider) noexcept; /** * @brief @@ -72,21 +79,87 @@ namespace SHADE * @param collider * A collider to remove. If a reference to it doesn't exist, it will be ignored. */ - void RemoveCollider (SHCollider* collider) noexcept; + void RemoveCollider (SHCollider* collider) noexcept; /** * @brief * Invoke this method to update the broadphase of colliders that have been moved since * the last frame. */ - void UpdateBroadphase () noexcept; + void UpdateBroadphase () noexcept; /** * @brief * Detects collisions between all colliders. Results are sent to the attached contact * manager for resolution. */ - void DetectCollisions () noexcept; + void DetectCollisions () noexcept; + + /** + * @brief + * Casts a ray into the collision space. + * @param ray + * The ray to cast. The direction of the ray must be normalised. + * @param distance + * The distance to cast the ray. Defaults to infinity. + * @param layer + * The layer(s) the ray is casting on. Defaults to all layers. + * @return + * A container of all the objects the raycast hit, ordered by distance.
+ * The first object in the container is the first object hit etc. + */ + [[nodiscard]] const RaycastHits& Raycast + ( + const SHRay& ray + , float distance = std::numeric_limits::infinity() + , uint16_t layer = static_cast(SHCollisionTag::Layer::ALL) + ) noexcept; + + /** + * @brief + * Casts a bounded ray into the collision space. + * @param start + * The origin of the ray. + * @param end + * The end of the ray. + * @param layer + * The layer(s) the ray is casting on. Defaults to all layers. + * @return + * A container of all the objects the raycast hit, ordered by distance.
+ * The first object in the container is the first object hit etc. + */ + [[nodiscard]] const RaycastHits& Linecast + ( + const SHVec3& start + , const SHVec3& end + , uint16_t layer = static_cast(SHCollisionTag::Layer::ALL) + ) noexcept; + + /** + * @brief + * Casts a ray into the collision space from a collider's position.
+ * The collider and all it's shapes will be ignored. + * @param colliderEID + * The entityID of the collider to cast from. + * @param ray + * The ray to cast.
+ * The position of the ray is the position offset from the collider's position.
+ * The direction of the ray must be normalised. + * @param distance + * The distance to cast the ray. Defaults to infinity. + * @param layer + * The layer(s) the ray is casting on. Defaults to all layers. + * @return + * A container of all the objects the raycast hit, ordered by distance.
+ * The first object in the container is the first object hit etc. + */ + [[nodiscard]] const RaycastHits& ColliderRaycast + ( + EntityID colliderEID + , const SHRay& ray + , float distance = std::numeric_limits::infinity() + , uint16_t layer = static_cast(SHCollisionTag::Layer::ALL) + ) noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -111,20 +184,24 @@ namespace SHADE Colliders colliders; NarrowphaseBatch narrowphaseBatch; + RaycastHits raycastHits; // Reusable container for raycast results + SHAABBTree broadphase; + + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ // Broadphase helpers - void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; + void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; // Narrowphase helpers - void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; - void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; + void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; + void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; }; -- 2.40.1 From 58a44997b2dd50a63e5fc57f6e1a0123110eb417 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 2 Jan 2023 22:31:48 +0800 Subject: [PATCH 59/84] Reworked raycasting on engine side. Re-added raycasting to scripting --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../Collision/Narrowphase/SHCollision.h | 24 +- .../Narrowphase/SHSphereVsConvex.cpp | 22 +- .../Physics/Collision/SHCollisionSpace.cpp | 160 +++------- .../src/Physics/Collision/SHCollisionSpace.h | 126 ++++---- .../src/Physics/System/SHPhysicsSystem.cpp | 20 ++ .../src/Physics/System/SHPhysicsSystem.h | 28 ++ .../System/SHPhysicsSystemInterface.cpp | 12 + .../Physics/System/SHPhysicsSystemInterface.h | 13 +- SHADE_Managed/src/Components/Collider.cxx | 34 +- SHADE_Managed/src/Components/Collider.hxx | 25 +- SHADE_Managed/src/Physics/Physics.cxx | 293 ++++++++++++++++-- SHADE_Managed/src/Physics/Physics.hxx | 114 +++++-- SHADE_Managed/src/Utility/Convert.cxx | 33 ++ SHADE_Managed/src/Utility/Convert.hxx | 14 + 15 files changed, 627 insertions(+), 293 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 95434172..b07549cc 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.45715916, y: 7, z: 0.319963396} + Translate: {x: -1.45715916, y: 7, z: 0.64831841} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 14ff5509..0c65a94f 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -84,9 +84,27 @@ namespace SHADE // Sphere VS Convex - static FaceQuery findClosestFace (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept; - static int32_t findClosestPoint (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept; - static int32_t findVoronoiRegion (const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; + static FaceQuery findClosestFace + ( + const SHSphereCollisionShape& sphere + , const SHConvexPolyhedronCollisionShape& polyhedron + ) noexcept; + + static int32_t findClosestPoint + ( + const SHSphereCollisionShape& sphere + , const SHConvexPolyhedronCollisionShape& polyhedron + , int32_t faceIndex + ) noexcept; + + static int32_t findVoronoiRegion + ( + const SHSphereCollisionShape& sphere + , const SHVec3& faceVertex + , const SHVec3& faceNormal + , const SHVec3& tangent1 + , const SHVec3& tangent2 + ) noexcept; // Capsule VS Convex diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 3827dc2f..8245d672 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -185,7 +185,11 @@ namespace SHADE /* Private Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollision::FaceQuery SHCollision::findClosestFace(const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept + SHCollision::FaceQuery SHCollision::findClosestFace + ( + const SHSphereCollisionShape& sphere + , const SHConvexPolyhedronCollisionShape& polyhedron + ) noexcept { FaceQuery faceQuery; @@ -227,7 +231,12 @@ namespace SHADE return faceQuery; } - int32_t SHCollision::findClosestPoint(const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept + int32_t SHCollision::findClosestPoint + ( + const SHSphereCollisionShape& sphere + , const SHConvexPolyhedronCollisionShape& polyhedron + , int32_t faceIndex + ) noexcept { // Find closest point on face int32_t closestPointIndex = -1; @@ -253,7 +262,14 @@ namespace SHADE return closestPointIndex; } - int32_t SHCollision::findVoronoiRegion(const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept + int32_t SHCollision::findVoronoiRegion + ( + const SHSphereCollisionShape& sphere + , const SHVec3& faceVertex + , const SHVec3& faceNormal + , const SHVec3& tangent1 + , const SHVec3& tangent2 + ) noexcept { static constexpr int NUM_TANGENTS = 2; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp index cbca890e..4dcc7cb7 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -160,44 +160,53 @@ namespace SHADE contactManager->Update(); } - const SHCollisionSpace::RaycastHits& SHCollisionSpace::Raycast(const SHRay& ray, float distance, uint16_t layer) noexcept + const SHCollisionSpace::RaycastResults& SHCollisionSpace::Raycast(const RaycastInfo& info) noexcept { - raycastHits.clear(); + static RaycastResults results; + results.clear(); + + const bool FILTER_COLLIDER = info.colliderEntityID.has_value(); + + // Cast ray into the broadphase scene + const auto& POTENTIAL_HITS = broadphase.Query(info.ray, info.distance); - const auto& POTENTIAL_HITS = broadphase.Query(ray, distance); if (POTENTIAL_HITS.empty()) - return raycastHits; + return results; - // Test potential hits individually - // Cull entities that are on different layers - for (auto& shapeID : POTENTIAL_HITS) + // Iterate through all potential hits + const int NUM_HITS = static_cast(POTENTIAL_HITS.size()); + for (const int i : std::ranges::views::iota(0, NUM_HITS)) { + const auto HIT_ID = POTENTIAL_HITS[i]; + + const EntityID EID = HIT_ID.GetEntityID(); + + if (FILTER_COLLIDER && EID == info.colliderEntityID.value()) + continue; + // Get shape - const EntityID EID = shapeID.GetEntityID(); - const uint32_t IDX = shapeID.GetShapeIndex(); + const uint32_t IDX = HIT_ID.GetShapeIndex(); + const auto* SHAPE = colliders.find(EID)->second->GetCollisionShape(IDX); - const auto* COLLIDER = colliders.find(EID)->second; - const auto* SHAPE = COLLIDER->GetCollisionShape(IDX); - - // Cull by layer - const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & layer; + // Filter the layers + const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & info.layers; if (!LAYER_MATCH) continue; - // Well this is awkward...I honestly don't have the mental capacity to solve this oversight right now. - // Cast the underlying shape to raycast. Convex hulls do not have an inherited raycast function + // We cast to the underlying shape. THis is done because a convex hull will not have an inherited raycast method. + // Kinda awkward oversight...oops - SHRaycastResult result; + SHRaycastResult baseResult; switch (SHAPE->GetType()) { case SHCollisionShape::Type::SPHERE: { - result = dynamic_cast(SHAPE)->Raycast(ray); + baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); break; } case SHCollisionShape::Type::BOX: { - result = dynamic_cast(SHAPE)->Raycast(ray); + baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); break; } case SHCollisionShape::Type::CAPSULE: @@ -205,118 +214,25 @@ namespace SHADE // TODO break; } - default: break; + default: continue; // Redundant case } - // If distance is greater than specified, skip this result - if (!result || result.distance > distance) + if (!baseResult || baseResult.distance > info.distance) continue; - SHPhysicsRaycastResult physicsResult; - physicsResult.hit = result.hit; - physicsResult.distance = result.distance; - physicsResult.angle = result.angle; - physicsResult.position = result.position; - physicsResult.normal = result.normal; - physicsResult.entityHit = EID; - physicsResult.shapeIndex = IDX; + // Copy to a physics raycast result + SHPhysicsRaycastResult result; + memcpy_s(&result, sizeof(SHRaycastResult), &baseResult, sizeof(SHRaycastResult)); - raycastHits.emplace_back(physicsResult); + result.entityHit = EID; + result.shapeIndex = IDX; + + results.emplace_back(result); } - // Sort by distance - std::ranges::sort(raycastHits.begin(), raycastHits.end(), [](const SHPhysicsRaycastResult& lhs, const SHPhysicsRaycastResult& rhs) - { - return lhs.distance < rhs.distance; - }); - - return raycastHits; + return results; } - const SHCollisionSpace::RaycastHits& SHCollisionSpace::Linecast(const SHVec3& start, const SHVec3& end, uint16_t layer) noexcept - { - // Create bounded ray and reuse the raycast function - const SHRay BOUNDED_RAY{ start, SHVec3::Normalise(end - start) }; - const float DISTANCE = SHVec3::Distance(end, start); - - return Raycast(BOUNDED_RAY, DISTANCE, layer); - } - - const SHCollisionSpace::RaycastHits& SHCollisionSpace::ColliderRaycast(EntityID colliderEID, const SHRay& ray, float distance, uint16_t layer) noexcept - { - raycastHits.clear(); - - const auto& POTENTIAL_HITS = broadphase.Query(ray, distance); - if (POTENTIAL_HITS.empty()) - return raycastHits; - - // Test potential hits individually - // Cull entities that are on different layers - for (auto& shapeID : POTENTIAL_HITS) - { - // Get shape - const EntityID EID = shapeID.GetEntityID(); - const auto* COLLIDER = colliders.find(EID)->second; - // Cull any shapes on the same entity - if (EID == colliderEID) - continue; - - const uint32_t IDX = shapeID.GetShapeIndex(); - const auto* SHAPE = COLLIDER->GetCollisionShape(IDX); - - // Cull by layer - const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & layer; - if (!LAYER_MATCH) - continue; - - // Well this is awkward...I honestly don't have the mental capacity to solve this oversight right now. - // Cast the underlying shape to raycast. Convex hulls do not have an inherited raycast function - - SHRaycastResult result; - switch (SHAPE->GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - result = dynamic_cast(SHAPE)->Raycast(ray); - break; - } - case SHCollisionShape::Type::BOX: - { - result = dynamic_cast(SHAPE)->Raycast(ray); - break; - } - case SHCollisionShape::Type::CAPSULE: - { - // TODO - break; - } - default: break; - } - - // If distance is greater than specified, skip this result - if (!result || result.distance > distance) - continue; - - SHPhysicsRaycastResult physicsResult; - physicsResult.hit = result.hit; - physicsResult.distance = result.distance; - physicsResult.angle = result.angle; - physicsResult.position = result.position; - physicsResult.normal = result.normal; - physicsResult.entityHit = EID; - physicsResult.shapeIndex = IDX; - - raycastHits.emplace_back(physicsResult); - } - - // Sort by distance - std::ranges::sort(raycastHits.begin(), raycastHits.end(), [](const SHPhysicsRaycastResult& lhs, const SHPhysicsRaycastResult& rhs) - { - return lhs.distance < rhs.distance; - }); - - return raycastHits; - } /*-----------------------------------------------------------------------------------*/ /* Private Member Functions Definitions */ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h index 9d52a140..8607cf45 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h @@ -13,12 +13,15 @@ #pragma once +#include + // Project Headers #include "Broadphase/SHDynamicAABBTree.h" #include "Physics/Dynamics/SHContactManager.h" #include "SHCollider.h" #include "SHPhysicsRaycastResult.h" #include "CollisionTags/SHCollisionTags.h" +#include "CollisionTags/SHCollisionTags.h" namespace SHADE { @@ -38,7 +41,52 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using RaycastHits = std::vector; + /** + * @brief + * Contains information to cast a ray into the collision space. + * The collider entityID and shape index is optional. + */ + struct RaycastInfo + { + private: + /*-------------------------------------------------------------------------------*/ + /* Friends */ + /*-------------------------------------------------------------------------------*/ + + friend class SHCollisionSpace; + + public: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + bool continuous = false; + uint16_t layers = static_cast(SHCollisionTag::Layer::ALL); + float distance = std::numeric_limits::infinity(); + SHRay ray; + + /*-------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*-------------------------------------------------------------------------------*/ + + /** + * @brief + * Sets the collider ID for the raycast. Setting this specifies that the ray + * should ignore this collider. + * @param eid + * The entity ID of the collider. + */ + void SetColliderID(EntityID eid) noexcept { colliderEntityID = eid; } + + private: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + std::optional colliderEntityID; + }; + + using RaycastResults = std::vector; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -98,68 +146,13 @@ namespace SHADE /** * @brief * Casts a ray into the collision space. - * @param ray - * The ray to cast. The direction of the ray must be normalised. - * @param distance - * The distance to cast the ray. Defaults to infinity. - * @param layer - * The layer(s) the ray is casting on. Defaults to all layers. + * @param info + * Contains the information for the raycast. * @return - * A container of all the objects the raycast hit, ordered by distance.
- * The first object in the container is the first object hit etc. + * A container of the objects hit by the ray. If nothing was hit, the container + * will be empty. */ - [[nodiscard]] const RaycastHits& Raycast - ( - const SHRay& ray - , float distance = std::numeric_limits::infinity() - , uint16_t layer = static_cast(SHCollisionTag::Layer::ALL) - ) noexcept; - - /** - * @brief - * Casts a bounded ray into the collision space. - * @param start - * The origin of the ray. - * @param end - * The end of the ray. - * @param layer - * The layer(s) the ray is casting on. Defaults to all layers. - * @return - * A container of all the objects the raycast hit, ordered by distance.
- * The first object in the container is the first object hit etc. - */ - [[nodiscard]] const RaycastHits& Linecast - ( - const SHVec3& start - , const SHVec3& end - , uint16_t layer = static_cast(SHCollisionTag::Layer::ALL) - ) noexcept; - - /** - * @brief - * Casts a ray into the collision space from a collider's position.
- * The collider and all it's shapes will be ignored. - * @param colliderEID - * The entityID of the collider to cast from. - * @param ray - * The ray to cast.
- * The position of the ray is the position offset from the collider's position.
- * The direction of the ray must be normalised. - * @param distance - * The distance to cast the ray. Defaults to infinity. - * @param layer - * The layer(s) the ray is casting on. Defaults to all layers. - * @return - * A container of all the objects the raycast hit, ordered by distance.
- * The first object in the container is the first object hit etc. - */ - [[nodiscard]] const RaycastHits& ColliderRaycast - ( - EntityID colliderEID - , const SHRay& ray - , float distance = std::numeric_limits::infinity() - , uint16_t layer = static_cast(SHCollisionTag::Layer::ALL) - ) noexcept; + [[nodiscard]] const RaycastResults& Raycast(const RaycastInfo& info) noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -184,25 +177,20 @@ namespace SHADE Colliders colliders; NarrowphaseBatch narrowphaseBatch; - RaycastHits raycastHits; // Reusable container for raycast results - SHAABBTree broadphase; - - /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ // Broadphase helpers - void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; + void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; // Narrowphase helpers - void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; - void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; - + void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; + void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 508c19ad..f9e7a3cd 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -19,6 +19,7 @@ #include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Editor/SHEditor.h" +#include "Physics/Collision/SHCollisionSpace.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Physics/Interface/SHColliderComponent.h" #include "Scripting/SHScriptEngine.h" @@ -189,6 +190,25 @@ namespace SHADE } } + const std::vector& SHPhysicsSystem::Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept + { + auto& results = collisionSpace->Raycast(info); + + // Load start and end points into the container for debug drawing + #ifdef SHEDITOR + + SHVec3 endPos = info.ray.position + info.ray.direction * SHRay::MAX_RAYCAST_DIST; + + if (!results.empty()) + endPos = results.back().position; + + raycastHits.emplace_back(info.ray.position, endPos); + + #endif + + return results; + } + /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index c7dff6c6..712727ec 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -76,8 +76,25 @@ namespace SHADE */ void Init() override; void Exit() override; + + /** + * @brief + * Forces the world to take a single step. Interpolation of bodies cannot be done when + * forcing an update. + */ void ForceUpdate(); + /** + * @brief + * Casts a ray into the collision space. + * @param info + * Contains the information for the raycast. + * @return + * A container of the objects hit by the ray. If nothing was hit, the container + * will be empty. + */ + [[nodiscard]] const std::vector& Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept; + /*---------------------------------------------------------------------------------*/ /* System Routines */ /*---------------------------------------------------------------------------------*/ @@ -129,6 +146,12 @@ namespace SHADE using EventFunctionPair = std::pair; + struct RaycastHit + { + SHVec3 start; + SHVec3 end; + }; + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ @@ -149,6 +172,11 @@ namespace SHADE SHCollisionSpace* collisionSpace; SHPhysicsObjectManager physicsObjectManager; + // For the debug drawer to draw rays + #ifdef SHEDITOR + std::vector raycastHits; + #endif + /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index f72eb271..b6ed9d56 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -67,4 +67,16 @@ namespace SHADE return 0.0; } + const std::vector& SHPhysicsSystemInterface::Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept + { + static std::vector emptyVec; + + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->Raycast(info); + + SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead."); + return emptyVec; + } + } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index e6103e87..8a1f6be8 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -14,6 +14,7 @@ of DigiPen Institute of Technology is prohibited. // Project Headers #include "ECS_Base/Entity/SHEntity.h" +#include "Physics/Collision/SHCollisionSpace.h" #include "Physics/Collision/Contacts/SHCollisionEvents.h" @@ -26,6 +27,7 @@ namespace SHADE class SHVec3; struct SHRay; struct SHPhysicsRaycastResult; + struct SHCollisionSpace::RaycastInfo; /*-----------------------------------------------------------------------------------*/ @@ -47,9 +49,12 @@ namespace SHADE /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; - [[nodiscard]] static double GetFixedDT () noexcept; - [[nodiscard]] static int GetFixedUpdateRate () noexcept; + [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; + [[nodiscard]] static double GetFixedDT () noexcept; + [[nodiscard]] static int GetFixedUpdateRate () noexcept; + [[nodiscard]] static const std::vector& Raycast (const SHCollisionSpace::RaycastInfo& info) noexcept; + + }; } diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 79140d2b..9ed46289 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -128,39 +128,19 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 BoxCollider::Center::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetCenter()); - return Vector3::Zero; - } - void BoxCollider::Center::set(Vector3 value) - { - //getNativeCollisionShape().SetCenter(Convert::ToNative(value)); + return Convert::ToCLI(getNativeCollisionShape().GetCenter()); } Vector3 BoxCollider::HalfExtents::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetExtents()); - return Vector3::Zero; + return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); } void BoxCollider::HalfExtents::set(Vector3 value) { - //getNativeCollisionShape().SetExtents(Convert::ToNative(value)); + getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); } - Vector3 BoxCollider::Min::get() + Quaternion BoxCollider::Orientation::get() { - //return Convert::ToCLI(getNativeCollisionShape().GetMin()); - return Vector3::Zero; - } - void BoxCollider::Min::set(Vector3 value) - { - //getNativeCollisionShape().SetMin(Convert::ToNative(value)); - } - Vector3 BoxCollider::Max::get() - { - //return Convert::ToCLI(getNativeCollisionShape().GetMax()); - return Vector3::Zero; - } - void BoxCollider::Max::set(Vector3 value) - { - //getNativeCollisionShape().SetMax(Convert::ToNative(value)); + return Convert::ToCLI(getNativeCollisionShape().GetOrientation()); } /*---------------------------------------------------------------------------------*/ @@ -184,10 +164,6 @@ namespace SHADE { return Convert::ToCLI(getNativeCollisionShape().GetCenter()); } - void SphereCollider::Center::set(Vector3 value) - { - getNativeCollisionShape().SetCenter(Convert::ToNative(value)); - } float SphereCollider::Radius::get() { return getNativeCollisionShape().GetWorldRadius(); diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index a649483f..19235571 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -142,15 +142,14 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Center of the Bounding Box formed by this bound. + /// Center of the box collider. /// property Vector3 Center { Vector3 get(); - void set(Vector3 value); } /// - /// Half of the scale of the Bounding Box formed by this bound. + /// Half of the scale of the box collider. /// property Vector3 HalfExtents { @@ -158,22 +157,11 @@ namespace SHADE void set(Vector3 value); } /// - /// Position of the bottom left back corner of the Bounding Box formed by this - /// bound. + /// The orientation of the box. /// - property Vector3 Min + property Quaternion Orientation { - Vector3 get(); - void set(Vector3 value); - } - /// - /// Position of the top right front corner of the Bounding Box formed by this - /// bound. - /// - property Vector3 Max - { - Vector3 get(); - void set(Vector3 value); + Quaternion get(); } /*-----------------------------------------------------------------------------*/ @@ -201,12 +189,11 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Center of the Bounding Sphere formed by this bound. + /// Center of the sphere. /// property Vector3 Center { Vector3 get(); - void set(Vector3 value); } /// /// Radius of the Bounding Sphere formed by this bound. diff --git a/SHADE_Managed/src/Physics/Physics.cxx b/SHADE_Managed/src/Physics/Physics.cxx index fc54f527..bfb79b75 100644 --- a/SHADE_Managed/src/Physics/Physics.cxx +++ b/SHADE_Managed/src/Physics/Physics.cxx @@ -15,10 +15,15 @@ // External Dependencies #include "Physics/System/SHPhysicsSystemInterface.h" // Project Header +#include "Components/Collider.hxx" +#include "Components/Transform.hxx" #include "Engine/GameObject.hxx" +#include "Physics/Collision/SHCollisionSpace.h" #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" +using namespace System::Collections::Generic; + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -41,49 +46,301 @@ namespace SHADE /* Raycast Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - RaycastHit Physics::Raycast(Ray ray) + List^ Physics::Raycast(Ray ray, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Cast natively + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::Raycast(Ray ray, float distance) + List^ Physics::Raycast(Ray ray, float distance, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Cast natively + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.distance = distance; + raycastInfo.continuous = continuous; + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::Linecast(Vector3 start, Vector3 end) + List^ Physics::Linecast(Vector3 start, Vector3 end, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Cast natively + Vector3 direction = end - start; + direction.Normalise(); + const Ray CLI_RAY( start, direction ); + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(CLI_RAY); + raycastInfo.distance = (end - start).GetMagnitude(); + raycastInfo.continuous = continuous; + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray) + List^ Physics::ColliderRaycast(GameObject object, Ray ray, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Get the collider's position (same as the transform) + Transform^ managedTransform = object.GetComponent(); + if (!managedTransform) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform."); + + const Vector3 COLLIDER_POS = managedTransform->GlobalPosition; + ray.Position += COLLIDER_POS; + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance) + List^ Physics::ColliderRaycast(GameObject object, Ray ray, float distance, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Get the collider's position (same as the transform) + Transform^ managedTransform = object.GetComponent(); + if (!managedTransform) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform."); + + const Vector3 COLLIDER_POS = managedTransform->GlobalPosition; + ray.Position += COLLIDER_POS; + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.distance = distance; + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray) + List^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Get the collider's position + Vector3 shapePos = Vector3::Zero; + Collider^ managedCollider = object.GetComponent(); + if (!managedCollider) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider."); + + CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex); + if (!managedShape) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); + + const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); + switch (NATIVE_SHAPE.GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); + break; + } + case SHCollisionShape::Type::BOX: + { + shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); + break; + } + default: break; + } + + ray.Position += shapePos; + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance) + List^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Get the collider's position + Vector3 shapePos = Vector3::Zero; + Collider^ managedCollider = object.GetComponent(); + if (!managedCollider) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider."); + + CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex); + if (!managedShape) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); + + const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); + switch (NATIVE_SHAPE.GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); + break; + } + case SHCollisionShape::Type::BOX: + { + shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); + break; + } + default: break; + } + + ray.Position += shapePos; + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(ray); + raycastInfo.continuous = continuous; + raycastInfo.distance = distance; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end) + List^ Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Get the collider's position (same as the transform) + Transform^ managedTransform = object.GetComponent(); + if (!managedTransform) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform."); + + const Vector3 COLLIDER_POS = managedTransform->GlobalPosition; + start += COLLIDER_POS; + + Vector3 direction = end - start; + direction.Normalise(); + const Ray CLI_RAY( start, direction ); + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(CLI_RAY); + raycastInfo.distance = (end - start).GetMagnitude(); + raycastInfo.continuous = continuous; + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } - RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end) + List^ Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous) { - return RaycastHit{}; + List^ results = gcnew List(); + + // Get the collider's position + Vector3 shapePos = Vector3::Zero; + Collider^ managedCollider = object.GetComponent(); + if (!managedCollider) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider."); + + CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex); + if (!managedShape) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); + + const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); + switch (NATIVE_SHAPE.GetType()) + { + case SHCollisionShape::Type::SPHERE: + { + shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); + break; + } + case SHCollisionShape::Type::BOX: + { + shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); + break; + } + default: break; + } + + start += shapePos; + + Vector3 direction = end - start; + direction.Normalise(); + const Ray CLI_RAY( start, direction ); + + SHCollisionSpace::RaycastInfo raycastInfo; + raycastInfo.ray = Convert::ToNative(CLI_RAY); + raycastInfo.continuous = continuous; + raycastInfo.distance = (end - start).GetMagnitude(); + raycastInfo.SetColliderID(object.EntityId); + + const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo); + if (!NATIVE_RESULTS.empty()) + { + for (const auto& nativeResult : NATIVE_RESULTS) + results->Add(Convert::ToCLI(nativeResult)); + } + + return results; } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Physics/Physics.hxx b/SHADE_Managed/src/Physics/Physics.hxx index f13e5952..abbd1891 100644 --- a/SHADE_Managed/src/Physics/Physics.hxx +++ b/SHADE_Managed/src/Physics/Physics.hxx @@ -10,6 +10,7 @@ #pragma once + // Project Includes #include "Math/Ray.hxx" #include "RaycastHit.hxx" @@ -39,83 +40,146 @@ namespace SHADE /* Raycast Function Members */ /*---------------------------------------------------------------------------------*/ + // TODO(Diren): Add layers for raycasting + /// - /// Casts an infinite ray into the world. + /// Casts an infinite ray into the world.
+ /// This raycast will stop at the first object hit. ///
/// The ray to cast. - /// The result of the raycast. - static RaycastHit Raycast (Ray ray); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ Raycast (Ray ray, bool continuous); /// /// Casts a ray for a given distance into the world. /// /// The ray to cast. /// The distance to cast the ray. - /// The result of the raycast. - static RaycastHit Raycast (Ray ray, float distance); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ Raycast (Ray ray, float distance, bool continuous); /// /// Casts a bounded ray into the world. /// /// The start of the bounded ray. /// The end of the bounded ray. - /// The result of the raycast. - static RaycastHit Linecast (Vector3 start, Vector3 end); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ Linecast (Vector3 start, Vector3 end, bool continuous); /// /// Casts an infinite ray w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// The ray to cast. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, Ray ray); + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, Ray ray, bool continuous); /// /// Casts a ray for a given distance w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// The ray to cast. + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// /// The distance to cast the ray. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, Ray ray, float distance, bool continuous); /// /// Casts an infinite ray w.r.t a specific collider on a GameObject. /// /// The GameObject to cast the ray to. /// The collision shape index on the collider to cast to. - /// The ray to cast. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray); + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, bool continuous); /// /// Casts a ray for a given distance w.r.t a specific collider on a GameObject. /// /// The GameObject to cast the ray to. /// The collision shape index on the collider to cast to. - /// The ray to cast. + /// + /// The ray to cast.
+ /// The position of the ray is offset from the collider's position. + /// /// The distance to cast the ray. - /// The result of the raycast. - static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance, bool continuous); /// /// Casts a bounded ray w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// The start of the bounded ray. + /// + /// The start of the bounded ray.
+ /// The start of the ray is offset from the collider's position. /// - /// The result of the raycast. - static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned. + /// + static System::Collections::Generic::List^ ColliderLineCast (GameObject object, Vector3 start, Vector3 end, bool continuous); /// /// Casts a bounded ray w.r.t a specific collider on a GameObject. /// /// The GameObject to cast the ray to. /// The collision shape index on the collider to cast to. - /// The start of the bounded ray. + /// + /// The start of the bounded ray.
+ /// The start of the ray is offset from the collider's position. /// The end of the bounded ray. - /// The result of the raycast. - static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end); + /// + /// Whether or not the raycast should stop at the first object hit. + /// + /// + /// The results of the raycast. If nothing was hit, an empty list is returned./// + static System::Collections::Generic::List^ ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous); private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index 1d277274..e3a53661 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -103,6 +103,39 @@ namespace SHADE /* Physics Conversions */ /*---------------------------------------------------------------------------------*/ + SHPhysicsRaycastResult Convert::ToNative(RaycastHit cli) + { + // This function shouldn't be used anyway, so we leave the entityHit empty. + + SHPhysicsRaycastResult native; + + native.hit = cli.Hit; + native.position = ToNative(cli.Position); + native.normal = ToNative(cli.Normal); + native.distance = cli.Distance; + native.shapeIndex = cli.CollisionShapeIndex; + + return native; + } + + RaycastHit Convert::ToCLI(const SHPhysicsRaycastResult& native) + { + RaycastHit cli; + + cli.Hit = native.hit; + cli.Position = ToCLI(native.position); + cli.Normal = ToCLI(native.normal); + cli.Distance = native.distance; + cli.CollisionShapeIndex = native.shapeIndex; + + cli.Other = SHEntityManager::IsValidEID(native.entityHit) + ? GameObject(native.entityHit) + : System::Nullable(); + + return cli; + } + + /*---------------------------------------------------------------------------------*/ /* Handle Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index 6fa4d935..f48eb66d 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -141,6 +141,20 @@ namespace SHADE /* Physics Conversions */ /*-----------------------------------------------------------------------------*/ + /// + /// Converts from a managed RaycastHit to a native SHPhysicsRaycastResult + /// + /// The managed RaycastHit to convert from. + /// Native copy of a managed RaycastHit. + static SHPhysicsRaycastResult ToNative(RaycastHit cli); + + /// + /// Converts from a native SHPhysicsRaycastResult to a managed RaycastHit + /// + /// The native SHPhysicsRaycastResult to convert from. + /// Managed copy of a native SHPhysicsRaycastResult. + static RaycastHit ToCLI(const SHPhysicsRaycastResult& native); + /*-----------------------------------------------------------------------------*/ /* Handle Conversions */ /*-----------------------------------------------------------------------------*/ -- 2.40.1 From 1f2a9820d1cc96a7d78e2842969a04e8f7c27cc4 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 2 Jan 2023 22:49:12 +0800 Subject: [PATCH 60/84] Readded collision tags and moved collision filtering to an earlier stage --- Assets/Scenes/PhysicsSandbox.shade | 4 ++-- .../EditorWindow/Inspector/SHEditorComponentView.hpp | 1 + .../Physics/Collision/Narrowphase/SHCollisionDispatch.cpp | 7 ------- SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp | 8 ++++++++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index b07549cc..a02f3b24 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -66,7 +66,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.45715916, y: 7, z: 0.64831841} + Translate: {x: -1.45715916, y: 7, z: 0.0329093337} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -136,7 +136,7 @@ DrawColliders: false Colliders: - Is Trigger: false - Collision Tag: 1 + Collision Tag: 2 Type: Box Half Extents: {x: 1, y: 1, z: 1} Friction: 0.400000006 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 6117dfe8..a46e2550 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -376,6 +376,7 @@ namespace SHADE { SHEditorWidgets::CheckBox("Is Trigger", [shape] { return shape->IsTrigger(); }, [shape](bool value) { shape->SetIsTrigger(value); }); + SHEditorWidgets::ComboBox("Tag", collisionTagNames, [shape]{return SHCollisionTagMatrix::GetTagIndex(shape->GetCollisionTag().GetName());}, [shape](int const& value){shape->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));}); if(ImGui::CollapsingHeader("Physics Material")) { diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp index 4a949d77..e11902e0 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp @@ -65,13 +65,6 @@ namespace SHADE if (!collisionTable[TYPE_A][TYPE_B]) return false; - - // Filter through tags - const uint16_t TAG_A = A.GetCollisionTag().GetMask(); - const uint16_t TAG_B = B.GetCollisionTag().GetMask(); - - const uint16_t MATCH = TAG_A & TAG_B; - return MATCH > 0; } bool SHCollisionDispatcher::Collide(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp index 4dcc7cb7..88fdac40 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -143,6 +143,14 @@ namespace SHADE // This applies both ways: A -> B and B -> A. for (auto& [key, narrowphasePair] : narrowphaseBatch) { + // Filter through tags before attempting narrow-phase + const uint16_t TAG_A = narrowphasePair.A->GetCollisionTag().GetMask(); + const uint16_t TAG_B = narrowphasePair.B->GetCollisionTag().GetMask(); + + const bool MATCH_TAG = TAG_A & TAG_B; + if (!MATCH_TAG) + continue; + const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger(); const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger(); -- 2.40.1 From 1b5024793ca71587230f711c91be8f2b3250d27f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 10:14:39 +0800 Subject: [PATCH 61/84] Added debug drawing for rays --- Assets/Scenes/PhysicsSandbox.shade | 32 ++++--------------- .../Implemented/LeafNodes/LeafSearch.cs | 2 +- .../Gameplay/Player/SC_PickAndThrow.cs | 11 +++++-- Assets/Scripts/Tests/PhysicsTestObj.cs | 14 +++++--- .../EditorWindow/MenuBar/SHEditorMenuBar.cpp | 4 +++ .../Routines/SHPhysicsDebugDrawRoutine.cpp | 10 ++++-- .../System/SHPhysicsDebugDrawSystem.cpp | 7 ---- .../Physics/System/SHPhysicsDebugDrawSystem.h | 2 -- 8 files changed, 37 insertions(+), 45 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index a02f3b24..c94f5ec7 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -38,11 +38,7 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: - - Type: PhysicsTestObj - Enabled: true - forceAmount: 50 - torqueAmount: 500 + Scripts: ~ - EID: 1 Name: Default IsActive: true @@ -81,7 +77,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -145,11 +141,7 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: - - Type: PhysicsTestObj - Enabled: true - forceAmount: 50 - torqueAmount: 500 + Scripts: ~ - EID: 4 Name: Default IsActive: true @@ -190,11 +182,7 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: - - Type: PhysicsTestObj - Enabled: true - forceAmount: 50 - torqueAmount: 500 + Scripts: ~ - EID: 5 Name: Default IsActive: true @@ -235,11 +223,7 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: - - Type: PhysicsTestObj - Enabled: true - forceAmount: 50 - torqueAmount: 500 + Scripts: ~ - EID: 6 Name: Default IsActive: true @@ -280,8 +264,4 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: - - Type: PhysicsTestObj - Enabled: true - forceAmount: 50 - torqueAmount: 500 \ No newline at end of file + Scripts: ~ \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs b/Assets/Scripts/Gameplay/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs index 7c68712c..b5b03629 100644 --- a/Assets/Scripts/Gameplay/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs +++ b/Assets/Scripts/Gameplay/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs @@ -159,7 +159,7 @@ public partial class LeafSearch : BehaviourTreeNode //Since transform position is often the raccoon's base and the ray needs to hit somewhere higher to be more reliable Vector3 rayDestination = plrT.GlobalPosition + plrT.GlobalScale * playerCollider.PositionOffset; Ray sightRay = new Ray(eyePosition, rayDestination - eyePosition); - RaycastHit sightRayHit = Physics.Raycast(sightRay); + RaycastHit sightRayHit = Physics.Raycast(sightRay, false)[0]; //As of November 2022, RaycastHit contains only the FIRST object hit by //the ray in the Other GameObject data member //Diren may likely add ALL objects hit by the ray over December diff --git a/Assets/Scripts/Gameplay/Player/SC_PickAndThrow.cs b/Assets/Scripts/Gameplay/Player/SC_PickAndThrow.cs index 9c879314..8323dba2 100644 --- a/Assets/Scripts/Gameplay/Player/SC_PickAndThrow.cs +++ b/Assets/Scripts/Gameplay/Player/SC_PickAndThrow.cs @@ -1,6 +1,7 @@ using SHADE; using SHADE_Scripting; using System; +using System.Collections.Generic; using static PlayerController; using static Item; @@ -203,9 +204,13 @@ public class PickAndThrow : Script Vector3 playerRayPos = pc.tranform.GlobalPosition; playerRayPos.y += 0.05f; dirNor.Normalise(); - RaycastHit ray1 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(22.5f))), rayDistance); - RaycastHit ray2 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(-22.5f))), rayDistance); - RaycastHit ray3 = Physics.Raycast(new Ray(playerRayPos, dirNor), rayDistance * 0.75f); + List rayList1 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(22.5f))), rayDistance, false); + List rayList2 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(-22.5f))), rayDistance, false); + List rayList3 = Physics.Raycast(new Ray(playerRayPos, dirNor), rayDistance * 0.75f, false); + + RaycastHit ray1 = rayList1[0]; + RaycastHit ray2 = rayList2[0]; + RaycastHit ray3 = rayList3[0]; inRange = CheckForItem(ray1) || CheckForItem(ray2) || CheckForItem(ray3); } } diff --git a/Assets/Scripts/Tests/PhysicsTestObj.cs b/Assets/Scripts/Tests/PhysicsTestObj.cs index 20437eb3..2348894f 100644 --- a/Assets/Scripts/Tests/PhysicsTestObj.cs +++ b/Assets/Scripts/Tests/PhysicsTestObj.cs @@ -6,7 +6,8 @@ using static Item; public class PhysicsTestObj : Script { - public RigidBody rb { get; set; } + public RigidBody body { get; set; } + public Collider collider { get; set; } // Movement input booleans public enum Direction @@ -67,7 +68,8 @@ public class PhysicsTestObj : Script protected override void awake() { - rb = GetComponent(); + body = GetComponent(); + collider = GetComponent(); for (int i = 0; i < 6; ++i) { @@ -78,6 +80,10 @@ public class PhysicsTestObj : Script protected override void update() { + Ray colliderRay = new Ray(); + colliderRay.Direction = Vector3.Right; + Physics.ColliderRaycast(collider.Owner, colliderRay, false); + for (int i = 0; i < 6; ++i) { if (Input.GetKeyDown(moveInputKeys[i])) @@ -99,13 +105,13 @@ public class PhysicsTestObj : Script { //Vector3 offset = new Vector3(0.25f, 0.0f, 0.0f); //rb.AddForceAtLocalPos(moveVec[i] * forceAmount, offset); - rb.AddForce(moveVec[i] * forceAmount); + body.AddForce(moveVec[i] * forceAmount); move[i] = false; } if (shouldRotate) { - rb.AddTorque(rotateVec[i] * torqueAmount); + body.AddTorque(rotateVec[i] * torqueAmount); rotate[i] = false; } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 31b527f3..2e40e92e 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -220,6 +220,10 @@ namespace SHADE if (ImGui::Checkbox("Draw Contact Points", &drawContactPoints)) physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS, drawContactPoints); + bool drawRays = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS); + if (ImGui::Checkbox("Draw Rays", &drawRays)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); + bool drawBroadphase = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE); if (ImGui::Checkbox("Draw Broadphase", &drawBroadphase)) physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBroadphase); diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index b1de5851..69317e59 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -87,8 +87,14 @@ namespace SHADE if (DRAW_RAYCASTS) { - // TODO - physicsDebugDrawSystem->raysToDraw.clear(); + const SHColour& RAY_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)]; + + const auto& RAYS = physicsSystem->raycastHits; + for (const auto& hit : RAYS) + debugDrawSystem->DrawLine(hit.start, hit.end, RAY_COLOUR, true); + + // Clear rays for the physics system + physicsSystem->raycastHits.clear(); } if (DRAW_BROADPHASE) diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 6d69181c..3bd26925 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -149,11 +149,4 @@ namespace SHADE } } - void SHPhysicsDebugDrawSystem::drawRaycast(SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept - { - static const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)]; - } - - - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index 3b4552a5..efc0738e 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -131,8 +131,6 @@ namespace SHADE uint8_t flags; Colliders collidersToDraw; - Raycasts raysToDraw; - Contacts contactToDraw; /*---------------------------------------------------------------------------------*/ /* Member Functions */ -- 2.40.1 From 0460d776b09d0cb21166d708ec375a4ff3b9d621 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 10:40:02 +0800 Subject: [PATCH 62/84] Fixed collision tag panel fallacies and saving of tag masks --- Assets/CollisionTags.SHConfig | 32 ++++++++--------- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../ColliderTagPanel/SHColliderTagPanel.cpp | 8 ++--- .../CollisionTags/SHCollisionTagMatrix.cpp | 35 ++++++++++++++++--- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/Assets/CollisionTags.SHConfig b/Assets/CollisionTags.SHConfig index d3ebe7e2..9488270c 100644 --- a/Assets/CollisionTags.SHConfig +++ b/Assets/CollisionTags.SHConfig @@ -1,16 +1,16 @@ -0 1 -1 2 -2 3 -3 4 -4 5 -5 6 -6 7 -7 8 -8 9 -9 10 -10 11 -11 12 -12 13 -13 14 -14 15 -15 16 +0 1 3 +1 2 3 +2 3 65535 +3 4 65535 +4 5 65535 +5 6 65535 +6 7 65535 +7 8 65535 +8 9 65535 +9 10 65535 +10 11 65535 +11 12 65535 +12 13 65535 +13 14 65535 +14 15 65535 +15 16 65535 diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index c94f5ec7..b8db2555 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -77,7 +77,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false diff --git a/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp index 9a04b812..f28e29c5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp @@ -15,7 +15,7 @@ namespace SHADE ImGui::TableNextRow(); ImGui::PushID("CollisionTagNames"); - for (int i = SHCollisionTag::NUM_LAYERS; i >= 0; --i) + for (int i = SHCollisionTag::NUM_LAYERS; i >= 1; --i) { ImGui::TableNextColumn(); if(i == SHCollisionTag::NUM_LAYERS) continue; @@ -29,7 +29,7 @@ namespace SHADE ImGui::PopID(); } ImGui::PopID(); - for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) + for (int i = 0; i < SHCollisionTag::NUM_LAYERS - 1; ++i) { std::string tagName = SHCollisionTagMatrix::GetTagName(i); auto tag = SHCollisionTagMatrix::GetTag(i); @@ -53,8 +53,8 @@ namespace SHADE tagName2 = std::to_string(idx); ImGui::TableNextColumn(); - //if(i == idx) - // continue; + if(i == idx) + continue; std::string label = std::format("##{} vs {}", tagName, tagName2); SHEditorWidgets::CheckBox(label, [tag, &idx]{return tag->GetLayerState(idx);}, [tag, i, idx](bool const& value){tag->SetLayerState(idx, value); SHCollisionTagMatrix::GetTag(idx)->SetLayerState(i, value);}, label.substr(2)); } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp index b687c6ca..4d3980b0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp @@ -14,6 +14,9 @@ // Primary Header #include "SHCollisionTagMatrix.h" +// Project Headers +#include "Tools/Utilities/SHUtilities.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -145,8 +148,9 @@ namespace SHADE /** * I HATE FILE IO * - * Each line in the file should be "indextag name". - * If the line fails to follow this format, use the default tag name (index + 1) + * Each line in the file should be "indextag namemask". + * If the line fails to follow this format, use the default tag name (index + 1) and default mask. + * If no mask was read, use a default mask. */ // Populate tag names with default @@ -187,18 +191,40 @@ namespace SHADE { SHLOG_ERROR ( - "Collision tag file line {} does not match the required format of 'indextag name'. Default tag used for index {}" + "Collision tag file line {} does not match the required format of 'indextag namemask'. Default tag used for index {}" , linesRead + 1 , tagIndex ) // Use default collisionTags[tagIndex].SetName(std::to_string(tagIndex + 1)); + collisionTags[tagIndex].SetMask(SHUtilities::ConvertEnum(SHCollisionTag::Layer::ALL)); continue; } collisionTags[tagIndex].SetName(tagName); + // Next element is the mask value + std::string maskString; + ss >> maskString; + + uint16_t mask = std::numeric_limits::max(); + if (maskString.empty()) + { + SHLOG_ERROR + ( + "Collision tag file line {} does not match the required format of 'indextag namemask'. Default mask used for index {}" + , linesRead + 1 + , tagIndex + ) + } + else + { + mask = static_cast(std::stoi(maskString)); + } + + collisionTags[tagIndex].SetMask(mask); + ss.clear(); } @@ -215,8 +241,9 @@ namespace SHADE return; } + // Index Name Mask for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) - collisionTagNamesFile << i << " " << collisionTags[i].GetName() << std::endl; + collisionTagNamesFile << i << " " << collisionTags[i].GetName() << " " << collisionTags[i].GetMask() << std::endl; collisionTagNamesFile.close(); } -- 2.40.1 From b2645fb584009c22383dab40f1cd1ca108f103c8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 18:53:21 +0800 Subject: [PATCH 63/84] Added support for composite colliders --- Assets/Scenes/PhysicsSandbox.shade | 17 +- .../Inspector/SHEditorComponentView.hpp | 11 +- .../CollisionShapes/SHBoxCollisionShape.cpp | 59 ++--- .../CollisionShapes/SHBoxCollisionShape.h | 8 +- .../CollisionShapes/SHCollisionShape.cpp | 16 ++ .../CollisionShapes/SHCollisionShape.h | 11 +- .../SHSphereCollisionShape.cpp | 20 ++ .../CollisionShapes/SHSphereCollisionShape.h | 11 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 212 ++++++++++++------ .../src/Physics/Dynamics/SHRigidBody.h | 9 +- 10 files changed, 246 insertions(+), 128 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index b8db2555..9fa2c0f1 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,7 +45,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 4, z: 5} + Position: {x: 0, y: 2, z: 5} Pitch: 0 Yaw: 0 Roll: 0 @@ -62,14 +62,14 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.45715916, y: 7, z: 0.0329093337} + Translate: {x: -1.45715916, y: 7, z: 0.227711335} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: Type: Dynamic Auto Mass: false - Mass: 1 + Mass: 0.52359879 Drag: 0.00999999978 Angular Drag: 0.00999999978 Use Gravity: true @@ -77,7 +77,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -95,6 +95,15 @@ Density: 1 Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} + - Is Trigger: false + Collision Tag: 1 + Type: Sphere + Radius: 0.5 + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0.75, y: 0.5, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true Scripts: - Type: PhysicsTestObj diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index a46e2550..7a528b0b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -251,9 +251,16 @@ namespace SHADE if(rbType == SHRigidBodyComponent::Type::DYNAMIC) //Dynamic only fields { - SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetIsGravityEnabled(value);}, "Gravity"); + SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetIsGravityEnabled(value);}, "Whether Gravity is enabled for this body"); SHEditorWidgets::DragFloat("Gravity Scale", [component] { return component->GetGravityScale(); }, [component](float const& value) { component->SetGravityScale(value); }, "Gravity Scale", 0.1f, 0.0f); - SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); + + SHEditorWidgets::CheckBox("Auto Mass", [component]{return component->GetAutoMass();}, [component](bool const& value){component->SetAutoMass(value);}, "If mass should be automatically computed"); + + const bool autoMass = component->GetAutoMass(); + if (autoMass) + SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {}, "Mass", 0.1f, 0.0f, 0.0f, "%.3f", ImGuiSliderFlags_ReadOnly); + else + SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); } if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp index 621b560b..7a6ab7d2 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp @@ -147,11 +147,6 @@ namespace SHADE return relativeExtents; } - SHQuaternion SHBoxCollisionShape::GetOrientation() const noexcept - { - return Orientation; - } - SHVec3 SHBoxCollisionShape::GetVertex(int index) const { static constexpr int NUM_VERTICES = 8; @@ -160,41 +155,6 @@ namespace SHADE throw std::invalid_argument("Index out-of-range!"); return GetVertices()[index]; - - //// Rotate half extents - //const SHVec3 ROTATED_EXTENTS = SHVec3::Rotate(Extents, Orientation); - //const SHVec3 CENTER { Center }; - - ///* - // * Front: -Z - // * - // * 3 _____ 2 - // * | | - // * | | - // * |_____| - // * 0 1 - // * - // * Back: +Z - // * - // * 7 _____ 6 - // * | | - // * | | - // * |_____| - // * 4 5 - // * - // */ - - //switch (index) - //{ - // case 0: return CENTER + SHVec3 { -ROTATED_EXTENTS.x, -ROTATED_EXTENTS.y, -ROTATED_EXTENTS.z } - // case 1: return CENTER + SHVec3 { - // case 2: return CENTER + SHVec3 { - // case 3: return CENTER + SHVec3 { - // case 4: return CENTER + SHVec3 { - // case 5: return CENTER + SHVec3 { - // case 6: return CENTER + SHVec3 { - // case 7: return CENTER + SHVec3 { - //} } SHVec3 SHBoxCollisionShape::GetNormal(int faceIndex) const @@ -204,7 +164,26 @@ namespace SHADE // Rotate normal into world space return SHVec3::Rotate(LOCAL_NORMAL, Orientation); + } + SHVec3 SHBoxCollisionShape::GetPosition() const noexcept + { + return Center; + } + + SHQuaternion SHBoxCollisionShape::GetOrientation() const noexcept + { + return Orientation; + } + + float SHBoxCollisionShape::GetVolume() const noexcept + { + return Volume(); + } + + SHVec3 SHBoxCollisionShape::GetLocalCentroid() const noexcept + { + return SHVec3::Zero; } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h index f34870f5..a5be0d70 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h @@ -75,10 +75,14 @@ namespace SHADE [[nodiscard]] SHVec3 GetCenter () const noexcept; [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept; [[nodiscard]] SHVec3 GetVertex (int index) const override; - [[nodiscard]] SHVec3 GetNormal (int faceIndex) const override; + [[nodiscard]] SHVec3 GetNormal (int faceIndex) const override; + + [[nodiscard]] SHVec3 GetPosition () const noexcept override; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept override; + [[nodiscard]] float GetVolume () const noexcept override; + [[nodiscard]] SHVec3 GetLocalCentroid () const noexcept override; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index 3696dd50..b412a227 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -14,6 +14,7 @@ #include "SHCollisionShape.h" // Project Headers +#include "Physics/Collision/SHCollider.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Reflection/SHReflectionMetadata.h" #include "Tools/Utilities/SHUtilities.h" @@ -111,6 +112,21 @@ namespace SHADE return *collisionTag; } + SHVec3 SHCollisionShape::GetPosition() const noexcept + { + const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); + + const SHQuaternion FINAL_ROT = PARENT_TRANSFORM.orientation * transform.orientation; + const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(PARENT_TRANSFORM.position); + + return SHVec3::Transform(transform.position, TRS); + } + + SHQuaternion SHCollisionShape::GetOrientation() const noexcept + { + return collider->GetOrientation() * transform.orientation; + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 729eecf7..42e9fb0e 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -94,6 +94,8 @@ namespace SHADE [[nodiscard]] float GetDensity () const noexcept; [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; + + // Offsets [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; @@ -107,6 +109,14 @@ namespace SHADE [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; + // Virtual methods + + [[nodiscard]] virtual SHVec3 GetPosition () const noexcept; + [[nodiscard]] virtual SHQuaternion GetOrientation () const noexcept; + [[nodiscard]] virtual float GetVolume () const noexcept = 0; + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; + [[nodiscard]] virtual SHVec3 GetLocalCentroid () const noexcept = 0; + /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ @@ -130,7 +140,6 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ virtual void ComputeTransforms () noexcept = 0; - [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp index 71d965c5..a5c82017 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp @@ -141,6 +141,26 @@ namespace SHADE return relativeRadius; } + SHVec3 SHSphereCollisionShape::GetPosition() const noexcept + { + return Center; + } + + SHQuaternion SHSphereCollisionShape::GetOrientation() const noexcept + { + return collider->GetTransform().orientation * transform.orientation; + } + + float SHSphereCollisionShape::GetVolume() const noexcept + { + return Volume(); + } + + SHVec3 SHSphereCollisionShape::GetLocalCentroid() const noexcept + { + return SHVec3::Zero; + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h index 54e04fe6..7dbdf13d 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h @@ -71,9 +71,14 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] 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; + + [[nodiscard]] SHVec3 GetPosition () const noexcept override; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept override; + [[nodiscard]] float GetVolume () const noexcept override; + [[nodiscard]] SHVec3 GetLocalCentroid () const noexcept override; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 3e24fa27..c4b27a42 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -14,6 +14,8 @@ #include "SHRigidBody.h" // Project Headers +#include + #include "Physics/Collision/SHCollider.h" #include "Tools/Logger/SHLogger.h" @@ -60,19 +62,19 @@ namespace SHADE } SHRigidBody::SHRigidBody(SHRigidBody&& rhs) noexcept - : entityID { rhs.entityID } - , collider { nullptr } - , bodyType { rhs.bodyType } - , gravityScale { rhs.gravityScale } - , invMass { rhs.invMass } - , linearDrag { rhs.linearDrag } - , angularDrag { rhs.angularDrag } + : entityID { rhs.entityID } + , collider { nullptr } + , bodyType { rhs.bodyType } + , gravityScale { rhs.gravityScale } + , invMass { rhs.invMass } + , linearDrag { rhs.linearDrag } + , angularDrag { rhs.angularDrag } , localInvInertia { rhs.localInvInertia } , worldInvInertia { rhs.worldInvInertia } , localCentroid { rhs.localCentroid } , worldCentroid { rhs.worldCentroid } - , flags { rhs.flags } - , motionState { std::move(rhs.motionState) } + , flags { rhs.flags } + , motionState { std::move(rhs.motionState) } { // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. } @@ -114,21 +116,21 @@ namespace SHADE SHRigidBody& SHRigidBody::operator=(SHRigidBody&& rhs) noexcept { - entityID = rhs.entityID; + entityID = rhs.entityID; // Deep copy the collider - *collider = *rhs.collider; - bodyType = rhs.bodyType; - gravityScale = rhs.gravityScale; - invMass = rhs.invMass; - linearDrag = rhs.linearDrag; - angularDrag = rhs.angularDrag; + *collider = *rhs.collider; + bodyType = rhs.bodyType; + gravityScale = rhs.gravityScale; + invMass = rhs.invMass; + linearDrag = rhs.linearDrag; + angularDrag = rhs.angularDrag; localInvInertia = rhs.localInvInertia; worldInvInertia = rhs.worldInvInertia; localCentroid = rhs.localCentroid; worldCentroid = rhs.worldCentroid; - flags = rhs.flags; - motionState = std::move(rhs.motionState); + flags = rhs.flags; + motionState = std::move(rhs.motionState); // All other properties are defaulted to 0 to not carry over any potential errors / invalid values. accumulatedForce = SHVec3::Zero; @@ -242,6 +244,12 @@ namespace SHADE return flags & (1U << FLAG_POS); } + bool SHRigidBody::IsTriggerInMassData() const noexcept + { + static constexpr unsigned int FLAG_POS = 6; + return flags & (1U << FLAG_POS); + } + bool SHRigidBody::GetFreezePositionX() const noexcept { static constexpr unsigned int FLAG_POS = 10; @@ -334,6 +342,11 @@ namespace SHADE invMass = 1.0f / newMass; + // Turn off automass + static constexpr unsigned int AUTO_MASS_FLAG = 4; + static constexpr uint16_t VALUE = 1U << AUTO_MASS_FLAG; + + flags &= ~(VALUE); ComputeMassData(); } @@ -455,7 +468,6 @@ namespace SHADE if (enableAutoMass) { flags |= VALUE; - // TODO: Compute mass based on collider geometry } else { @@ -463,6 +475,16 @@ namespace SHADE // Use default mass of 1 invMass = 1.0f; } + + ComputeMassData(); + } + + void SHRigidBody::SetTriggerInMassData(bool triggerInMassData) noexcept + { + static constexpr unsigned int FLAG_POS = 6; + static constexpr uint16_t VALUE = 1U << FLAG_POS; + + triggerInMassData ? flags |= VALUE : flags &= ~VALUE; } void SHRigidBody::SetFreezePositionX(bool freezePositionX) noexcept @@ -532,7 +554,7 @@ namespace SHADE else { flags &= ~VALUE; - computeInertiaTensor(); + ComputeMassData(); } } @@ -552,7 +574,7 @@ namespace SHADE else { flags &= ~VALUE; - computeInertiaTensor(); + ComputeMassData(); } } @@ -572,7 +594,7 @@ namespace SHADE else { flags &= ~VALUE; - computeInertiaTensor(); + ComputeMassData(); } } @@ -628,60 +650,110 @@ namespace SHADE void SHRigidBody::ComputeMassData() noexcept { - computeCentroid(); - computeMassAndInertiaTensor(); + // Reset centroid + localCentroid = SHVec3::Zero; + localInvInertia = SHMatrix::Identity; + + // In the instance the body is a particle + if (!collider || collider->GetCollisionShapes().empty()) + { + localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = invMass; + return; + } + + const float CUSTOM_MASS = 1.0f / invMass; + const bool AUTO_MASS = IsAutoMassEnabled(); + const bool INCLUDE_TRIGGERS = IsTriggerInMassData(); + const auto& SHAPES = collider->GetCollisionShapes(); + + // Compute Total mass and store individual masses if custom mass is being used. + // Compute local centroid at the same time + + // Zero matrix; + SHMatrix tmpLocalTensor; + tmpLocalTensor -= SHMatrix::Identity; + + float totalMass = 0.0f; + std::vector trueMass; + + for (auto* shape : SHAPES) + { + // We skip triggers by default + if (shape->IsTrigger() && !INCLUDE_TRIGGERS) + continue; + + shape->ComputeTransforms(); + + // p = m/v, therefore m = pv. This is the true mass of the shape. + const float MASS = shape->GetDensity() * shape->GetVolume(); + totalMass += MASS; + + trueMass.emplace_back(MASS); + + // Weighted sum of masses contribute to the centroid's location using the collider's local position. + localCentroid += MASS * (shape->GetPosition() - collider->GetPosition()); + } + + if (totalMass > 0.0f) + { + localCentroid /= totalMass; + + if (AUTO_MASS) + invMass = 1.0f / totalMass; + } + + const SHMatrix R = SHMatrix::Rotate(motionState.orientation); + const SHMatrix RT = SHMatrix::Transpose(R); + + worldCentroid = (R * localCentroid) + motionState.position; + + for (size_t i = 0; i < SHAPES.size(); ++i) + { + const auto* SHAPE = SHAPES[i]; + + // We skip triggers by default + if (SHAPE->IsTrigger() && !INCLUDE_TRIGGERS) + continue; + + // If using custom mass, take the ratio of the mass + float actualMass = trueMass[i]; + if (!AUTO_MASS) + actualMass *= CUSTOM_MASS / totalMass; + + // Convert inertia tensor into local-space of the body + SHMatrix I = SHAPE->GetInertiaTensor( actualMass ) * RT; + I = R * I; + + // Parallel Axis Theorem + const SHVec3 O = SHAPE->GetPosition() - worldCentroid; + const float O2 = O.LengthSquared(); + + SHMatrix offsetMatrix; + offsetMatrix -= SHMatrix::Identity; + offsetMatrix.m[0][0] = offsetMatrix.m[1][1] = offsetMatrix.m[2][2] = O2; + + const SHVec3 NOX = O * -O.x; + const SHVec3 NOY = O * -O.y; + const SHVec3 NOZ = O * -O.z; + + offsetMatrix += SHMatrix{ NOX, NOY, NOZ, SHVec4::Zero }; + offsetMatrix *= actualMass; + + tmpLocalTensor += I + offsetMatrix; + } + + // Set diagonals then invert + localInvInertia.m[0][0] = tmpLocalTensor.m[0][0]; + localInvInertia.m[1][1] = tmpLocalTensor.m[1][1]; + localInvInertia.m[2][2] = tmpLocalTensor.m[2][2]; + + localInvInertia = SHMatrix::Inverse(localInvInertia); } /*-----------------------------------------------------------------------------------*/ /* Private Member Function Definition */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBody::computeCentroid() noexcept - { - // TODO - } - - void SHRigidBody::computeMass() noexcept - { - // TODO: If auto mass in enabled, compute total mass based from each collider. - // TODO: If auto mass disabled, compute inertia tensor for each shape using the ratio of its mass / total mass by comparing the volume / total volume. - } - - void SHRigidBody::computeInertiaTensor() noexcept - { - // TODO: Compute total inertia from composited colliders using the Parallel Axis Theorem. - - if (!collider || collider->GetCollisionShapes().empty()) - { - localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = invMass; - } - else - { - // HACK: For now, take only the first shape as we are testing with non-composited colliders. We are using the center as the centroid. - const auto* FIRST_SHAPE = collider->GetCollisionShape(0); - localInvInertia = SHMatrix::Inverse(FIRST_SHAPE->GetInertiaTensor(1.0f / invMass)); - } - } - - void SHRigidBody::computeMassAndInertiaTensor() noexcept - { - // TODO: If auto mass in enabled, compute total mass based from each collider. - // TODO: If auto mass disabled, compute inertia tensor for each shape using the ratio of its mass / total mass by comparing the volume / total volume. - - // TODO: Compute total inertia from composited colliders using the Parallel Axis Theorem. - - if (!collider || collider->GetCollisionShapes().empty()) - { - localInvInertia.m[0][0] = localInvInertia.m[1][1] = localInvInertia.m[2][2] = invMass; - } - else - { - // HACK: For now, take only the first shape as we are testing with non-composited colliders. We are using the center as the centroid. - const auto* FIRST_SHAPE = collider->GetCollisionShape(0); - localInvInertia = SHMatrix::Inverse(FIRST_SHAPE->GetInertiaTensor(1.0f / invMass)); - } - } - void SHRigidBody::constrainLinearVelocities() noexcept { linearVelocity.x = GetFreezePositionX() ? 0.0f : linearVelocity.x; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 34424a1c..3c869ad2 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -99,6 +99,7 @@ namespace SHADE [[nodiscard]] bool IsSleepingEnabled () const noexcept; [[nodiscard]] bool IsGravityEnabled () const noexcept; [[nodiscard]] bool IsAutoMassEnabled () const noexcept; + [[nodiscard]] bool IsTriggerInMassData () const noexcept; [[nodiscard]] bool GetFreezePositionX () const noexcept; [[nodiscard]] bool GetFreezePositionY () const noexcept; [[nodiscard]] bool GetFreezePositionZ () const noexcept; @@ -157,6 +158,7 @@ namespace SHADE void SetSleepingEnabled (bool enableSleeping) noexcept; void SetGravityEnabled (bool enableGravity) noexcept; void SetAutoMassEnabled (bool enableAutoMass) noexcept; + void SetTriggerInMassData(bool triggerInMassData) noexcept; void SetFreezePositionX (bool freezePositionX) noexcept; void SetFreezePositionY (bool freezePositionY) noexcept; void SetFreezePositionZ (bool freezePositionZ) noexcept; @@ -249,7 +251,7 @@ namespace SHADE SHVec3 linearVelocity; SHVec3 angularVelocity; - // aZ aY aX rotLockActive pZ pY pX posLockActive 0 0 inIsland autoMass enableGravity enableSleeping sleeping active + // aZ aY aX pZ pY pX 0 0 0 addTriggersToMassData inIsland autoMass enableGravity enableSleeping sleeping active uint16_t flags; SHMotionState motionState; @@ -258,11 +260,6 @@ namespace SHADE /* Member Functions */ /*-----------------------------------------------------------------------------------*/ - void computeCentroid () noexcept; - void computeMass () noexcept; - void computeInertiaTensor () noexcept; - void computeMassAndInertiaTensor() noexcept; - void constrainLinearVelocities () noexcept; void constrainAngularVelocities () noexcept; -- 2.40.1 From f7e867098dff21acd65bbbfb4a25ce0b1cae967e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 20:30:20 +0800 Subject: [PATCH 64/84] Small changes to rigidbody tooltips --- Assets/Scenes/PhysicsSandbox.shade | 4 +-- .../Inspector/SHEditorComponentView.hpp | 25 ++++++++----------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 9fa2c0f1..34e78cc3 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,7 +45,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 2, z: 5} + Position: {x: 0, y: 4, z: 5} Pitch: 0 Yaw: 0 Roll: 0 @@ -69,7 +69,7 @@ RigidBody Component: Type: Dynamic Auto Mass: false - Mass: 0.52359879 + Mass: 10 Drag: 0.00999999978 Angular Drag: 0.00999999978 Use Gravity: true diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 7a528b0b..16961fe0 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -252,38 +252,33 @@ namespace SHADE if(rbType == SHRigidBodyComponent::Type::DYNAMIC) //Dynamic only fields { SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetIsGravityEnabled(value);}, "Whether Gravity is enabled for this body"); - SHEditorWidgets::DragFloat("Gravity Scale", [component] { return component->GetGravityScale(); }, [component](float const& value) { component->SetGravityScale(value); }, "Gravity Scale", 0.1f, 0.0f); + SHEditorWidgets::DragFloat("Gravity Scale", [component] { return component->GetGravityScale(); }, [component](float const& value) { component->SetGravityScale(value); }, "Per-object Gravity Scale", 0.1f, 0.0f); - SHEditorWidgets::CheckBox("Auto Mass", [component]{return component->GetAutoMass();}, [component](bool const& value){component->SetAutoMass(value);}, "If mass should be automatically computed"); - - const bool autoMass = component->GetAutoMass(); - if (autoMass) - SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {}, "Mass", 0.1f, 0.0f, 0.0f, "%.3f", ImGuiSliderFlags_ReadOnly); - else - SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); + SHEditorWidgets::CheckBox("Auto Mass", [component]{return component->GetAutoMass();}, [component](bool const& value){component->SetAutoMass(value);}, "If mass should be automatically computed. Setting mass will turn this off."); + SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); } if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields { SHEditorWidgets::DragFloat("Drag", [component] {return component->GetDrag(); }, [component](float const& value) {component->SetDrag(value); }, "Drag", 0.1f, 0.0f); SHEditorWidgets::DragFloat("Angular Drag", [component] {return component->GetAngularDrag(); }, [component](float const& value) {component->SetAngularDrag(value); }, "Angular Drag", 0.1f, 0.0f); - SHEditorWidgets::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "Interpolate"); + SHEditorWidgets::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "If the position between frames should be interpolated."); SHEditorWidgets::BeginPanel(std::format("{} Constraints", ICON_FA_LOCK).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::TextLabel("Freeze Position"); ImGui::PushID("FreezePos"); - SHEditorWidgets::CheckBox("X", [component] {return component->GetFreezePositionX(); }, [component](bool const& value) {component->SetFreezePositionX(value); }, "Freeze Position - X"); ImGui::SameLine(); - SHEditorWidgets::CheckBox("Y", [component] {return component->GetFreezePositionY(); }, [component](bool const& value) {component->SetFreezePositionY(value); }, "Freeze Position - Y"); ImGui::SameLine(); - SHEditorWidgets::CheckBox("Z", [component] {return component->GetFreezePositionZ(); }, [component](bool const& value) {component->SetFreezePositionZ(value); }, "Freeze Position - Z"); + SHEditorWidgets::CheckBox("X", [component] {return component->GetFreezePositionX(); }, [component](bool const& value) {component->SetFreezePositionX(value); }, "Stops any displacement along the X-axis."); ImGui::SameLine(); + SHEditorWidgets::CheckBox("Y", [component] {return component->GetFreezePositionY(); }, [component](bool const& value) {component->SetFreezePositionY(value); }, "Stops any displacement along the Y-axis."); ImGui::SameLine(); + SHEditorWidgets::CheckBox("Z", [component] {return component->GetFreezePositionZ(); }, [component](bool const& value) {component->SetFreezePositionZ(value); }, "Stops any displacement along the Z-axis."); ImGui::PopID(); SHEditorWidgets::TextLabel("Freeze Rotation"); ImGui::PushID("FreezeRot"); - SHEditorWidgets::CheckBox("X", [component] {return component->GetFreezeRotationX(); }, [component](bool const& value) {component->SetFreezeRotationX(value); }, "Freeze Rotation - X"); ImGui::SameLine(); - SHEditorWidgets::CheckBox("Y", [component] {return component->GetFreezeRotationY(); }, [component](bool const& value) {component->SetFreezeRotationY(value); }, "Freeze Rotation - Y"); ImGui::SameLine(); - SHEditorWidgets::CheckBox("Z", [component] {return component->GetFreezeRotationZ(); }, [component](bool const& value) {component->SetFreezeRotationZ(value); }, "Freeze Rotation - Z"); + SHEditorWidgets::CheckBox("X", [component] {return component->GetFreezeRotationX(); }, [component](bool const& value) {component->SetFreezeRotationX(value); }, "Stops any rotation about the X-axis."); ImGui::SameLine(); + SHEditorWidgets::CheckBox("Y", [component] {return component->GetFreezeRotationY(); }, [component](bool const& value) {component->SetFreezeRotationY(value); }, "Stops any rotation about the Y-axis."); ImGui::SameLine(); + SHEditorWidgets::CheckBox("Z", [component] {return component->GetFreezeRotationZ(); }, [component](bool const& value) {component->SetFreezeRotationZ(value); }, "Stops any rotation about the Z-axis."); ImGui::PopID(); SHEditorWidgets::EndPanel(); -- 2.40.1 From a49c674c2b445032ff2bb1f159c16b3c97abb728 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 4 Jan 2023 15:03:58 +0800 Subject: [PATCH 65/84] Generalised the Parallel Axis Theorem for computing inertia tensors --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../EditorWindow/MenuBar/SHEditorMenuBar.cpp | 34 +++++++-------- SHADE_Engine/src/Math/SHMatrix.cpp | 8 ++++ SHADE_Engine/src/Math/SHMatrix.h | 1 + SHADE_Engine/src/Math/Vector/SHVec3.cpp | 24 +++++++++++ SHADE_Engine/src/Math/Vector/SHVec3.h | 41 ++++++++++--------- .../src/Physics/Dynamics/SHRigidBody.cpp | 38 +++++++---------- 7 files changed, 87 insertions(+), 61 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 34e78cc3..6dea778f 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -77,7 +77,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 5f9bf4d7..8e8c88f3 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -309,28 +309,28 @@ namespace SHADE void SHEditorMenuBar::DrawPhysicsSettings() noexcept { if (ImGui::BeginMenu("Physics Settings")) + { + if (auto* physicsDebugDraw = SHSystemManager::GetSystem()) { - if (auto* physicsDebugDraw = SHSystemManager::GetSystem()) - { - bool drawColliders = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS); - if (ImGui::Checkbox("Draw Colliders", &drawColliders)) - physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS, drawColliders); + bool drawColliders = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS); + if (ImGui::Checkbox("Draw Colliders", &drawColliders)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS, drawColliders); - bool drawContactPoints = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS); - if (ImGui::Checkbox("Draw Contact Points", &drawContactPoints)) - physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS, drawContactPoints); + bool drawContactPoints = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS); + if (ImGui::Checkbox("Draw Contact Points", &drawContactPoints)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS, drawContactPoints); - bool drawRays = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS); - if (ImGui::Checkbox("Draw Rays", &drawRays)) - physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); + bool drawRays = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS); + if (ImGui::Checkbox("Draw Rays", &drawRays)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); - bool drawBroadphase = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE); - if (ImGui::Checkbox("Draw Broadphase", &drawBroadphase)) - physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBroadphase); - } - - ImGui::EndMenu(); + bool drawBroadphase = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE); + if (ImGui::Checkbox("Draw Broadphase", &drawBroadphase)) + physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::BROADPHASE, drawBroadphase); } + + ImGui::EndMenu(); + } } }//namespace SHADE diff --git a/SHADE_Engine/src/Math/SHMatrix.cpp b/SHADE_Engine/src/Math/SHMatrix.cpp index 3d450a88..2cbd5ef6 100644 --- a/SHADE_Engine/src/Math/SHMatrix.cpp +++ b/SHADE_Engine/src/Math/SHMatrix.cpp @@ -34,6 +34,14 @@ namespace SHADE 0.0f, 0.0f, 0.0f, 1.0f }; + const SHMatrix SHMatrix::Zero + { + SHVec4::Zero + , SHVec4::Zero + , SHVec4::Zero + , SHVec4::Zero + }; + /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Math/SHMatrix.h b/SHADE_Engine/src/Math/SHMatrix.h index 6af8fdc9..ffd8ce89 100644 --- a/SHADE_Engine/src/Math/SHMatrix.h +++ b/SHADE_Engine/src/Math/SHMatrix.h @@ -45,6 +45,7 @@ namespace SHADE static constexpr size_t NUM_COLS = 4U; static const SHMatrix Identity; + static const SHMatrix Zero; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ diff --git a/SHADE_Engine/src/Math/Vector/SHVec3.cpp b/SHADE_Engine/src/Math/Vector/SHVec3.cpp index 6b042c61..72d2b0a2 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec3.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec3.cpp @@ -372,6 +372,30 @@ namespace SHADE return lhs.Cross(rhs); } + SHMatrix SHVec3::OuterProduct(const SHVec3& lhs, const SHVec3& rhs) noexcept + { + /* + * Outer product is a matrix multiplication u * vT + * 3x1 * 1x3 = 3x3 + * + * | u1 | | v1 v2 v3 | | u1v1 u1v2 u1v3 | + * | u2 | = | u2v1 u2v2 u2v3 | + * | u3 | | u3v1 u3v2 u3v3 | + */ + + SHMatrix u = SHMatrix::Zero; + SHMatrix vT = SHMatrix::Zero; + + for (int i = 0; i < SIZE; ++i) + { + u.m[0][i] = lhs[i]; + vT.m[i][0] = rhs[i]; + } + + return u * vT; + } + + SHVec3 SHVec3::Project(const SHVec3& v, const SHVec3& u) noexcept { SHVec3 result; diff --git a/SHADE_Engine/src/Math/Vector/SHVec3.h b/SHADE_Engine/src/Math/Vector/SHVec3.h index 657e167e..4b0112c5 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec3.h +++ b/SHADE_Engine/src/Math/Vector/SHVec3.h @@ -115,27 +115,28 @@ namespace SHADE /* Static Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static SHVec3 Normalise (const SHVec3& v) noexcept; - [[nodiscard]] static SHVec3 Abs (const SHVec3& v) noexcept; - [[nodiscard]] static SHVec3 Min (const std::initializer_list& vs) noexcept; - [[nodiscard]] static SHVec3 Max (const std::initializer_list& vs) noexcept; - [[nodiscard]] static SHVec3 Clamp (const SHVec3& v, const SHVec3& vMin, const SHVec3& vMax) noexcept; - [[nodiscard]] static SHVec3 Lerp (const SHVec3& a, const SHVec3& b, float t) noexcept; - [[nodiscard]] static SHVec3 ClampedLerp (const SHVec3& a, const SHVec3& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; + [[nodiscard]] static SHVec3 Normalise (const SHVec3& v) noexcept; + [[nodiscard]] static SHVec3 Abs (const SHVec3& v) noexcept; + [[nodiscard]] static SHVec3 Min (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec3 Max (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec3 Clamp (const SHVec3& v, const SHVec3& vMin, const SHVec3& vMax) noexcept; + [[nodiscard]] static SHVec3 Lerp (const SHVec3& a, const SHVec3& b, float t) noexcept; + [[nodiscard]] static SHVec3 ClampedLerp (const SHVec3& a, const SHVec3& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; - [[nodiscard]] static float Distance (const SHVec3& lhs, const SHVec3& rhs) noexcept; - [[nodiscard]] static float DistanceSquared (const SHVec3& lhs, const SHVec3& rhs) noexcept; - [[nodiscard]] static float Angle (const SHVec3& lhs, const SHVec3& rhs) noexcept; - [[nodiscard]] static float Dot (const SHVec3& lhs, const SHVec3& rhs) noexcept; - [[nodiscard]] static SHVec3 Cross (const SHVec3& lhs, const SHVec3& rhs) noexcept; - [[nodiscard]] static SHVec3 Project (const SHVec3& v, const SHVec3& u) noexcept; - [[nodiscard]] static SHVec3 Reflect (const SHVec3& v, const SHVec3& normal) noexcept; - [[nodiscard]] static SHVec3 Rotate (const SHVec3& v, const SHVec3& axis, float angleInRad) noexcept; - [[nodiscard]] static SHVec3 Rotate (const SHVec3& v, const SHQuaternion& q) noexcept; - [[nodiscard]] static SHVec3 RotateX (const SHVec3& v, float angleInRad) noexcept; - [[nodiscard]] static SHVec3 RotateY (const SHVec3& v, float angleInRad) noexcept; - [[nodiscard]] static SHVec3 RotateZ (const SHVec3& v, float angleInRad) noexcept; - [[nodiscard]] static SHVec3 Transform (const SHVec3& v, const SHMatrix& transformMtx) noexcept; + [[nodiscard]] static float Distance (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static float DistanceSquared (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static float Angle (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static float Dot (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static SHVec3 Cross (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static SHMatrix OuterProduct (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static SHVec3 Project (const SHVec3& v, const SHVec3& u) noexcept; + [[nodiscard]] static SHVec3 Reflect (const SHVec3& v, const SHVec3& normal) noexcept; + [[nodiscard]] static SHVec3 Rotate (const SHVec3& v, const SHVec3& axis, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 Rotate (const SHVec3& v, const SHQuaternion& q) noexcept; + [[nodiscard]] static SHVec3 RotateX (const SHVec3& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 RotateY (const SHVec3& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 RotateZ (const SHVec3& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 Transform (const SHVec3& v, const SHMatrix& transformMtx) noexcept; }; SHVec3 operator* (float lhs, const SHVec3& rhs) noexcept; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index c4b27a42..3b2de659 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -14,6 +14,7 @@ #include "SHRigidBody.h" // Project Headers +#include #include #include "Physics/Collision/SHCollider.h" @@ -664,26 +665,24 @@ namespace SHADE const float CUSTOM_MASS = 1.0f / invMass; const bool AUTO_MASS = IsAutoMassEnabled(); const bool INCLUDE_TRIGGERS = IsTriggerInMassData(); - const auto& SHAPES = collider->GetCollisionShapes(); + // Compute Total mass and store individual masses if custom mass is being used. // Compute local centroid at the same time // Zero matrix; - SHMatrix tmpLocalTensor; - tmpLocalTensor -= SHMatrix::Identity; + SHMatrix J = SHMatrix::Zero; float totalMass = 0.0f; - std::vector trueMass; + std::vector trueMass; // We store the true masses here for calculating the ratio with custom masses. + const auto& SHAPES = collider->GetCollisionShapes(); for (auto* shape : SHAPES) { // We skip triggers by default if (shape->IsTrigger() && !INCLUDE_TRIGGERS) continue; - shape->ComputeTransforms(); - // p = m/v, therefore m = pv. This is the true mass of the shape. const float MASS = shape->GetDensity() * shape->GetVolume(); totalMass += MASS; @@ -705,6 +704,7 @@ namespace SHADE const SHMatrix R = SHMatrix::Rotate(motionState.orientation); const SHMatrix RT = SHMatrix::Transpose(R); + // We need the world centroid to compute the offset of the collider from the body's centroid worldCentroid = (R * localCentroid) + motionState.position; for (size_t i = 0; i < SHAPES.size(); ++i) @@ -721,31 +721,23 @@ namespace SHADE actualMass *= CUSTOM_MASS / totalMass; // Convert inertia tensor into local-space of the body + // R * I * RT = R * (I * RT) SHMatrix I = SHAPE->GetInertiaTensor( actualMass ) * RT; I = R * I; // Parallel Axis Theorem - const SHVec3 O = SHAPE->GetPosition() - worldCentroid; - const float O2 = O.LengthSquared(); + // J = I + m((R /dot R)E_3 - R /outerProduct R) + const SHVec3 R = SHAPE->GetPosition() - worldCentroid; + const float R_MAG2 = R.LengthSquared(); + const SHMatrix R_OX_R = SHVec3::OuterProduct(R, R); - SHMatrix offsetMatrix; - offsetMatrix -= SHMatrix::Identity; - offsetMatrix.m[0][0] = offsetMatrix.m[1][1] = offsetMatrix.m[2][2] = O2; - - const SHVec3 NOX = O * -O.x; - const SHVec3 NOY = O * -O.y; - const SHVec3 NOZ = O * -O.z; - - offsetMatrix += SHMatrix{ NOX, NOY, NOZ, SHVec4::Zero }; - offsetMatrix *= actualMass; - - tmpLocalTensor += I + offsetMatrix; + J += I + actualMass * (SHMatrix::Identity * R_MAG2 - R_OX_R); } // Set diagonals then invert - localInvInertia.m[0][0] = tmpLocalTensor.m[0][0]; - localInvInertia.m[1][1] = tmpLocalTensor.m[1][1]; - localInvInertia.m[2][2] = tmpLocalTensor.m[2][2]; + localInvInertia.m[0][0] = J.m[0][0]; + localInvInertia.m[1][1] = J.m[1][1]; + localInvInertia.m[2][2] = J.m[2][2]; localInvInertia = SHMatrix::Inverse(localInvInertia); } -- 2.40.1 From dd2fc934a2dd6c12439dea9d49fbe8bae891895c Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 4 Jan 2023 17:48:08 +0800 Subject: [PATCH 66/84] Removed Redundant Geometry --- .../Inspector/SHEditorComponentView.hpp | 4 +- SHADE_Engine/src/Math/Geometry/SHBox.cpp | 154 ---------- SHADE_Engine/src/Math/Geometry/SHBox.h | 138 --------- SHADE_Engine/src/Math/Geometry/SHSphere.cpp | 150 ---------- SHADE_Engine/src/Math/Geometry/SHSphere.h | 146 ---------- .../{SHBoxCollisionShape.cpp => SHBox.cpp} | 275 +++++++++--------- .../{SHBoxCollisionShape.h => SHBox.h} | 116 +++----- .../CollisionShapes/SHCollisionShape.cpp | 31 +- .../CollisionShapes/SHCollisionShape.h | 104 +++++-- .../SHCollisionShapeLibrary.cpp | 14 +- .../CollisionShapes/SHCollisionShapeLibrary.h | 12 +- ...lisionShape.cpp => SHConvexPolyhedron.cpp} | 22 +- ...nCollisionShape.h => SHConvexPolyhedron.h} | 16 +- ...HSphereCollisionShape.cpp => SHSphere.cpp} | 184 ++++++------ .../{SHSphereCollisionShape.h => SHSphere.h} | 98 ++----- .../Collision/Contacts/SHCollisionKey.cpp | 2 +- .../Narrowphase/SHCapsuleVsConvex.cpp | 2 +- .../Collision/Narrowphase/SHCollision.h | 24 +- .../Narrowphase/SHSphereVsCapsule.cpp | 2 +- .../Narrowphase/SHSphereVsConvex.cpp | 42 +-- .../Narrowphase/SHSphereVsSphere.cpp | 41 ++- .../Physics/Collision/SHCollisionSpace.cpp | 10 +- .../src/Physics/Collision/SHCollisionSpace.h | 10 +- ...SHCollider.cpp => SHCompositeCollider.cpp} | 72 ++--- .../{SHCollider.h => SHCompositeCollider.h} | 16 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 9 +- .../src/Physics/Dynamics/SHRigidBody.h | 6 +- .../PhysicsObject/SHPhysicsObject.cpp | 8 +- .../Interface/PhysicsObject/SHPhysicsObject.h | 8 +- .../Physics/Interface/SHColliderComponent.cpp | 6 +- .../Physics/Interface/SHColliderComponent.h | 10 +- .../System/SHPhysicsDebugDrawSystem.cpp | 6 +- .../Physics/System/SHPhysicsDebugDrawSystem.h | 6 +- .../src/Serialization/SHYAMLConverters.h | 10 +- SHADE_Managed/src/Components/Collider.cxx | 18 +- SHADE_Managed/src/Physics/Physics.cxx | 45 +-- 36 files changed, 556 insertions(+), 1261 deletions(-) delete mode 100644 SHADE_Engine/src/Math/Geometry/SHBox.cpp delete mode 100644 SHADE_Engine/src/Math/Geometry/SHBox.h delete mode 100644 SHADE_Engine/src/Math/Geometry/SHSphere.cpp delete mode 100644 SHADE_Engine/src/Math/Geometry/SHSphere.h rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHBoxCollisionShape.cpp => SHBox.cpp} (51%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHBoxCollisionShape.h => SHBox.h} (53%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHConvexPolyhedronCollisionShape.cpp => SHConvexPolyhedron.cpp} (76%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHConvexPolyhedronCollisionShape.h => SHConvexPolyhedron.h} (83%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHSphereCollisionShape.cpp => SHSphere.cpp} (51%) rename SHADE_Engine/src/Physics/Collision/CollisionShapes/{SHSphereCollisionShape.h => SHSphere.h} (55%) rename SHADE_Engine/src/Physics/Collision/{SHCollider.cpp => SHCompositeCollider.cpp} (81%) rename SHADE_Engine/src/Physics/Collision/{SHCollider.h => SHCompositeCollider.h} (92%) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index ed6b7bd4..765dbc9b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -358,7 +358,7 @@ namespace SHADE { SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto* box = reinterpret_cast(shape); + auto* box = reinterpret_cast(shape); SHEditorWidgets::DragVec3 ( "Half Extents", { "X", "Y", "Z" }, @@ -368,7 +368,7 @@ namespace SHADE 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(shape); + auto* sphere = reinterpret_cast(shape); SHEditorWidgets::DragFloat ( "Radius", diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp deleted file mode 100644 index bcdb7324..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHBox.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/**************************************************************************************** - * \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 - -// 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 - { - Extents = SHVec3::One * 0.5f; - } - - SHBox::SHBox(const SHVec3& c, const SHVec3& hE, const SHQuaternion& o) noexcept - { - Center = c; - Extents = hE; - Orientation = o; - } - - - SHBox::SHBox(const SHBox& rhs) noexcept - { - if (this == &rhs) - return; - - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; - } - - SHBox::SHBox(SHBox&& rhs) noexcept - { - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHBox& SHBox::operator=(const SHBox& rhs) noexcept - { - if (this != &rhs) - { - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; - } - - return *this; - } - - SHBox& SHBox::operator=(SHBox&& rhs) noexcept - { - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; - - return *this; - } - - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - std::vector SHBox::GetVertices() const noexcept - { - std::vector 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); - - // TODO: Compute Normal - } - - 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h deleted file mode 100644 index 7815ce2c..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHBox.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************************** - * \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 - -// Project Headers -#include "SHShape.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a 3D-oriented bounding box. - */ - 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 GetVertices () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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.
- * 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 Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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 \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp deleted file mode 100644 index 9d7a7c68..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************************** - * \file SHSphere.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Bounding Sphere - * - * \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 - -// Primary Header -#include "SHSphere.h" -// Project Headers -#include "Math/SHMathHelpers.h" -#include "Math/SHRay.h" - -using namespace DirectX; - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere::SHSphere() noexcept - { - Radius = 0.5f; - } - - SHSphere::SHSphere(const SHVec3& center, float radius) noexcept - { - Center = center; - Radius = radius; - } - - SHSphere::SHSphere(const SHSphere& rhs) noexcept - { - if (this == &rhs) - return; - - Center = rhs.Center; - Radius = rhs.Radius; - } - - SHSphere::SHSphere(SHSphere&& rhs) noexcept - { - Center = rhs.Center; - Radius = rhs.Radius; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept - { - if (this != &rhs) - { - Center = rhs.Center; - Radius = rhs.Radius; - } - - return *this; - } - - SHSphere& SHSphere::operator=(SHSphere&& rhs) noexcept - { - - Center = rhs.Center; - Radius = rhs.Radius; - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHSphere::TestPoint(const SHVec3& point) const noexcept - { - return BoundingSphere::Contains(point); - } - - SHRaycastResult SHSphere::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); - - // TODO: Compute Normal - } - - return result; - } - - bool SHSphere::Contains(const SHSphere& rhs) const noexcept - { - return BoundingSphere::Contains(rhs) == CONTAINS; - } - - float SHSphere::Volume() const noexcept - { - return (4.0f / 3.0f) * SHMath::PI * (Radius * Radius * Radius); - } - - float SHSphere::SurfaceArea() const noexcept - { - return 4.0f * SHMath::PI * (Radius * Radius); - } - - /*-----------------------------------------------------------------------------------*/ - /* Static Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere SHSphere::Combine(const SHSphere& lhs, const SHSphere& rhs) noexcept - { - SHSphere result; - CreateMerged(result, lhs, rhs); - return result; - } - - bool SHSphere::Intersect(const SHSphere& lhs, const SHSphere& rhs) noexcept - { - return lhs.Intersects(rhs); - } - - SHSphere SHSphere::BuildFromSpheres(const SHSphere* spheres, size_t numSpheres) noexcept - { - SHSphere result; - - for (size_t i = 1; i < numSpheres; ++i) - CreateMerged(result, spheres[i - 1], spheres[i]); - - return result; - } - - SHSphere SHSphere::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept - { - SHSphere result; - CreateFromPoints(result, numVertices, vertices, stride); - return result; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHSphere.h b/SHADE_Engine/src/Math/Geometry/SHSphere.h deleted file mode 100644 index 3c534ac4..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHSphere.h +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************************** - * \file SHSphere.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Bounding Sphere. - * - * \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 - -// Project Headers -#include "SHShape.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a 3D Sphere. - */ - class SH_API SHSphere : public SHShape, - public DirectX::BoundingSphere - { - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHSphere () noexcept; - SHSphere (const SHVec3& center, float radius) noexcept; - SHSphere (const SHSphere& rhs) noexcept; - SHSphere (SHSphere&& rhs) noexcept; - - ~SHSphere () override = default; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHSphere& operator= (const SHSphere& rhs) noexcept; - SHSphere& operator= (SHSphere&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @brief - * Checks if a point is inside the sphere. - * @param point - * The point to check. - * @return - * True if the point is inside the sphere. - */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - - /** - * @brief - * Casts a ray against the sphere. - * @param ray - * The ray to cast. - * @return - * The result of the raycast.
- * 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 sphere is contained by this sphere. - * @param rhs - * The sphere to check. - * @return - * True if the other sphere is completely contained by this sphere. - */ - [[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept; - - /** - * @brief - * Calculates the volume of the sphere. - */ - [[nodiscard]] float Volume () const noexcept; - - /** - * @brief - * Calculates the surface area of the sphere. - */ - [[nodiscard]] float SurfaceArea () const noexcept; - - - /*---------------------------------------------------------------------------------*/ - /* Static Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @brief - * Combines two spheres to form a larger sphere. - * If one sphere is completely contained by the other, the result is the larger sphere. - * @return - * The combined sphere. - */ - [[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept; - - /** - * @brief - * Checks if two spheres are intersecting. - * @return - * True if they are intersecting. - */ - [[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept; - - /** - * @brief - * Builds a single sphere from multiple spheres. - * @param spheres - * The set of spheres to build from. - * @param numSpheres - * The number of spheres in the set to build from. - * @return - * A sphere that contains all the spheres in the set. - */ - [[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept; - - /** - * @brief - * Builds a sphere from a set of vertices. - * @param vertices - * The vertices to build a sphere 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 - * A sphere that contains all the vertices in the set. - */ - [[nodiscard]] static SHSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; - }; -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.cpp similarity index 51% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.cpp index 7a6ab7d2..b46c92da 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.cpp @@ -11,12 +11,12 @@ #include // Primary Header -#include "SHBoxCollisionShape.h" +#include "SHBox.h" // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" namespace SHADE { @@ -24,66 +24,46 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHBoxCollisionShape::SHBoxCollisionShape(SHCollisionShapeID id) noexcept - : SHConvexPolyhedronCollisionShape (id, SHCollisionShape::Type::BOX) - , SHBox () - , relativeExtents { SHVec3::One } - , scale { SHVec3::One } - {} - - SHBoxCollisionShape::SHBoxCollisionShape(const SHBoxCollisionShape& rhs) noexcept - : SHConvexPolyhedronCollisionShape (rhs.id, SHCollisionShape::Type::BOX) - , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) - , relativeExtents { rhs.relativeExtents } - , scale { rhs.scale } + SHBox::SHBox(SHCollisionShapeID id) noexcept + : SHConvexPolyhedron (id, Type::BOX) + , relativeExtents { SHVec3::One } + , scale { SHVec3::One } { - halfEdgeStructure = rhs.halfEdgeStructure; - - 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; + Extents = SHVec3::One * 0.5f; } - SHBoxCollisionShape::SHBoxCollisionShape(SHBoxCollisionShape&& rhs) noexcept - : SHConvexPolyhedronCollisionShape (rhs.id, SHCollisionShape::Type::BOX) - , SHBox (rhs.Center, rhs.Extents, rhs.Orientation) - , relativeExtents { rhs.relativeExtents } - , scale { rhs.scale } + SHBox::SHBox(const SHBox& rhs) noexcept + : SHConvexPolyhedron ( rhs ) + , relativeExtents { rhs.relativeExtents } + , scale { rhs.scale } { - halfEdgeStructure = rhs.halfEdgeStructure; + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; + } - 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; + SHBox::SHBox(SHBox&& rhs) noexcept + : SHConvexPolyhedron ( rhs ) + , relativeExtents { rhs.relativeExtents } + , scale { rhs.scale } + { + Center = rhs.Center; + Extents = rhs.Extents; + Orientation = rhs.Orientation; } /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHBoxCollisionShape& SHBoxCollisionShape::operator=(const SHBoxCollisionShape& rhs) noexcept + SHBox& SHBox::operator=(const SHBox& 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; + SHConvexPolyhedron::operator=(rhs); // Box Properties @@ -95,23 +75,15 @@ namespace SHADE relativeExtents = rhs.relativeExtents; scale = rhs.scale; - halfEdgeStructure = rhs.halfEdgeStructure; return *this; } - SHBoxCollisionShape& SHBoxCollisionShape::operator=(SHBoxCollisionShape&& rhs) noexcept + SHBox& SHBox::operator=(SHBox&& 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; + SHConvexPolyhedron::operator=(rhs); // Box Properties @@ -123,7 +95,6 @@ namespace SHADE relativeExtents = rhs.relativeExtents; scale = rhs.scale; - halfEdgeStructure = rhs.halfEdgeStructure; return *this; } @@ -132,32 +103,28 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHVec3 SHBoxCollisionShape::GetCenter() const noexcept - { - return Center; - } - - SHVec3 SHBoxCollisionShape::GetWorldExtents() const noexcept + SHVec3 SHBox::GetWorldExtents() const noexcept { return Extents; } - SHVec3 SHBoxCollisionShape::GetRelativeExtents() const noexcept + SHVec3 SHBox::GetRelativeExtents() const noexcept { return relativeExtents; } - SHVec3 SHBoxCollisionShape::GetVertex(int index) const + SHVec3 SHBox::GetVertex(int index) const { - static constexpr int NUM_VERTICES = 8; - if (index < 0 || index >= NUM_VERTICES) throw std::invalid_argument("Index out-of-range!"); - return GetVertices()[index]; + SHVec3 vertices[NUM_VERTICES]; + GetCorners(vertices); + + return vertices[index]; } - SHVec3 SHBoxCollisionShape::GetNormal(int faceIndex) const + SHVec3 SHBox::GetNormal(int faceIndex) const { // Get local normal const SHVec3& LOCAL_NORMAL = halfEdgeStructure->GetFace(faceIndex).normal; @@ -166,88 +133,47 @@ namespace SHADE return SHVec3::Rotate(LOCAL_NORMAL, Orientation); } - SHVec3 SHBoxCollisionShape::GetPosition() const noexcept + SHVec3 SHBox::GetWorldCentroid() const noexcept { return Center; } - SHQuaternion SHBoxCollisionShape::GetOrientation() const noexcept + SHVec3 SHBox::GetRelativeCentroid() const noexcept { - return Orientation; + if (collider) + return SHVec3{ Center } - collider->GetPosition(); + + return Center; } - float SHBoxCollisionShape::GetVolume() const noexcept - { - return Volume(); - } - - SHVec3 SHBoxCollisionShape::GetLocalCentroid() const noexcept + SHVec3 SHBox::GetLocalCentroid() const noexcept { return SHVec3::Zero; } - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHBoxCollisionShape::SetCenter(const SHVec3& newCenter) noexcept + SHQuaternion SHBox::GetWorldOrientation() const noexcept { - Center = newCenter; + return Orientation; } - void SHBoxCollisionShape::SetWorldExtents(const SHVec3& newWorldExtents) noexcept + SHQuaternion SHBox::GetRelativeOrientation() const noexcept { - Extents = newWorldExtents; - - // Recompute Relative radius - relativeExtents = 2.0f * Extents / scale; + return transform.orientation; } - void SHBoxCollisionShape::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept + float SHBox::GetVolume() const noexcept { - relativeExtents = newRelativeExtents; - - // Recompute world radius - Extents = relativeExtents * scale * 0.5f; + return 8.0f * (Extents.x * Extents.y * Extents.z); } - void SHBoxCollisionShape::SetScale(const SHVec3& newScale) noexcept + float SHBox::GetSurfaceArea() const noexcept { - scale = SHVec3::Abs(newScale); - - // Recompute world radius - Extents = relativeExtents * scale * 0.5f; + return 8.0f * (Extents.x * Extents.y + + Extents.x * Extents.z + + Extents.y * Extents.z); } - /*-----------------------------------------------------------------------------------*/ - /* 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); - - Orientation = FINAL_ROT; - 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 + SHMatrix SHBox::GetInertiaTensor(float mass) const noexcept { static constexpr float ONE_OVER_TWELVE = (1.0f / 12.0f); @@ -270,30 +196,93 @@ namespace SHADE 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; + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ - return SHMatrix::Transform - ( - Center - , ROTATION - , SCALE - ); + void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept + { + Extents = newWorldExtents; + + // Recompute Relative radius + relativeExtents = 2.0f * Extents / scale; } - SHAABB SHBoxCollisionShape::ComputeAABB() const noexcept + void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept + { + relativeExtents = newRelativeExtents; + + // Recompute world radius + Extents = relativeExtents * scale * 0.5f; + } + + void SHBox::SetScale(const SHVec3& newScale) noexcept + { + scale = SHVec3::Abs(newScale); + + // Recompute world radius + Extents = relativeExtents * scale * 0.5f; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHBox::Update() 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); + + Orientation = FINAL_ROT; + Center = SHVec3::Transform(transform.position, TRS); + } + + bool SHBox::TestPoint(const SHVec3& point) const noexcept + { + return 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); + + // TODO: Compute Normal: Test which face the position belongs in. The normal is that face's normal. + } + + return result; + } + + SHMatrix SHBox::GetTRS() const noexcept + { + const SHQuaternion ROTATION = collider ? collider->GetTransform().orientation * transform.orientation : Orientation; + const SHVec3 SCALE = SHVec3{ Extents } *2.0f; + + return SHMatrix::Transform(Center, ROTATION, SCALE); + } + + SHAABB SHBox::ComputeAABB() const noexcept { SHVec3 min{ std::numeric_limits::max() }; SHVec3 max{ std::numeric_limits::lowest() }; - const auto& VERTICES = GetVertices(); - for (auto& vtx : VERTICES) + SHVec3 vertices[NUM_VERTICES]; + GetCorners(vertices); + + for (auto& vertex : vertices) { - min = SHVec3::Min({ vtx, min }); - max = SHVec3::Max({ vtx, max }); + min = SHVec3::Min({ vertex, min }); + max = SHVec3::Max({ vertex, max }); } const SHVec3 HALF_EXTENTS = (max - min) * 0.5f; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.h similarity index 53% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.h index a5be0d70..bf250726 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBoxCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.h @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHBoxCollisionShape.h + * \file SHBox.h * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Interface for a Box Collision Shape. * @@ -10,9 +10,10 @@ #pragma once +#include + // Project Headers -#include "Math/Geometry/SHBox.h" -#include "SHConvexPolyhedronCollisionShape.h" +#include "SHConvexPolyhedron.h" namespace SHADE { @@ -38,57 +39,67 @@ namespace SHADE * @brief * Encapsulate a Box Shape used for Physics Simulations. */ - class SH_API SHBoxCollisionShape final : public SHConvexPolyhedronCollisionShape - , private SHBox + class SH_API SHBox final : public SHConvexPolyhedron + , private DirectX::BoundingOrientedBox { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCollider; + friend class SHCompositeCollider; friend class SHCollision; friend class SHCollisionShapeLibrary; public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr int NUM_VERTICES = 8; + /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHBoxCollisionShape (SHCollisionShapeID id) noexcept; - SHBoxCollisionShape (const SHBoxCollisionShape& rhs) noexcept; - SHBoxCollisionShape (SHBoxCollisionShape&& rhs) noexcept; + SHBox (SHCollisionShapeID id) noexcept; + SHBox (const SHBox& rhs) noexcept; + SHBox (SHBox&& rhs) noexcept; - ~SHBoxCollisionShape () override = default; + ~SHBox () override = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHBoxCollisionShape& operator= (const SHBoxCollisionShape& rhs) noexcept; - SHBoxCollisionShape& operator= (SHBoxCollisionShape&& rhs) noexcept; + SHBox& operator= (const SHBox& rhs) noexcept; + SHBox& operator= (SHBox&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; + [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; + [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; - [[nodiscard]] SHVec3 GetVertex (int index) const override; - [[nodiscard]] SHVec3 GetNormal (int faceIndex) const override; + // Overriden Methods - [[nodiscard]] SHVec3 GetPosition () const noexcept override; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept override; - [[nodiscard]] float GetVolume () const noexcept override; - [[nodiscard]] SHVec3 GetLocalCentroid () const noexcept override; + [[nodiscard]] SHVec3 GetVertex (int index) const override; + [[nodiscard]] SHVec3 GetNormal (int faceIndex) const override; + + [[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override; + [[nodiscard]] SHVec3 GetRelativeCentroid () const noexcept override; + [[nodiscard]] SHVec3 GetLocalCentroid () const noexcept override; + [[nodiscard]] SHQuaternion GetWorldOrientation () const noexcept override; + [[nodiscard]] SHQuaternion GetRelativeOrientation () const noexcept override; + [[nodiscard]] float GetVolume () const noexcept override; + [[nodiscard]] float GetSurfaceArea () const noexcept override; + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCenter (const SHVec3& newCenter) noexcept; void SetWorldExtents (const SHVec3& newWorldExtents) noexcept; void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept; void SetScale (const SHVec3& newScale) noexcept; @@ -97,66 +108,19 @@ namespace SHADE /* 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.
- * 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; + void Update () noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHMatrix GetTRS () const noexcept override; + [[nodiscard]] SHAABB ComputeAABB () const noexcept override; private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHVec3 relativeExtents; - SHVec3 scale; // Intended to be passed in by the base collider. + SHVec3 relativeExtents; + SHVec3 scale; }; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp index b412a227..f089c02c 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp @@ -14,7 +14,7 @@ #include "SHCollisionShape.h" // Project Headers -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Reflection/SHReflectionMetadata.h" #include "Tools/Utilities/SHUtilities.h" @@ -112,25 +112,15 @@ namespace SHADE return *collisionTag; } - SHVec3 SHCollisionShape::GetPosition() const noexcept - { - const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); - - const SHQuaternion FINAL_ROT = PARENT_TRANSFORM.orientation * transform.orientation; - const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(PARENT_TRANSFORM.position); - - return SHVec3::Transform(transform.position, TRS); - } - - SHQuaternion SHCollisionShape::GetOrientation() const noexcept - { - return collider->GetOrientation() * transform.orientation; - } - /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept + { + collisionTag = newCollisionTag; + } + void SHCollisionShape::SetFriction(float friction) noexcept { material.SetFriction(friction); @@ -155,7 +145,7 @@ namespace SHADE { transform.position = posOffset; - ComputeTransforms(); + Update(); } void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept @@ -163,7 +153,7 @@ namespace SHADE rotationOffset = rotOffset; transform.orientation = SHQuaternion::FromEuler(rotationOffset); - ComputeTransforms(); + Update(); } void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept @@ -174,11 +164,6 @@ namespace SHADE isTrigger ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE; } - void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept - { - collisionTag = newCollisionTag; - } - } // namespace SHADE RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index 42e9fb0e..b4ce9529 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -41,7 +41,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCollider; + friend class SHCompositeCollider; friend class SHColliderComponent; friend class SHCollisionShapeLibrary; friend class SHCollisionSpace; @@ -57,6 +57,7 @@ namespace SHADE SPHERE , BOX , CAPSULE + , CONVEX_HULL , COUNT , INVALID = -1 @@ -83,44 +84,47 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] EntityID GetEntityID () const noexcept; - [[nodiscard]] uint32_t GetIndex () const noexcept; + [[nodiscard]] EntityID GetEntityID () const noexcept; + [[nodiscard]] uint32_t GetIndex () const noexcept; // Material Properties // TODO: Remove individual setters once instanced materials are supported - [[nodiscard]] float GetFriction () const noexcept; - [[nodiscard]] float GetBounciness () const noexcept; - [[nodiscard]] float GetDensity () const noexcept; - [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; - - + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; // Offsets - [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; - [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; + [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; + [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; // Flags - [[nodiscard]] Type GetType () const noexcept; - [[nodiscard]] bool IsTrigger () const noexcept; - [[nodiscard]] bool IsColliding () const noexcept; + [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] bool IsTrigger () const noexcept; + [[nodiscard]] bool IsColliding () const noexcept; - [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; + [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; // Virtual methods - [[nodiscard]] virtual SHVec3 GetPosition () const noexcept; - [[nodiscard]] virtual SHQuaternion GetOrientation () const noexcept; - [[nodiscard]] virtual float GetVolume () const noexcept = 0; - [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; - [[nodiscard]] virtual SHVec3 GetLocalCentroid () const noexcept = 0; + [[nodiscard]] virtual SHVec3 GetWorldCentroid () const noexcept = 0; + [[nodiscard]] virtual SHVec3 GetRelativeCentroid () const noexcept = 0; + [[nodiscard]] virtual SHVec3 GetLocalCentroid () const noexcept = 0; + [[nodiscard]] virtual SHQuaternion GetWorldOrientation () const noexcept = 0; + [[nodiscard]] virtual SHQuaternion GetRelativeOrientation () const noexcept = 0; + [[nodiscard]] virtual float GetVolume () const noexcept = 0; + [[nodiscard]] virtual float GetSurfaceArea () const noexcept = 0; + [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ + void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; + void SetFriction (float friction) noexcept; void SetBounciness (float bounciness) noexcept; void SetDensity (float density) noexcept; @@ -130,18 +134,55 @@ namespace SHADE void SetRotationOffset (const SHVec3& rotOffset) noexcept; // Flags - - void SetIsTrigger (bool isTrigger) noexcept; - void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept; + // Forces rigidbody to recompute mass if one exists + void SetIsTrigger (bool isTrigger) noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ - virtual void ComputeTransforms () noexcept = 0; - [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0; - [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; + /** + * @brief + * Computes the transform of the shape. + */ + virtual void Update () noexcept = 0; + + /** + * @brief + * Tests if a point is inside this shape. + * @param point + * The point to test against the shape. + * @return + * True if the point is inside the shape. False otherwise. + */ + [[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0; + + /** + * @brief + * Casts a ray at this shape. + * @param ray + * The ray to cast at the shape. + * @return + * The result of the ray cast. See the corresponding struct for it's contents. + */ + [[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0; + + /** + * @brief + * Computes the TRS matrix for rendering the shape. + * @return + * The model-to-world matrix for rendering the shape. + */ + [[nodiscard]] virtual SHMatrix GetTRS () const noexcept = 0; + + /** + * @brief + * Computes a tight-fitting AABB around this shape. + * @return + * An AABB. + */ + [[nodiscard]] virtual SHAABB ComputeAABB () const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ @@ -150,16 +191,17 @@ namespace SHADE SHCollisionShapeID id; - SHPhysicsMaterial material; + SHCompositeCollider* collider; // The collider it belongs to. + SHCollisionTag* collisionTag; + SHPhysicsMaterial material; // TODO: Change to pointer once instancing is supported - SHCollider* collider; // The collider it belongs to. - SHTransform transform; + SHTransform transform; // Stores the local position and rotation. // Needed for conversion to euler angles SHVec3 rotationOffset; - uint8_t flags; // 0 0 0 isColliding trigger capsule sphere box - SHCollisionTag* collisionTag; + uint8_t flags; // 0 0 0 trigger convexHull capsule sphere box + RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp index 46adb47b..e0202d67 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp @@ -39,12 +39,12 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHSphereCollisionShape* SHCollisionShapeLibrary::CreateSphere(SHCollisionShapeID id, const SHSphereCreateInfo& createInfo) + SHSphere* SHCollisionShapeLibrary::CreateSphere(SHCollisionShapeID id, const SHSphereCreateInfo& createInfo) { - const auto RESULT = spheres.emplace(id, new SHSphereCollisionShape{ id }); + const auto RESULT = spheres.emplace(id, new SHSphere{ id }); if (RESULT.second) { - SHSphereCollisionShape* sphere = RESULT.first->second; + SHSphere* sphere = RESULT.first->second; sphere->Center = createInfo.Center; sphere->Radius = createInfo.Radius; @@ -57,12 +57,12 @@ namespace SHADE return spheres.find(id)->second; } - SHBoxCollisionShape* SHCollisionShapeLibrary::CreateBox(SHCollisionShapeID id, const SHBoxCreateInfo& createInfo) + SHBox* SHCollisionShapeLibrary::CreateBox(SHCollisionShapeID id, const SHBoxCreateInfo& createInfo) { - const auto RESULT = boxes.emplace(id, new SHBoxCollisionShape{ id }); + const auto RESULT = boxes.emplace(id, new SHBox{ id }); if (RESULT.second) { - SHBoxCollisionShape* box = RESULT.first->second; + SHBox* box = RESULT.first->second; box->Center = createInfo.Center; box->Extents = createInfo.Extents; @@ -90,7 +90,7 @@ namespace SHADE } case SHCollisionShape::Type::SPHERE: { - SHSphereCollisionShape* sphere = spheres.find(shape->id)->second; + SHSphere* sphere = spheres.find(shape->id)->second; spheres.erase(shape->id); delete sphere; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h index dbfc4fc7..462b8dd8 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h @@ -13,8 +13,8 @@ #include // Project Header -#include "SHSphereCollisionShape.h" -#include "SHBoxCollisionShape.h" +#include "SHSphere.h" +#include "SHBox.h" namespace SHADE { @@ -51,7 +51,7 @@ namespace SHADE * @return * A new sphere collision shape. */ - SHSphereCollisionShape* CreateSphere (SHCollisionShapeID id, const SHSphereCreateInfo& createInfo); + SHSphere* CreateSphere (SHCollisionShapeID id, const SHSphereCreateInfo& createInfo); /** * @brief @@ -63,7 +63,7 @@ namespace SHADE * @return * A new box collision shape. */ - SHBoxCollisionShape* CreateBox (SHCollisionShapeID id, const SHBoxCreateInfo& createInfo); + SHBox* CreateBox (SHCollisionShapeID id, const SHBoxCreateInfo& createInfo); /** * @brief @@ -85,8 +85,8 @@ namespace SHADE // We use unordered maps for fast lookup when deleting. // 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; - using Boxes = std::unordered_map; + using Spheres = std::unordered_map; + using Boxes = std::unordered_map; /*---------------------------------------------------------------------------------*/ /* Data Members */ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp similarity index 76% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp index 51d4e684..a2aef745 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHConvexPolyhedronCollisionShape.h" +#include "SHConvexPolyhedron.h" namespace SHADE { @@ -19,12 +19,12 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHConvexPolyhedronCollisionShape::SHConvexPolyhedronCollisionShape(SHCollisionShapeID id,Type polyhedronType) noexcept + SHConvexPolyhedron::SHConvexPolyhedron(SHCollisionShapeID id,Type polyhedronType) noexcept : SHCollisionShape (id, polyhedronType) , halfEdgeStructure { nullptr } {} - SHConvexPolyhedronCollisionShape::SHConvexPolyhedronCollisionShape(const SHConvexPolyhedronCollisionShape& rhs) noexcept + SHConvexPolyhedron::SHConvexPolyhedron(const SHConvexPolyhedron& rhs) noexcept : SHCollisionShape (rhs.id, rhs.GetType()) , halfEdgeStructure { nullptr } { @@ -37,7 +37,7 @@ namespace SHADE collisionTag = rhs.collisionTag; } - SHConvexPolyhedronCollisionShape::SHConvexPolyhedronCollisionShape(SHConvexPolyhedronCollisionShape&& rhs) noexcept + SHConvexPolyhedron::SHConvexPolyhedron(SHConvexPolyhedron&& rhs) noexcept : SHCollisionShape (rhs.id, rhs.GetType()) , halfEdgeStructure { nullptr } { @@ -54,7 +54,7 @@ namespace SHADE /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHConvexPolyhedronCollisionShape& SHConvexPolyhedronCollisionShape::operator=(const SHConvexPolyhedronCollisionShape& rhs) noexcept + SHConvexPolyhedron& SHConvexPolyhedron::operator=(const SHConvexPolyhedron& rhs) noexcept { if (this == &rhs) return *this; @@ -73,7 +73,7 @@ namespace SHADE return *this; } - SHConvexPolyhedronCollisionShape& SHConvexPolyhedronCollisionShape::operator=(SHConvexPolyhedronCollisionShape&& rhs) noexcept + SHConvexPolyhedron& SHConvexPolyhedron::operator=(SHConvexPolyhedron&& rhs) noexcept { material = rhs.material; collider = rhs.collider; @@ -93,28 +93,28 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHHalfEdgeStructure* SHConvexPolyhedronCollisionShape::GetHalfEdgeStructure() const noexcept + const SHHalfEdgeStructure* SHConvexPolyhedron::GetHalfEdgeStructure() const noexcept { return halfEdgeStructure; } - int32_t SHConvexPolyhedronCollisionShape::GetFaceCount() const noexcept + int32_t SHConvexPolyhedron::GetFaceCount() const noexcept { return halfEdgeStructure->GetFaceCount(); } - int32_t SHConvexPolyhedronCollisionShape::GetHalfEdgeCount() const noexcept + int32_t SHConvexPolyhedron::GetHalfEdgeCount() const noexcept { return halfEdgeStructure->GetHalfEdgeCount(); } - const SHHalfEdgeStructure::Face& SHConvexPolyhedronCollisionShape::GetFace(int index) const + const SHHalfEdgeStructure::Face& SHConvexPolyhedron::GetFace(int index) const { // Assume it has already been initialised return halfEdgeStructure->GetFace(index); } - const SHHalfEdgeStructure::HalfEdge& SHConvexPolyhedronCollisionShape::GetHalfEdge(int index) const + const SHHalfEdgeStructure::HalfEdge& SHConvexPolyhedron::GetHalfEdge(int index) const { // Assume it has already been initialised return halfEdgeStructure->GetHalfEdge(index); diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h similarity index 83% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h index 6095cbca..cdc7f45f 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedronCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h @@ -24,14 +24,14 @@ namespace SHADE * @brief * Encapsulates a convex polyhedron shape used for Physics Simulations.. */ - class SH_API SHConvexPolyhedronCollisionShape : public SHCollisionShape + class SH_API SHConvexPolyhedron : public SHCollisionShape { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCollider; + friend class SHCompositeCollider; friend class SHCollision; friend class SHCollisionShapeLibrary; @@ -40,18 +40,18 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHConvexPolyhedronCollisionShape (SHCollisionShapeID id, Type polyhedronType) noexcept; - SHConvexPolyhedronCollisionShape (const SHConvexPolyhedronCollisionShape& rhs) noexcept; - SHConvexPolyhedronCollisionShape (SHConvexPolyhedronCollisionShape&& rhs) noexcept; + SHConvexPolyhedron (SHCollisionShapeID id, Type polyhedronType) noexcept; + SHConvexPolyhedron (const SHConvexPolyhedron& rhs) noexcept; + SHConvexPolyhedron (SHConvexPolyhedron&& rhs) noexcept; - ~SHConvexPolyhedronCollisionShape () override = default; + ~SHConvexPolyhedron () override = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHConvexPolyhedronCollisionShape& operator=(const SHConvexPolyhedronCollisionShape& rhs) noexcept; - SHConvexPolyhedronCollisionShape& operator=(SHConvexPolyhedronCollisionShape&& rhs) noexcept; + SHConvexPolyhedron& operator=(const SHConvexPolyhedron& rhs) noexcept; + SHConvexPolyhedron& operator=(SHConvexPolyhedron&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.cpp similarity index 51% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.cpp index a5c82017..04f8718e 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.cpp @@ -11,12 +11,12 @@ #include // Primary Header -#include "SHSphereCollisionShape.h" +#include "SHSphere.h" // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" namespace SHADE { @@ -24,64 +24,42 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHSphereCollisionShape::SHSphereCollisionShape(SHCollisionShapeID id) noexcept - : SHCollisionShape (id, SHCollisionShape::Type::SPHERE) - , SHSphere () + SHSphere::SHSphere(SHCollisionShapeID id) noexcept + : SHCollisionShape (id, Type::SPHERE) , relativeRadius { 1.0f } , scale { 1.0f } - {} - - SHSphereCollisionShape::SHSphereCollisionShape(const SHSphereCollisionShape& rhs) noexcept - : SHCollisionShape (rhs.id, SHCollisionShape::Type::SPHERE) - , SHSphere (rhs.Center, rhs.Radius) - , relativeRadius { rhs.relativeRadius } - , 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; + Radius = 0.5f; } - SHSphereCollisionShape::SHSphereCollisionShape(SHSphereCollisionShape&& rhs) noexcept - : SHCollisionShape (rhs.id, SHCollisionShape::Type::SPHERE) - , SHSphere (rhs.Center, rhs.Radius) + SHSphere::SHSphere(const SHSphere& rhs) noexcept + : SHCollisionShape ( rhs ) , relativeRadius { rhs.relativeRadius } , scale { rhs.scale } { + Center = rhs.Center; + Radius = rhs.Radius; + } - 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; + SHSphere::SHSphere(SHSphere&& rhs) noexcept + : SHCollisionShape ( rhs ) + , relativeRadius { rhs.relativeRadius } + , scale { rhs.scale } + { + Center = rhs.Center; + Radius = rhs.Radius; } /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHSphereCollisionShape& SHSphereCollisionShape::operator=(const SHSphereCollisionShape& rhs) noexcept + SHSphere& SHSphere::operator=(const SHSphere& 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; + SHCollisionShape::operator=(rhs); // Sphere Properties @@ -96,18 +74,9 @@ namespace SHADE return *this; } - SHSphereCollisionShape& SHSphereCollisionShape::operator=(SHSphereCollisionShape&& rhs) noexcept + SHSphere& SHSphere::operator=(SHSphere&& 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; + SHCollisionShape::operator=(rhs); // Sphere Properties @@ -126,51 +95,73 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHVec3 SHSphereCollisionShape::GetCenter() const noexcept - { - return Center; - } - - float SHSphereCollisionShape::GetWorldRadius() const noexcept + float SHSphere::GetWorldRadius() const noexcept { return Radius; } - float SHSphereCollisionShape::GetRelativeRadius() const noexcept + float SHSphere::GetRelativeRadius() const noexcept { return relativeRadius; } - SHVec3 SHSphereCollisionShape::GetPosition() const noexcept + SHVec3 SHSphere::GetWorldCentroid() const noexcept { return Center; } - SHQuaternion SHSphereCollisionShape::GetOrientation() const noexcept + SHVec3 SHSphere::GetRelativeCentroid() const noexcept { - return collider->GetTransform().orientation * transform.orientation; + if (collider) + return SHVec3{ Center } - collider->GetPosition(); + + return Center; } - float SHSphereCollisionShape::GetVolume() const noexcept - { - return Volume(); - } - - SHVec3 SHSphereCollisionShape::GetLocalCentroid() const noexcept + SHVec3 SHSphere::GetLocalCentroid() const noexcept { return SHVec3::Zero; } + SHQuaternion SHSphere::GetWorldOrientation() const noexcept + { + if (collider) + return collider->GetOrientation() * transform.orientation; + + return transform.orientation; + } + + SHQuaternion SHSphere::GetRelativeOrientation() const noexcept + { + return transform.orientation; + } + + float SHSphere::GetVolume() const noexcept + { + return (4.0f / 3.0f) * SHMath::PI * (Radius * Radius * Radius); + } + + float SHSphere::GetSurfaceArea() const noexcept + { + return 4.0f * SHMath::PI * (Radius * Radius); + } + + SHMatrix SHSphere::GetInertiaTensor(float mass) const noexcept + { + static constexpr float TWO_OVER_FIVE = 2.0f / 5.0f; + + const float DIAGONAL = TWO_OVER_FIVE * mass * (Radius * Radius); + + SHMatrix result; + result.m[0][0] = result.m[1][1] = result.m[2][2] = DIAGONAL; + return result; + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHSphereCollisionShape::SetCenter(const SHVec3& newCenter) noexcept - { - Center = newCenter; - } - - void SHSphereCollisionShape::SetWorldRadius(float newWorldRadius) noexcept + void SHSphere::SetWorldRadius(float newWorldRadius) noexcept { Radius = newWorldRadius; @@ -178,7 +169,7 @@ namespace SHADE relativeRadius = 2.0f * Radius / scale; } - void SHSphereCollisionShape::SetRelativeRadius(float newRelativeRadius) noexcept + void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept { relativeRadius = newRelativeRadius; @@ -186,7 +177,7 @@ namespace SHADE Radius = relativeRadius * scale * 0.5f; } - void SHSphereCollisionShape::SetScale(float maxScale) noexcept + void SHSphere::SetScale(float maxScale) noexcept { scale = std::fabs(maxScale); @@ -198,7 +189,7 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHSphereCollisionShape::ComputeTransforms() noexcept + void SHSphere::Update() noexcept { const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); @@ -212,42 +203,35 @@ namespace SHADE Center = SHVec3::Transform(transform.position, TRS); } - bool SHSphereCollisionShape::TestPoint(const SHVec3& point) const noexcept + bool SHSphere::TestPoint(const SHVec3& point) const noexcept { - return SHSphere::TestPoint(point); + return Contains(point); } - SHRaycastResult SHSphereCollisionShape::Raycast(const SHRay& ray) const noexcept + SHRaycastResult SHSphere::Raycast(const SHRay& ray) const noexcept { - return SHSphere::Raycast(ray); - } + SHRaycastResult result; - SHMatrix SHSphereCollisionShape::GetInertiaTensor(float mass) const noexcept - { - static constexpr float TWO_OVER_FIVE = 2.0f / 5.0f; + 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); + result.normal = SHVec3::Normalise(result.position - Center); + } - const float DIAGONAL = TWO_OVER_FIVE * mass * (Radius * Radius); - - SHMatrix result; - result.m[0][0] = result.m[1][1] = result.m[2][2] = DIAGONAL; return result; } - SHMatrix SHSphereCollisionShape::ComputeWorldTransform() const noexcept + SHMatrix SHSphere::GetTRS() const noexcept { - const SHTransform& PARENT_TRANSFORM = collider->GetTransform(); - const SHQuaternion ROTATION = PARENT_TRANSFORM.orientation * transform.orientation; - const SHVec3 SCALE{ Radius }; + const SHQuaternion ROTATION = collider ? collider->GetTransform().orientation * transform.orientation : transform.orientation; + const SHVec3 SCALE { Radius }; - return SHMatrix::Transform - ( - Center - , ROTATION - , SCALE - ); + return SHMatrix::Transform(Center, ROTATION, SCALE); } - SHAABB SHSphereCollisionShape::ComputeAABB() const noexcept + SHAABB SHSphere::ComputeAABB() const noexcept { return SHAABB{ Center, SHVec3{ Radius } }; } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.h similarity index 55% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h rename to SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.h index 7dbdf13d..c4e97fe0 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphereCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.h @@ -10,8 +10,9 @@ #pragma once +#include + // Project Headers -#include "Math/Geometry/SHSphere.h" #include "SHCollisionShape.h" namespace SHADE @@ -37,15 +38,15 @@ namespace SHADE * @brief * Encapsulate a Sphere Shape used for Physics Simulations. */ - class SH_API SHSphereCollisionShape final : public SHCollisionShape - , private SHSphere + class SH_API SHSphere final : public SHCollisionShape + , private DirectX::BoundingSphere { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCollider; + friend class SHCompositeCollider; friend class SHCollision; friend class SHCollisionShapeLibrary; @@ -54,37 +55,39 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHSphereCollisionShape (SHCollisionShapeID id) noexcept; - SHSphereCollisionShape (const SHSphereCollisionShape& rhs) noexcept; - SHSphereCollisionShape (SHSphereCollisionShape&& rhs) noexcept; + SHSphere (SHCollisionShapeID id) noexcept; + SHSphere (const SHSphere& rhs) noexcept; + SHSphere (SHSphere&& rhs) noexcept; - ~SHSphereCollisionShape () override = default; + ~SHSphere () override = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHSphereCollisionShape& operator= (const SHSphereCollisionShape& rhs) noexcept; - SHSphereCollisionShape& operator= (SHSphereCollisionShape&& rhs) noexcept; + SHSphere& operator= (const SHSphere& rhs) noexcept; + SHSphere& operator= (SHSphere&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHVec3 GetCenter () const noexcept; - [[nodiscard]] float GetWorldRadius () const noexcept; - [[nodiscard]] float GetRelativeRadius () const noexcept; + [[nodiscard]] float GetWorldRadius () const noexcept; + [[nodiscard]] float GetRelativeRadius () const noexcept; - [[nodiscard]] SHVec3 GetPosition () const noexcept override; - [[nodiscard]] SHQuaternion GetOrientation () const noexcept override; - [[nodiscard]] float GetVolume () const noexcept override; - [[nodiscard]] SHVec3 GetLocalCentroid () const noexcept override; + [[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override; + [[nodiscard]] SHVec3 GetRelativeCentroid () const noexcept override; + [[nodiscard]] SHVec3 GetLocalCentroid () const noexcept override; + [[nodiscard]] SHQuaternion GetWorldOrientation () const noexcept override; + [[nodiscard]] SHQuaternion GetRelativeOrientation () const noexcept override; + [[nodiscard]] float GetVolume () const noexcept override; + [[nodiscard]] float GetSurfaceArea () const noexcept override; + [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCenter (const SHVec3& newCenter) noexcept; void SetWorldRadius (float newWorldRadius) noexcept; void SetRelativeRadius (float newRelativeRadius) noexcept; void SetScale (float maxScale) noexcept; @@ -93,58 +96,11 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Recomputes the transform of this sphere. - */ - void ComputeTransforms () noexcept override; - - /** - * @brief - * Tests if a point is inside the sphere. - * @param point - * The point to test. - * @return - * True if the point is inside the sphere. - */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - - /** - * @brief - * Casts a ray against this sphere. - * @param ray - * The ray to cast. - * @return - * An object holding the results of the raycast.
- * 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 sphere. - * @param mass - * The mass of the sphere. - * @return - * The inertia tensor of the sphere. - */ - [[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; + void Update () noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHMatrix GetTRS () const noexcept override; + [[nodiscard]] SHAABB ComputeAABB () const noexcept override; private: /*---------------------------------------------------------------------------------*/ @@ -152,7 +108,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ float relativeRadius; - float scale; // Intended to be passed in by the base collider. + float scale; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp index 4bb22697..8bd26e91 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp @@ -14,7 +14,7 @@ #include "SHCollisionKey.h" // Project Headers -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Physics/Interface/SHColliderComponent.h" diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp index 1b03feab..e7da5f8b 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp @@ -16,7 +16,7 @@ // Project Headers #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHBoxCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHBox.h" // TODO diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 0c65a94f..e98983b4 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -84,27 +84,9 @@ namespace SHADE // Sphere VS Convex - static FaceQuery findClosestFace - ( - const SHSphereCollisionShape& sphere - , const SHConvexPolyhedronCollisionShape& polyhedron - ) noexcept; - - static int32_t findClosestPoint - ( - const SHSphereCollisionShape& sphere - , const SHConvexPolyhedronCollisionShape& polyhedron - , int32_t faceIndex - ) noexcept; - - static int32_t findVoronoiRegion - ( - const SHSphereCollisionShape& sphere - , const SHVec3& faceVertex - , const SHVec3& faceNormal - , const SHVec3& tangent1 - , const SHVec3& tangent2 - ) noexcept; + static FaceQuery findClosestFace (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron) noexcept; + static int32_t findClosestPoint (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron, int32_t faceIndex) noexcept; + static int32_t findVoronoiRegion (const SHSphere& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; // Capsule VS Convex diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp index 3e308aed..d7eb02fc 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp @@ -15,7 +15,7 @@ // Project Headers #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHSphere.h" // TODO diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 8245d672..1b97a7c6 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -18,7 +18,7 @@ #include "Math/Geometry/SHPlane.h" #include "Math/SHMathHelpers.h" #include "Physics/Collision/CollisionShapes/SHCollisionShape.h" -#include "Physics/Collision/CollisionShapes/SHBoxCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHBox.h" namespace SHADE { @@ -28,10 +28,10 @@ namespace SHADE bool SHCollision::SphereVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - const SHSphereCollisionShape& SPHERE = dynamic_cast(A); - const SHConvexPolyhedronCollisionShape& POLYHEDRON = dynamic_cast(B); + const SHSphere& SPHERE = dynamic_cast(A); + const SHConvexPolyhedron& POLYHEDRON = dynamic_cast(B); - const SHVec3 CENTER = SPHERE.GetCenter(); + const SHVec3 CENTER = SPHERE.Center; const float RADIUS = SPHERE.GetWorldRadius(); // Find closest face @@ -76,10 +76,10 @@ namespace SHADE { // Convert to underlying types // For the convex, we only need the convex polyhedron shape since the get vertex is pure virtual. - const SHSphereCollisionShape& SPHERE = dynamic_cast(A); - const SHConvexPolyhedronCollisionShape& POLYHEDRON = dynamic_cast(B); + const SHSphere& SPHERE = dynamic_cast(A); + const SHConvexPolyhedron& POLYHEDRON = dynamic_cast(B); - const SHVec3 CENTER = SPHERE.GetCenter(); + const SHVec3 CENTER = SPHERE.Center; const float RADIUS = SPHERE.GetWorldRadius(); const FaceQuery FACE_QUERY = findClosestFace(SPHERE, POLYHEDRON); @@ -98,7 +98,7 @@ namespace SHADE manifold.normal = -POLYHEDRON.GetNormal(FACE_QUERY.closestFace); contact.penetration = PENETRATION; - contact.position = SPHERE.GetCenter(); + contact.position = CENTER; manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; @@ -187,13 +187,13 @@ namespace SHADE SHCollision::FaceQuery SHCollision::findClosestFace ( - const SHSphereCollisionShape& sphere - , const SHConvexPolyhedronCollisionShape& polyhedron + const SHSphere& sphere + , const SHConvexPolyhedron& polyhedron ) noexcept { FaceQuery faceQuery; - const SHVec3 CENTER = sphere.GetCenter(); + const SHVec3 CENTER = sphere.Center; const float RADIUS = sphere.GetWorldRadius(); /* @@ -233,15 +233,15 @@ namespace SHADE int32_t SHCollision::findClosestPoint ( - const SHSphereCollisionShape& sphere - , const SHConvexPolyhedronCollisionShape& polyhedron - , int32_t faceIndex + const SHSphere& sphere + , const SHConvexPolyhedron& polyhedron + , int32_t faceIndex ) noexcept { // Find closest point on face int32_t closestPointIndex = -1; - const SHVec3 CENTER = sphere.GetCenter(); + const SHVec3 CENTER = sphere.Center; const SHHalfEdgeStructure::Face& FACE = polyhedron.GetFace(faceIndex); const int32_t NUM_VERITICES = static_cast(FACE.vertexIndices.size()); @@ -264,11 +264,11 @@ namespace SHADE int32_t SHCollision::findVoronoiRegion ( - const SHSphereCollisionShape& sphere - , const SHVec3& faceVertex - , const SHVec3& faceNormal - , const SHVec3& tangent1 - , const SHVec3& tangent2 + const SHSphere& sphere + , const SHVec3& faceVertex + , const SHVec3& faceNormal + , const SHVec3& tangent1 + , const SHVec3& tangent2 ) noexcept { static constexpr int NUM_TANGENTS = 2; @@ -288,7 +288,7 @@ namespace SHADE * */ - const SHVec3& CENTER = sphere.GetCenter(); + const SHVec3 CENTER = sphere.Center; const float RADIUS = sphere.GetWorldRadius(); const SHVec3 TANGENTS [NUM_TANGENTS] { tangent1, tangent2 }; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp index 07b6c9a6..aa270b16 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp @@ -15,7 +15,7 @@ // Project Headers #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHSphere.h" namespace SHADE { @@ -25,22 +25,41 @@ namespace SHADE bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); - const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); + const SHSphere& SPHERE_A = dynamic_cast(A); + const SHSphere& SPHERE_B = dynamic_cast(B); - return SHSphere::Intersect(SPHERE_A, SPHERE_B); + const SHVec3 CENTER_A = SPHERE_A.Center; + const float RADIUS_A = SPHERE_A.Radius; + const SHVec3 CENTER_B = SPHERE_B.Center; + const float RADIUS_B = SPHERE_B.Radius; + + + const SHVec3 A_TO_B = CENTER_B - CENTER_A; + const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared(); + + const float COMBINED_RADIUS = RADIUS_B + RADIUS_A; + const float COMBINED_RADIUS_SQUARED = COMBINED_RADIUS * COMBINED_RADIUS; + + if (DISTANCE_BETWEEN_CENTERS_SQUARED > COMBINED_RADIUS_SQUARED) + return false; } bool SHCollision::SphereVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { // Convert to underlying types - const SHSphereCollisionShape& SPHERE_A = dynamic_cast(A); - const SHSphereCollisionShape& SPHERE_B = dynamic_cast(B); + const SHSphere& SPHERE_A = dynamic_cast(A); + const SHSphere& SPHERE_B = dynamic_cast(B); - const SHVec3 A_TO_B = SPHERE_B.GetCenter() - SPHERE_A.GetCenter(); + const SHVec3 CENTER_A = SPHERE_A.Center; + const float RADIUS_A = SPHERE_A.Radius; + const SHVec3 CENTER_B = SPHERE_B.Center; + const float RADIUS_B = SPHERE_B.Radius; + + + const SHVec3 A_TO_B = CENTER_B - CENTER_A; const float DISTANCE_BETWEEN_CENTERS_SQUARED = A_TO_B.LengthSquared(); - const float COMBINED_RADIUS = (SPHERE_A.GetWorldRadius() + SPHERE_B.GetWorldRadius()); + const float COMBINED_RADIUS = RADIUS_B + RADIUS_A; const float COMBINED_RADIUS_SQUARED = COMBINED_RADIUS * COMBINED_RADIUS; if (DISTANCE_BETWEEN_CENTERS_SQUARED > COMBINED_RADIUS_SQUARED) @@ -56,15 +75,15 @@ namespace SHADE if (SHMath::CompareFloat(DISTANCE_BETWEEN_CENTERS_SQUARED, 0.0f)) { manifold.normal = SHVec3::UnitY; - contact.position = SPHERE_A.GetCenter(); - contact.penetration = SPHERE_B.GetWorldRadius(); + contact.position = CENTER_A; + contact.penetration = RADIUS_B; manifold.contacts[numContacts++] = contact; } else { manifold.normal = SHVec3::Normalise(A_TO_B); - contact.position = SPHERE_B.GetCenter() - (manifold.normal * SPHERE_B.GetWorldRadius()); + contact.position = CENTER_B - manifold.normal * RADIUS_B; contact.penetration = COMBINED_RADIUS - A_TO_B.Length(); manifold.contacts[numContacts++] = contact; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp index 88fdac40..e410ac36 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -40,7 +40,7 @@ namespace SHADE /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollisionSpace::AddCollider(SHCollider* collider) noexcept + void SHCollisionSpace::AddCollider(SHCompositeCollider* collider) noexcept { const bool INSERTED = colliders.emplace(collider->entityID, collider).second; if (!INSERTED) @@ -56,7 +56,7 @@ namespace SHADE broadphase.Insert(shape->id, shape->ComputeAABB()); } - void SHCollisionSpace::RemoveCollider(SHCollider* collider) noexcept + void SHCollisionSpace::RemoveCollider(SHCompositeCollider* collider) noexcept { colliders.erase(collider->entityID); @@ -209,12 +209,12 @@ namespace SHADE { case SHCollisionShape::Type::SPHERE: { - baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); + baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); break; } case SHCollisionShape::Type::BOX: { - baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); + baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); break; } case SHCollisionShape::Type::CAPSULE: @@ -246,7 +246,7 @@ namespace SHADE /* Private Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollisionSpace::broadphaseQuery(SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept + void SHCollisionSpace::broadphaseQuery(SHRigidBody::Type rigidBodyType, SHCompositeCollider* collider) noexcept { for (auto* shape : collider->shapes) { diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h index 8607cf45..fa1f0d16 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h @@ -18,7 +18,7 @@ // Project Headers #include "Broadphase/SHDynamicAABBTree.h" #include "Physics/Dynamics/SHContactManager.h" -#include "SHCollider.h" +#include "SHCompositeCollider.h" #include "SHPhysicsRaycastResult.h" #include "CollisionTags/SHCollisionTags.h" #include "CollisionTags/SHCollisionTags.h" @@ -118,7 +118,7 @@ namespace SHADE * @param collider * A collider to add. Duplicates will be ignored. */ - void AddCollider (SHCollider* collider) noexcept; + void AddCollider (SHCompositeCollider* collider) noexcept; /** * @brief @@ -127,7 +127,7 @@ namespace SHADE * @param collider * A collider to remove. If a reference to it doesn't exist, it will be ignored. */ - void RemoveCollider (SHCollider* collider) noexcept; + void RemoveCollider (SHCompositeCollider* collider) noexcept; /** * @brief @@ -165,7 +165,7 @@ namespace SHADE SHCollisionShape* B = nullptr; }; - using Colliders = std::unordered_map; + using Colliders = std::unordered_map; using NarrowphaseBatch = std::unordered_map; /*---------------------------------------------------------------------------------*/ @@ -185,7 +185,7 @@ namespace SHADE // Broadphase helpers - void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; + void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCompositeCollider* collider) noexcept; // Narrowphase helpers diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp similarity index 81% rename from SHADE_Engine/src/Physics/Collision/SHCollider.cpp rename to SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp index 021605c7..97fef331 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHCollider.h" +#include "SHCompositeCollider.h" // Project Headers #include "Broadphase/SHDynamicAABBTree.h" @@ -27,7 +27,7 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept + SHCompositeCollider::SHCompositeCollider(EntityID eid, const SHTransform& worldTransform) noexcept : entityID { eid } , active { true } , debugDraw { false } @@ -38,7 +38,7 @@ namespace SHADE , transform { worldTransform } {} - SHCollider::SHCollider(const SHCollider& rhs) noexcept + SHCompositeCollider::SHCompositeCollider(const SHCompositeCollider& rhs) noexcept : entityID { rhs.entityID } , active { rhs.active } , debugDraw { rhs.debugDraw } @@ -57,7 +57,7 @@ namespace SHADE copyShapes(rhs); } - SHCollider::SHCollider(SHCollider&& rhs) noexcept + SHCompositeCollider::SHCompositeCollider(SHCompositeCollider&& rhs) noexcept : entityID { rhs.entityID } , active { rhs.active } , debugDraw { rhs.debugDraw } @@ -76,7 +76,7 @@ namespace SHADE copyShapes(rhs); } - SHCollider::~SHCollider() noexcept + SHCompositeCollider::~SHCompositeCollider() noexcept { if (!shapeLibrary) { @@ -92,7 +92,7 @@ namespace SHADE /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollider& SHCollider::operator=(const SHCollider& rhs) noexcept + SHCompositeCollider& SHCompositeCollider::operator=(const SHCompositeCollider& rhs) noexcept { if (this == &rhs) return *this; @@ -117,7 +117,7 @@ namespace SHADE return *this; } - SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept + SHCompositeCollider& SHCompositeCollider::operator=(SHCompositeCollider&& rhs) noexcept { if (!shapeLibrary) { @@ -143,47 +143,47 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - EntityID SHCollider::GetEntityID() const noexcept + EntityID SHCompositeCollider::GetEntityID() const noexcept { return entityID; } - bool SHCollider::IsActive() const noexcept + bool SHCompositeCollider::IsActive() const noexcept { return active; } - bool SHCollider::GetDebugDrawState() const noexcept + bool SHCompositeCollider::GetDebugDrawState() const noexcept { return debugDraw; } - const SHTransform& SHCollider::GetTransform() const noexcept + const SHTransform& SHCompositeCollider::GetTransform() const noexcept { return transform; } - const SHVec3& SHCollider::GetPosition() const noexcept + const SHVec3& SHCompositeCollider::GetPosition() const noexcept { return transform.position; } - const SHQuaternion& SHCollider::GetOrientation() const noexcept + const SHQuaternion& SHCompositeCollider::GetOrientation() const noexcept { return transform.orientation; } - const SHVec3& SHCollider::GetScale() const noexcept + const SHVec3& SHCompositeCollider::GetScale() const noexcept { return transform.scale; } - const SHCollider::CollisionShapes& SHCollider::GetCollisionShapes() const noexcept + const SHCompositeCollider::CollisionShapes& SHCompositeCollider::GetCollisionShapes() const noexcept { return shapes; } - SHCollisionShape* SHCollider::GetCollisionShape(int index) const + SHCollisionShape* SHCompositeCollider::GetCollisionShape(int index) const { const int NUM_SHAPES = static_cast(shapes.size()); @@ -197,7 +197,7 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollider::SetIsActive(bool state) noexcept + void SHCompositeCollider::SetIsActive(bool state) noexcept { if (active == state) return; @@ -216,7 +216,7 @@ namespace SHADE } } - void SHCollider::SetDebugDrawState(bool state) noexcept + void SHCompositeCollider::SetDebugDrawState(bool state) noexcept { debugDraw = state; @@ -234,36 +234,36 @@ namespace SHADE #endif } - void SHCollider::SetRigidBody(SHRigidBody* rb) noexcept + void SHCompositeCollider::SetRigidBody(SHRigidBody* rb) noexcept { rigidBody = rb; } - void SHCollider::SetTransform(const SHTransform& newTransform) noexcept + void SHCompositeCollider::SetTransform(const SHTransform& newTransform) noexcept { hasMoved = true; transform = newTransform; } - void SHCollider::SetPosition(const SHVec3& newPosition) noexcept + void SHCompositeCollider::SetPosition(const SHVec3& newPosition) noexcept { hasMoved = true; transform.position = newPosition; } - void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept + void SHCompositeCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept { hasMoved = true; transform.orientation = newOrientation; } - void SHCollider::SetScale(const SHVec3& newScale) noexcept + void SHCompositeCollider::SetScale(const SHVec3& newScale) noexcept { hasMoved = true; transform.scale = newScale; } - void SHCollider::SetFactory(SHCollisionShapeLibrary* factory) noexcept + void SHCompositeCollider::SetFactory(SHCollisionShapeLibrary* factory) noexcept { shapeLibrary = factory; } @@ -272,12 +272,12 @@ namespace SHADE /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHMatrix& SHCollider::ComputeTransformTRS() noexcept + const SHMatrix& SHCompositeCollider::ComputeTransformTRS() noexcept { return transform.ComputeTRS(); } - int SHCollider::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) + int SHCompositeCollider::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) { if (!shapeLibrary) { @@ -304,7 +304,7 @@ namespace SHADE const uint32_t NEW_INDEX = static_cast(shapes.size()); const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - SHSphereCollisionShape* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + SHSphere* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); // Set offsets sphere->collider = this; @@ -332,7 +332,7 @@ namespace SHADE return static_cast(NEW_INDEX); } - int SHCollider::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset) + int SHCompositeCollider::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset) { if (!shapeLibrary) { @@ -357,7 +357,7 @@ namespace SHADE const uint32_t NEW_INDEX = static_cast(shapes.size()); const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - SHBoxCollisionShape* box = shapeLibrary->CreateBox(NEW_SHAPE_ID, BOX_CREATE_INFO); + SHBox* box = shapeLibrary->CreateBox(NEW_SHAPE_ID, BOX_CREATE_INFO); // Set offsets box->collider = this; @@ -386,7 +386,7 @@ namespace SHADE } - void SHCollider::RemoveCollisionShape(int index) + void SHCompositeCollider::RemoveCollisionShape(int index) { if (!shapeLibrary) { @@ -434,23 +434,23 @@ namespace SHADE SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) } - void SHCollider::RecomputeShapes() noexcept + void SHCompositeCollider::RecomputeShapes() noexcept { for (auto* shape : shapes) - shape->ComputeTransforms(); + shape->Update(); } /*-----------------------------------------------------------------------------------*/ /* Private Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollider::copyShapes(const SHCollider& rhsCollider) + void SHCompositeCollider::copyShapes(const SHCompositeCollider& rhsCollider) { for (const auto* shape : rhsCollider.shapes) copyShape(shape); } - void SHCollider::copyShape(const SHCollisionShape* rhsShape) + void SHCompositeCollider::copyShape(const SHCollisionShape* rhsShape) { switch (rhsShape->GetType()) { @@ -460,7 +460,7 @@ namespace SHADE } case SHCollisionShape::Type::SPHERE: { - const SHSphereCollisionShape* RHS_SPHERE = dynamic_cast(rhsShape); + const SHSphere* RHS_SPHERE = dynamic_cast(rhsShape); const SHSphereCreateInfo SPHERE_CREATE_INFO { @@ -473,7 +473,7 @@ namespace SHADE const uint32_t NEW_INDEX = static_cast(shapes.size()); const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - SHSphereCollisionShape* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + SHSphere* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); *sphere = *RHS_SPHERE; shapes.emplace_back(sphere); diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h similarity index 92% rename from SHADE_Engine/src/Physics/Collision/SHCollider.h rename to SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h index c4a4ad17..e5ce8609 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h @@ -33,7 +33,7 @@ namespace SHADE * Base class for a collider. * There are only two collider types supported by SHADE Engine: Composite & Hull */ - class SH_API SHCollider + class SH_API SHCompositeCollider { private: /*---------------------------------------------------------------------------------*/ @@ -64,17 +64,17 @@ namespace SHADE * This is particularly important for composite colliders for offsets & relative sizes. * @return */ - SHCollider (EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; - SHCollider (const SHCollider& rhs) noexcept; - SHCollider (SHCollider&& rhs) noexcept; - ~SHCollider () noexcept; + SHCompositeCollider (EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; + SHCompositeCollider (const SHCompositeCollider& rhs) noexcept; + SHCompositeCollider (SHCompositeCollider&& rhs) noexcept; + ~SHCompositeCollider () noexcept; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHCollider& operator=(const SHCollider& rhs) noexcept; - SHCollider& operator=(SHCollider&& rhs) noexcept; + SHCompositeCollider& operator=(const SHCompositeCollider& rhs) noexcept; + SHCompositeCollider& operator=(SHCompositeCollider&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -192,7 +192,7 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - void copyShapes (const SHCollider& rhsCollider); + void copyShapes (const SHCompositeCollider& rhsCollider); void copyShape (const SHCollisionShape* rhsShape); }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 3b2de659..9688caa2 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -17,7 +17,7 @@ #include #include -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Tools/Logger/SHLogger.h" namespace SHADE @@ -296,7 +296,7 @@ namespace SHADE /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBody::SetCollider(SHCollider* c) noexcept + void SHRigidBody::SetCollider(SHCompositeCollider* c) noexcept { collider = c; } @@ -690,7 +690,7 @@ namespace SHADE trueMass.emplace_back(MASS); // Weighted sum of masses contribute to the centroid's location using the collider's local position. - localCentroid += MASS * (shape->GetPosition() - collider->GetPosition()); + localCentroid += MASS * shape->GetRelativeCentroid(); } if (totalMass > 0.0f) @@ -726,8 +726,9 @@ namespace SHADE I = R * I; // Parallel Axis Theorem + // https://en.wikipedia.org/wiki/Parallel_axis_theorem // J = I + m((R /dot R)E_3 - R /outerProduct R) - const SHVec3 R = SHAPE->GetPosition() - worldCentroid; + const SHVec3 R = SHAPE->GetWorldCentroid() - worldCentroid; const float R_MAG2 = R.LengthSquared(); const SHMatrix R_OX_R = SHVec3::OuterProduct(R, R); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 3c869ad2..44ae3f48 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -22,7 +22,7 @@ namespace SHADE /* Forward Declarations */ /*-------------------------------------------------------------------------------------*/ - class SHCollider; + class SHCompositeCollider; /*-------------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -113,7 +113,7 @@ namespace SHADE /* Setter Functions */ /*-----------------------------------------------------------------------------------*/ - void SetCollider (SHCollider* c) noexcept; + void SetCollider (SHCompositeCollider* c) noexcept; /** * @brief @@ -229,7 +229,7 @@ namespace SHADE // The entityID here is only meant for linking with the actual component in the engine. EntityID entityID; - SHCollider* collider; + SHCompositeCollider* collider; Type bodyType; diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp index 56c2ac7b..07e08b78 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -111,7 +111,7 @@ namespace SHADE collider->SetRigidBody(nullptr); } - SHCollider* SHPhysicsObject::CreateCollider(const SHTransform& transform) + SHCompositeCollider* SHPhysicsObject::CreateCollider(const SHTransform& transform) { if (collider) { @@ -119,7 +119,7 @@ namespace SHADE return collider; } - collider = new SHCollider{ entityID, transform }; + collider = new SHCompositeCollider{ entityID, transform }; // Link with rigidBody if it exists if (rigidBody) @@ -148,13 +148,13 @@ namespace SHADE /* Private Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsObject::deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCollider* rhsCollider) + void SHPhysicsObject::deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCompositeCollider* rhsCollider) { if (rhsRigidBody) rigidBody = new SHRigidBody{ *rhsRigidBody }; if (rhsCollider) - collider = new SHCollider { *rhsCollider }; + collider = new SHCompositeCollider { *rhsCollider }; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h index 2550543b..f1ee042d 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h @@ -11,7 +11,7 @@ #pragma once // Project Headers -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Physics/Dynamics/SHRigidBody.h" namespace SHADE @@ -33,7 +33,7 @@ namespace SHADE EntityID entityID = MAX_EID; SHRigidBody* rigidBody = nullptr; - SHCollider* collider = nullptr; + SHCompositeCollider* collider = nullptr; /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -91,7 +91,7 @@ namespace SHADE * Pointer to the collider that was created. The memory of this collider is managed * by the physics object itself. */ - SHCollider* CreateCollider (const SHTransform& transform = SHTransform::Identity); + SHCompositeCollider* CreateCollider (const SHTransform& transform = SHTransform::Identity); /** * @brief @@ -104,6 +104,6 @@ namespace SHADE /* Member Functions */ /*-----------------------------------------------------------------------------------*/ - void deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCollider* rhsCollider); + void deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCompositeCollider* rhsCollider); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index 7425f418..5569c713 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -32,12 +32,12 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollider* const SHColliderComponent::GetCollider() const noexcept + SHCompositeCollider* const SHColliderComponent::GetCollider() const noexcept { return collider; } - const SHCollider::CollisionShapes* const SHColliderComponent::GetCollisionShapes() const noexcept + const SHCompositeCollider::CollisionShapes* const SHColliderComponent::GetCollisionShapes() const noexcept { if (!collider) return nullptr; @@ -66,7 +66,7 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHColliderComponent::SetCollider(SHCollider* c) noexcept + void SHColliderComponent::SetCollider(SHCompositeCollider* c) noexcept { collider = c; } diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index d0cc7064..3c8e6342 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -14,7 +14,7 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" namespace SHADE { @@ -54,8 +54,8 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHCollider* const GetCollider () const noexcept; - [[nodiscard]] const SHCollider::CollisionShapes* const GetCollisionShapes() const noexcept; + [[nodiscard]] SHCompositeCollider* const GetCollider () const noexcept; + [[nodiscard]] const SHCompositeCollider::CollisionShapes* const GetCollisionShapes() const noexcept; [[nodiscard]] SHCollisionShape* const GetCollisionShape (int index) const; // Required for serialisation @@ -66,7 +66,7 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetCollider (SHCollider* c) noexcept; + void SetCollider (SHCompositeCollider* c) noexcept; // Required for serialisation @@ -77,7 +77,7 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHCollider* collider; + SHCompositeCollider* collider; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 3bd26925..1b1055be 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -122,7 +122,7 @@ namespace SHADE return onColliderDrawEvent.get()->handle; } - void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept + void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHCompositeCollider& collider) noexcept { for (const auto* SHAPE : collider.GetCollisionShapes()) { @@ -132,12 +132,12 @@ namespace SHADE { case SHCollisionShape::Type::SPHERE: { - debugDrawSystem->DrawWireSphere(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true); + debugDrawSystem->DrawWireSphere(SHAPE->GetTRS(), DRAW_COLOUR, true); break; } case SHCollisionShape::Type::BOX: { - debugDrawSystem->DrawWireCube(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true); + debugDrawSystem->DrawWireCube(SHAPE->GetTRS(), DRAW_COLOUR, true); break; } case SHCollisionShape::Type::CAPSULE: diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index efc0738e..c284792f 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -18,9 +18,9 @@ #include "ECS_Base/System/SHSystemRoutine.h" #include "Events/SHEvent.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Physics/Collision/SHPhysicsRaycastResult.h" -#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHSphere.h" namespace SHADE @@ -138,7 +138,7 @@ namespace SHADE SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); - static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; + static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCompositeCollider& collider) noexcept; static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; }; diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index a746df1b..18d8d63f 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -1,7 +1,7 @@ #pragma once #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" -#include "Physics/Collision/CollisionShapes/SHSphereCollisionShape.h" +#include "Physics/Collision/CollisionShapes/SHSphere.h" #include "Resource/SHResourceManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" @@ -144,13 +144,13 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - const auto& BOX = dynamic_cast(rhs); + const auto& BOX = dynamic_cast(rhs); node[HalfExtents] = BOX.GetRelativeExtents(); } break; case SHCollisionShape::Type::SPHERE: { - const auto& SPHERE = dynamic_cast(rhs); + const auto& SPHERE = dynamic_cast(rhs); node[Radius] = SPHERE.GetRelativeRadius(); } break; @@ -188,7 +188,7 @@ namespace YAML { if (node[HalfExtents].IsDefined()) { - auto* box = dynamic_cast(&rhs); + auto* box = dynamic_cast(&rhs); box->SetRelativeExtents(node[HalfExtents].as()); } } @@ -197,7 +197,7 @@ namespace YAML { if (node[Radius].IsDefined()) { - auto* sphere = dynamic_cast(&rhs); + auto* sphere = dynamic_cast(&rhs); sphere->SetRelativeRadius(node[Radius].as()); } } diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 9ed46289..f4b4f09d 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -128,19 +128,19 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 BoxCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + return Convert::ToCLI(getNativeCollisionShape().GetWorldCentroid()); } Vector3 BoxCollider::HalfExtents::get() { - return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); + return Convert::ToCLI(getNativeCollisionShape().GetWorldExtents()); } void BoxCollider::HalfExtents::set(Vector3 value) { - getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); + getNativeCollisionShape().SetWorldExtents(Convert::ToNative(value)); } Quaternion BoxCollider::Orientation::get() { - return Convert::ToCLI(getNativeCollisionShape().GetOrientation()); + return Convert::ToCLI(getNativeCollisionShape().GetWorldOrientation()); } /*---------------------------------------------------------------------------------*/ @@ -162,15 +162,15 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 SphereCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + return Convert::ToCLI(getNativeCollisionShape().GetWorldCentroid()); } float SphereCollider::Radius::get() { - return getNativeCollisionShape().GetWorldRadius(); + return getNativeCollisionShape().GetWorldRadius(); } void SphereCollider::Radius::set(float value) { - getNativeCollisionShape().SetWorldRadius(value); + getNativeCollisionShape().SetWorldRadius(value); } /*---------------------------------------------------------------------------------*/ @@ -178,11 +178,11 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool SphereCollider::TestPoint(Vector3 point) { - return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); + return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); } bool SphereCollider::Raycast(Ray ray, float maxDistance) { - return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); + return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Physics/Physics.cxx b/SHADE_Managed/src/Physics/Physics.cxx index bfb79b75..60aba58d 100644 --- a/SHADE_Managed/src/Physics/Physics.cxx +++ b/SHADE_Managed/src/Physics/Physics.cxx @@ -179,20 +179,7 @@ namespace SHADE throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); - switch (NATIVE_SHAPE.GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); - break; - } - case SHCollisionShape::Type::BOX: - { - shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); - break; - } - default: break; - } + shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); ray.Position += shapePos; @@ -226,20 +213,7 @@ namespace SHADE throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); - switch (NATIVE_SHAPE.GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); - break; - } - case SHCollisionShape::Type::BOX: - { - shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); - break; - } - default: break; - } + shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); ray.Position += shapePos; @@ -306,20 +280,7 @@ namespace SHADE throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape(); - switch (NATIVE_SHAPE.GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); - break; - } - case SHCollisionShape::Type::BOX: - { - shapePos = Convert::ToCLI(dynamic_cast(NATIVE_SHAPE).GetCenter()); - break; - } - default: break; - } + shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); start += shapePos; -- 2.40.1 From dffdec9d9c428573ecb3c6dfe2cae0ad4cd68055 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 4 Jan 2023 19:45:41 +0800 Subject: [PATCH 67/84] Cleaned up colliders --- .../Inspector/SHEditorComponentView.hpp | 8 +- SHADE_Engine/src/Math/Geometry/SHAABB.h | 11 +- SHADE_Engine/src/Math/Geometry/SHPlane.h | 10 +- SHADE_Engine/src/Math/Geometry/SHShape.h | 42 -- .../Collision/Broadphase/SHDynamicAABBTree.h | 2 +- .../Collision/Contacts/SHCollisionKey.cpp | 2 +- .../Physics/Collision/Contacts/SHContact.h | 2 +- .../Physics/Collision/Contacts/SHManifold.h | 2 +- .../Narrowphase/SHCapsuleVsConvex.cpp | 2 +- .../Collision/Narrowphase/SHCollision.h | 1 - .../Narrowphase/SHConvexVsConvex.cpp | 2 + .../Narrowphase/SHSphereVsCapsule.cpp | 2 +- .../Narrowphase/SHSphereVsConvex.cpp | 4 +- .../Narrowphase/SHSphereVsSphere.cpp | 2 +- .../src/Physics/Collision/SHCollider.cpp | 393 ++++++++++++++++++ .../src/Physics/Collision/SHCollider.h | 178 ++++++++ .../Physics/Collision/SHCollisionSpace.cpp | 14 +- .../src/Physics/Collision/SHCollisionSpace.h | 10 +- .../Physics/Collision/SHCompositeCollider.cpp | 339 +-------------- .../Physics/Collision/SHCompositeCollider.h | 141 +------ .../{CollisionShapes => Shapes}/SHBox.cpp | 2 +- .../{CollisionShapes => Shapes}/SHBox.h | 1 + .../SHCollisionShape.cpp | 2 +- .../SHCollisionShape.h | 3 +- .../SHCollisionShapeID.h | 0 .../SHCollisionShapeID.hpp | 0 .../SHCollisionShapeLibrary.cpp | 0 .../SHCollisionShapeLibrary.h | 0 .../SHConvexPolyhedron.cpp | 44 +- .../SHConvexPolyhedron.h | 2 +- .../SHHalfEdgeStructure.cpp | 0 .../SHHalfEdgeStructure.h | 0 .../{CollisionShapes => Shapes}/SHSphere.cpp | 2 +- .../{CollisionShapes => Shapes}/SHSphere.h | 1 + .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 2 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 4 +- .../src/Physics/Dynamics/SHRigidBody.h | 6 +- .../PhysicsObject/SHPhysicsObject.cpp | 9 +- .../Interface/PhysicsObject/SHPhysicsObject.h | 16 +- .../PhysicsObject/SHPhysicsObjectManager.cpp | 12 +- .../PhysicsObject/SHPhysicsObjectManager.h | 4 +- .../Physics/Interface/SHColliderComponent.cpp | 7 +- .../Physics/Interface/SHColliderComponent.h | 4 +- SHADE_Engine/src/Physics/SHPhysicsEvents.h | 2 +- .../Routines/SHPhysicsPreUpdateRoutine.cpp | 2 +- .../System/SHPhysicsDebugDrawSystem.cpp | 2 +- .../Physics/System/SHPhysicsDebugDrawSystem.h | 6 +- .../src/Physics/System/SHPhysicsSystem.cpp | 4 +- .../src/Serialization/SHYAMLConverters.h | 12 +- 49 files changed, 697 insertions(+), 619 deletions(-) delete mode 100644 SHADE_Engine/src/Math/Geometry/SHShape.h create mode 100644 SHADE_Engine/src/Physics/Collision/SHCollider.cpp create mode 100644 SHADE_Engine/src/Physics/Collision/SHCollider.h rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHBox.cpp (99%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHBox.h (99%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHCollisionShape.cpp (99%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHCollisionShape.h (98%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHCollisionShapeID.h (100%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHCollisionShapeID.hpp (100%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHCollisionShapeLibrary.cpp (100%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHCollisionShapeLibrary.h (100%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHConvexPolyhedron.cpp (66%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHConvexPolyhedron.h (99%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHHalfEdgeStructure.cpp (100%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHHalfEdgeStructure.h (100%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHSphere.cpp (98%) rename SHADE_Engine/src/Physics/Collision/{CollisionShapes => Shapes}/SHSphere.h (99%) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 765dbc9b..db9c161f 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -21,6 +21,7 @@ #include "Serialization/SHSerializationHelper.hpp" #include "Tools/Utilities/SHClipboardUtilities.h" #include "SHInspectorCommands.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" namespace SHADE { @@ -420,17 +421,20 @@ namespace SHADE } ImGui::EndChild(); + // TODO: Handle differences between composite & hull collider if (ImGui::BeginMenu("Add Collider")) { int newColl = -1; if (ImGui::Selectable("Box Collider")) { - component->GetCollider()->AddBoxCollisionShape(SHVec3::One); + auto* compositeCollider = dynamic_cast(component->GetCollider()); + compositeCollider->AddBoxCollisionShape(SHVec3::One); } if (ImGui::Selectable("Sphere Collider")) { - component->GetCollider()->AddSphereCollisionShape(1.0f); + auto* compositeCollider = dynamic_cast(component->GetCollider()); + compositeCollider->AddSphereCollisionShape(1.0f); } //No idea why this doesn't work diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.h b/SHADE_Engine/src/Math/Geometry/SHAABB.h index e6536fa5..9b62c85b 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.h +++ b/SHADE_Engine/src/Math/Geometry/SHAABB.h @@ -13,7 +13,7 @@ #include // Project Headers -#include "SHShape.h" +#include "Math/SHRay.h" namespace SHADE { @@ -25,8 +25,7 @@ namespace SHADE * @brief * Encapsulates a 3D Axis-Aligned Bounding Box. */ - class SH_API SHAABB : public SHShape, - private DirectX::BoundingBox + class SH_API SHAABB : private DirectX::BoundingBox { public: /*---------------------------------------------------------------------------------*/ @@ -39,7 +38,7 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - ~SHAABB () override = default; + ~SHAABB () noexcept = default; SHAABB () noexcept; SHAABB (const SHVec3& center, const SHVec3& halfExtents) noexcept; @@ -85,7 +84,7 @@ namespace SHADE * @return * True if the point is inside the aabb. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept; /** * @brief @@ -96,7 +95,7 @@ namespace SHADE * The result of the raycast.
* See the corresponding header for the contents of the raycast result object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept; /** * @brief diff --git a/SHADE_Engine/src/Math/Geometry/SHPlane.h b/SHADE_Engine/src/Math/Geometry/SHPlane.h index 581b1c03..6593c627 100644 --- a/SHADE_Engine/src/Math/Geometry/SHPlane.h +++ b/SHADE_Engine/src/Math/Geometry/SHPlane.h @@ -11,7 +11,7 @@ #pragma once // Project Headers -#include "SHShape.h" +#include "Math/SHRay.h" #include "Math/Vector/SHVec4.h" namespace SHADE @@ -24,14 +24,14 @@ namespace SHADE * @brief * Encapsulates a 3D plane in point-normal form. */ - class SH_API SHPlane : public SHShape + class SH_API SHPlane { public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - ~SHPlane () override = default; + ~SHPlane () noexcept = default; SHPlane (const SHPlane& rhs) noexcept = default; SHPlane (SHPlane&& rhs) noexcept = default; @@ -77,7 +77,7 @@ namespace SHADE * @return * True if the point is on the plane. */ - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept; /** * @brief @@ -88,7 +88,7 @@ namespace SHADE * The result of the raycast.
* See the corresponding header for the contents of the raycast result object. */ - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept; /** * @brief diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h deleted file mode 100644 index 7781a5a4..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************************** - * \file SHShape.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a 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/SHRay.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a base class for any shape. - */ - class SH_API SHShape - { - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - virtual ~SHShape () = default; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0; - [[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0; - }; -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h index 32b5095a..292c3528 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h @@ -13,7 +13,7 @@ #include // Project Headers -#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" +#include "Physics/Collision/Shapes/SHCollisionShape.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp index 8bd26e91..4bb22697 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp @@ -14,7 +14,7 @@ #include "SHCollisionKey.h" // Project Headers -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" #include "Physics/Interface/SHColliderComponent.h" diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h index 0c137f2f..70e53794 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -12,7 +12,7 @@ // Primary Header #include "Physics/Dynamics/SHRigidBody.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" +#include "Physics/Collision/Shapes/SHCollisionShape.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h index 15741276..3b591875 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h @@ -12,7 +12,7 @@ // Primary Header #include "Physics/Dynamics/SHRigidBody.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" +#include "Physics/Collision/Shapes/SHCollisionShape.h" #include "SHContact.h" #include "SHCollisionEvents.h" diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp index e7da5f8b..6c82c3a5 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp @@ -16,7 +16,7 @@ // Project Headers #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHBox.h" +#include "Physics/Collision/Shapes/SHConvexPolyhedron.h" // TODO diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index e98983b4..0ce1f688 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -11,7 +11,6 @@ #pragma once // Project Headers -#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" #include "Physics/Collision/Contacts/SHManifold.h" #include "Physics/Collision/Contacts/SHCollisionKey.h" diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index d73097bb..6753c453 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -15,6 +15,8 @@ // Project Headers #include "Math/SHMathHelpers.h" +#include "Physics/Collision/Shapes/SHConvexPolyhedron.h" + namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp index d7eb02fc..25515fd7 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp @@ -15,7 +15,7 @@ // Project Headers #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHSphere.h" // TODO diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 1b97a7c6..2b08313b 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -17,8 +17,8 @@ // Project Headers #include "Math/Geometry/SHPlane.h" #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShape.h" -#include "Physics/Collision/CollisionShapes/SHBox.h" +#include "Physics/Collision/Shapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHConvexPolyhedron.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp index aa270b16..1a76924e 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp @@ -15,7 +15,7 @@ // Project Headers #include "Math/SHMathHelpers.h" -#include "Physics/Collision/CollisionShapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHSphere.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp new file mode 100644 index 00000000..2e7cc3c6 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -0,0 +1,393 @@ +/**************************************************************************************** + * \file SHCollider.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Base Collider Class. + * + * \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 + +// Primary Header +#include "SHCollider.h" + +// Project Headers +#include "Broadphase/SHDynamicAABBTree.h" +#include "Events/SHEvent.h" +#include "Math/SHMathHelpers.h" +#include "Physics/SHPhysicsEvents.h" +#include "Physics/Dynamics/SHRigidBody.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept + : entityID { eid } + , flags { 0 } + , rigidBody { nullptr } + , shapeLibrary { nullptr } + , broadphase { nullptr } + , transform { worldTransform } + { + flags |= ACTIVE_FLAG; + flags |= MOVED_FLAG; + } + + SHCollider::SHCollider(const SHCollider& rhs) noexcept + : entityID { rhs.entityID } + , flags { rhs.flags } + , rigidBody { rhs.rigidBody } + , shapeLibrary { rhs.shapeLibrary } + , broadphase { rhs.broadphase } + , transform { rhs.transform } + {} + + SHCollider::SHCollider(SHCollider&& rhs) noexcept + : entityID { rhs.entityID } + , flags { rhs.flags } + , rigidBody { rhs.rigidBody } + , shapeLibrary { rhs.shapeLibrary } + , broadphase { rhs.broadphase } + , transform { rhs.transform } + {} + + SHCollider::~SHCollider() noexcept + { + if (!shapeLibrary) + { + SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add destroy collider!", entityID) + return; + } + + for (auto* shape : shapes) + shapeLibrary->DestroyShape(shape); + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollider& SHCollider::operator=(const SHCollider& rhs) noexcept + { + if (this == &rhs) + return *this; + + if (!shapeLibrary) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) + return *this; + } + + entityID = rhs.entityID; + flags = rhs.flags; + rigidBody = rhs.rigidBody; + shapeLibrary = rhs.shapeLibrary; + broadphase = rhs.broadphase; + transform = rhs.transform; + + copyShapes(rhs); + + return *this; + } + + SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept + { + if (!shapeLibrary) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) + return *this; + } + + entityID = rhs.entityID; + flags = rhs.flags; + rigidBody = rhs.rigidBody; + shapeLibrary = rhs.shapeLibrary; + broadphase = rhs.broadphase; + transform = rhs.transform; + + copyShapes(rhs); + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + EntityID SHCollider::GetEntityID() const noexcept + { + return entityID; + } + + SHCollider::Type SHCollider::GetType() const noexcept + { + if (flags & COMPOSITE_FLAG) + return Type::COMPOSITE; + + if (flags & HULL_FLAG) + return Type::HULL; + + return Type::INVALID; + } + + bool SHCollider::IsActive() const noexcept + { + return flags & ACTIVE_FLAG; + } + + bool SHCollider::GetDebugDrawState() const noexcept + { + return flags & DRAW_FLAG; + } + + const SHTransform& SHCollider::GetTransform() const noexcept + { + return transform; + } + + const SHVec3& SHCollider::GetPosition() const noexcept + { + return transform.position; + } + + const SHQuaternion& SHCollider::GetOrientation() const noexcept + { + return transform.orientation; + } + + const SHVec3& SHCollider::GetScale() const noexcept + { + return transform.scale; + } + + const SHCollider::CollisionShapes& SHCollider::GetCollisionShapes() const noexcept + { + return shapes; + } + + SHCollisionShape* SHCollider::GetCollisionShape(int index) const + { + const int NUM_SHAPES = static_cast(shapes.size()); + + if (index < 0 || index >= NUM_SHAPES) + throw std::invalid_argument("Out-of-range index!"); + + return shapes[index]; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::SetType(Type type) noexcept + { + if (type == Type::COMPOSITE) + flags |= COMPOSITE_FLAG; + + if (type == Type::HULL) + flags |= HULL_FLAG; + } + + void SHCollider::SetIsActive(bool state) noexcept + { + const bool PREV_STATE = flags & ACTIVE_FLAG; + state ? flags |= ACTIVE_FLAG : flags &= ~(ACTIVE_FLAG); + + if (!broadphase) + return; + + for (auto* shape : shapes) + { + if (PREV_STATE) // Previously inactive + broadphase->Insert(shape->id, shape->ComputeAABB()); + else // Previously active + broadphase->Remove(shape->id); + } + } + + void SHCollider::SetDebugDrawState(bool state) noexcept + { + state ? flags |= DRAW_FLAG : flags &= ~(DRAW_FLAG); + + #ifdef SHEDITOR + + // Broadcast event for the Debug Draw system to catch + const SHColliderOnDebugDrawEvent EVENT_DATA + { + .entityID = entityID + , .debugDrawState = state + }; + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_DRAW_EVENT); + + #endif + } + + void SHCollider::SetRigidBody(SHRigidBody* rb) noexcept + { + rigidBody = rb; + } + + void SHCollider::SetTransform(const SHTransform& newTransform) noexcept + { + flags |= MOVED_FLAG; + transform = newTransform; + } + + void SHCollider::SetPosition(const SHVec3& newPosition) noexcept + { + flags |= MOVED_FLAG; + transform.position = newPosition; + } + + void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept + { + flags |= MOVED_FLAG; + transform.orientation = newOrientation; + } + + void SHCollider::SetScale(const SHVec3& newScale) noexcept + { + flags |= MOVED_FLAG; + transform.scale = newScale; + } + + void SHCollider::SetLibrary(SHCollisionShapeLibrary* factory) noexcept + { + shapeLibrary = factory; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHMatrix& SHCollider::ComputeTRS() noexcept + { + return transform.ComputeTRS(); + } + + void SHCollider::RemoveCollisionShape(int index) + { + if (!shapeLibrary) + { + SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add remove shape!", entityID) + return; + } + + const int NUM_SHAPES = static_cast(shapes.size()); + + if (index < 0 || index >= NUM_SHAPES) + throw std::invalid_argument("Out-of-range index!"); + + auto shape = shapes.begin(); + for (int i = 0; i < NUM_SHAPES; ++i, ++shape) + { + if (i == index) + break; + } + + const SHPhysicsColliderRemovedEvent EVENT_DATA + { + .entityID = entityID + , .colliderType = (*shape)->GetType() + , .colliderIndex = index + }; + + // Remove from broadphase + if (broadphase) + broadphase->Remove((*shape)->id); + + shapeLibrary->DestroyShape(*shape); + *shape = nullptr; + + // Remove the shape from the container to prevent accessing a nullptr + shape = shapes.erase(shape); + + + + // Broadcast Event for removing a shape + SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); + + if (rigidBody) + rigidBody->ComputeMassData(); + + SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) + } + + void SHCollider::Update() noexcept + { + for (auto* shape : shapes) + shape->Update(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::copyShapes(const SHCollider& rhsCollider) + { + for (const auto* shape : rhsCollider.shapes) + { + switch (shape->GetType()) + { + case SHCollisionShape::Type::BOX: + { + const SHBox* RHS_BOX = dynamic_cast(shape); + + const SHBoxCreateInfo BOX_CREATE_INFO + { + .Center = RHS_BOX->Center + , .Extents = RHS_BOX->Extents + , .RelativeExtents = RHS_BOX->relativeExtents + , .Orientation = RHS_BOX->Orientation + , .Scale = RHS_BOX->scale + }; + + const uint32_t NEW_INDEX = static_cast(shapes.size()); + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; + + SHBox* box = shapeLibrary->CreateBox(NEW_SHAPE_ID, BOX_CREATE_INFO); + *box = *RHS_BOX; + + shapes.emplace_back(box); + + break; + } + case SHCollisionShape::Type::SPHERE: + { + const SHSphere* RHS_SPHERE = dynamic_cast(shape); + + const SHSphereCreateInfo SPHERE_CREATE_INFO + { + .Center = RHS_SPHERE->Center + , .Radius = RHS_SPHERE->Radius + , .RelativeRadius = RHS_SPHERE->relativeRadius + , .Scale = RHS_SPHERE->scale + }; + + const uint32_t NEW_INDEX = static_cast(shapes.size()); + const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; + + SHSphere* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); + *sphere = *RHS_SPHERE; + + shapes.emplace_back(sphere); + + break; + } + case SHCollisionShape::Type::CAPSULE: + { + break; + } + default: break; + } + } + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h new file mode 100644 index 00000000..a326215f --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -0,0 +1,178 @@ +/**************************************************************************************** + * \file SHCollider.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Base Collider Class. + * + * \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/Entity/SHEntity.h" +#include "Math/Transform/SHTransform.h" +#include "Physics/Collision/Shapes/SHCollisionShapeLibrary.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHRigidBody; + class SHAABBTree; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief + * Base class for a collider. + * There are only two collider types supported by SHADE Engine: Composite & Hull + */ + class SH_API SHCollider + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHCollisionSpace; + friend struct SHManifold; + + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Type + { + COMPOSITE + , HULL + + , TOTAL + , INVALID = -1 + }; + + using CollisionShapes = std::vector; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Constructor for a collider. + * @param eid + * The entity this collider belongs to. + * @param worldTransform + * The world transform for the collider. Defaults to the identity transform. + * This is particularly important for composite colliders for offsets & relative sizes. + * @return + */ + SHCollider (EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; + SHCollider (const SHCollider& rhs) noexcept; + SHCollider (SHCollider&& rhs) noexcept; + virtual ~SHCollider () noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollider& operator=(const SHCollider& rhs) noexcept; + SHCollider& operator=(SHCollider&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] EntityID GetEntityID () const noexcept; + + [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] bool IsActive () const noexcept; + [[nodiscard]] bool GetDebugDrawState () const noexcept; + + [[nodiscard]] const SHTransform& GetTransform () const noexcept; + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + [[nodiscard]] const SHVec3& GetScale () const noexcept; + + [[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept; + [[nodiscard]] SHCollisionShape* GetCollisionShape (int index) const; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetType (Type type) noexcept; + void SetIsActive (bool state) noexcept; + void SetDebugDrawState (bool state) noexcept; + + void SetRigidBody (SHRigidBody* rb) noexcept; + + void SetTransform (const SHTransform& newTransform) noexcept; + void SetPosition (const SHVec3& newPosition) noexcept; + void SetOrientation (const SHQuaternion& newOrientation) noexcept; + void SetScale (const SHVec3& newScale) noexcept; + + void SetLibrary (SHCollisionShapeLibrary* factory) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Computes the TRS for the collider's transform + * @return + * The computed TRS. + */ + const SHMatrix& ComputeTRS() noexcept; + + /** + * @brief + * Removes a shape from the container. Removal reduces the size of the container. + * If removing all, perform removal from back to front. + * @param index + * The index of the shape to remove. + * @throws + * Invalid argument for out-of-range indices. + */ + void RemoveCollisionShape (int index); + + /** + * @brief + * Recomputes the transforms for all shapes in this composite collider. + */ + void Update () noexcept; + + protected: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr uint8_t COMPOSITE_FLAG = 1U << static_cast(Type::COMPOSITE); + static constexpr uint8_t HULL_FLAG = 1U << static_cast(Type::HULL); + static constexpr uint8_t ACTIVE_FLAG = 1U << 2; + static constexpr uint8_t DRAW_FLAG = 1U << 3; + static constexpr uint8_t MOVED_FLAG = 1U << 4; + + EntityID entityID; + uint8_t flags; // 0 0 0 hasMoved debugDraw active hull composite + SHRigidBody* rigidBody; + SHCollisionShapeLibrary* shapeLibrary; + SHAABBTree* broadphase; + SHTransform transform; + CollisionShapes shapes; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void copyShapes (const SHCollider& rhsCollider); + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp index e410ac36..c643e05e 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -40,7 +40,7 @@ namespace SHADE /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollisionSpace::AddCollider(SHCompositeCollider* collider) noexcept + void SHCollisionSpace::AddCollider(SHCollider* collider) noexcept { const bool INSERTED = colliders.emplace(collider->entityID, collider).second; if (!INSERTED) @@ -56,7 +56,7 @@ namespace SHADE broadphase.Insert(shape->id, shape->ComputeAABB()); } - void SHCollisionSpace::RemoveCollider(SHCompositeCollider* collider) noexcept + void SHCollisionSpace::RemoveCollider(SHCollider* collider) noexcept { colliders.erase(collider->entityID); @@ -85,14 +85,14 @@ namespace SHADE // Update any colliders that have moved for (auto& collider : colliders | std::views::values) { - const bool IS_ACTIVE = collider->active; - const bool HAS_MOVED = collider->hasMoved; + const bool IS_ACTIVE = collider->IsActive(); + const bool HAS_MOVED = collider->flags & SHCollider::MOVED_FLAG; if (!IS_ACTIVE || !HAS_MOVED) continue; // Clear hasMoved flag here - collider->hasMoved = false; + collider->flags &= ~SHCollider::MOVED_FLAG; // Update moved shapes in broadphase for (auto* shape : collider->shapes) @@ -114,7 +114,7 @@ namespace SHADE // Colliders without bodies are considered to be static bodies // This is specific to this engine because of Unity's stupid convention. const bool IS_IMPLICIT_STATIC = !collider->rigidBody; - const bool IS_ACTIVE = collider->active; + const bool IS_ACTIVE = collider->IsActive(); // Skip inactive colliders if (!IS_ACTIVE || IS_IMPLICIT_STATIC) @@ -246,7 +246,7 @@ namespace SHADE /* Private Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollisionSpace::broadphaseQuery(SHRigidBody::Type rigidBodyType, SHCompositeCollider* collider) noexcept + void SHCollisionSpace::broadphaseQuery(SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept { for (auto* shape : collider->shapes) { diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h index fa1f0d16..8607cf45 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h @@ -18,7 +18,7 @@ // Project Headers #include "Broadphase/SHDynamicAABBTree.h" #include "Physics/Dynamics/SHContactManager.h" -#include "SHCompositeCollider.h" +#include "SHCollider.h" #include "SHPhysicsRaycastResult.h" #include "CollisionTags/SHCollisionTags.h" #include "CollisionTags/SHCollisionTags.h" @@ -118,7 +118,7 @@ namespace SHADE * @param collider * A collider to add. Duplicates will be ignored. */ - void AddCollider (SHCompositeCollider* collider) noexcept; + void AddCollider (SHCollider* collider) noexcept; /** * @brief @@ -127,7 +127,7 @@ namespace SHADE * @param collider * A collider to remove. If a reference to it doesn't exist, it will be ignored. */ - void RemoveCollider (SHCompositeCollider* collider) noexcept; + void RemoveCollider (SHCollider* collider) noexcept; /** * @brief @@ -165,7 +165,7 @@ namespace SHADE SHCollisionShape* B = nullptr; }; - using Colliders = std::unordered_map; + using Colliders = std::unordered_map; using NarrowphaseBatch = std::unordered_map; /*---------------------------------------------------------------------------------*/ @@ -185,7 +185,7 @@ namespace SHADE // Broadphase helpers - void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCompositeCollider* collider) noexcept; + void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept; // Narrowphase helpers diff --git a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp index 97fef331..28b6aafe 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollider.cpp + * \file SHCompositeCollider.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for a Base Collider Class. + * \brief Implementation for a Composite Collider Class. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -15,12 +15,10 @@ // Project Headers #include "Broadphase/SHDynamicAABBTree.h" -#include "Events/SHEvent.h" #include "Math/SHMathHelpers.h" #include "Physics/SHPhysicsEvents.h" #include "Physics/Dynamics/SHRigidBody.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -28,65 +26,18 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHCompositeCollider::SHCompositeCollider(EntityID eid, const SHTransform& worldTransform) noexcept - : entityID { eid } - , active { true } - , debugDraw { false } - , hasMoved { true } - , rigidBody { nullptr } - , shapeLibrary { nullptr } - , broadphase { nullptr } - , transform { worldTransform } - {} + : SHCollider( eid, worldTransform ) + { + flags |= COMPOSITE_FLAG; + } SHCompositeCollider::SHCompositeCollider(const SHCompositeCollider& rhs) noexcept - : entityID { rhs.entityID } - , active { rhs.active } - , debugDraw { rhs.debugDraw } - , hasMoved { rhs.hasMoved } - , rigidBody { rhs.rigidBody } - , shapeLibrary { rhs.shapeLibrary } - , broadphase { rhs.broadphase } - , transform { rhs.transform } - { - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) - return; - } - - copyShapes(rhs); - } + : SHCollider( rhs ) + {} SHCompositeCollider::SHCompositeCollider(SHCompositeCollider&& rhs) noexcept - : entityID { rhs.entityID } - , active { rhs.active } - , debugDraw { rhs.debugDraw } - , hasMoved { rhs.hasMoved } - , rigidBody { rhs.rigidBody } - , shapeLibrary { rhs.shapeLibrary } - , broadphase { rhs.broadphase } - , transform { rhs.transform } - { - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) - return; - } - - copyShapes(rhs); - } - - SHCompositeCollider::~SHCompositeCollider() noexcept - { - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with Composite Collider {}. Unable to add destroy collider!", entityID) - return; - } - - for (auto* shape : shapes) - shapeLibrary->DestroyShape(shape); - } + : SHCollider( rhs ) + {} /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ @@ -97,186 +48,22 @@ namespace SHADE if (this == &rhs) return *this; - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) - return *this; - } - - entityID = rhs.entityID; - active = rhs.active; - debugDraw = rhs.debugDraw; - hasMoved = rhs.hasMoved; - rigidBody = rhs.rigidBody; - shapeLibrary = rhs.shapeLibrary; - broadphase = rhs.broadphase; - transform = rhs.transform; - - copyShapes(rhs); + SHCollider::operator=(rhs); return *this; } SHCompositeCollider& SHCompositeCollider::operator=(SHCompositeCollider&& rhs) noexcept { - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add copy shapes!", entityID) - return *this; - } - - entityID = rhs.entityID; - active = rhs.active; - debugDraw = rhs.debugDraw; - hasMoved = rhs.hasMoved; - rigidBody = rhs.rigidBody; - shapeLibrary = rhs.shapeLibrary; - broadphase = rhs.broadphase; - transform = rhs.transform; - - copyShapes(rhs); + SHCollider::operator=(rhs); return *this; } - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - EntityID SHCompositeCollider::GetEntityID() const noexcept - { - return entityID; - } - - bool SHCompositeCollider::IsActive() const noexcept - { - return active; - } - - bool SHCompositeCollider::GetDebugDrawState() const noexcept - { - return debugDraw; - } - - const SHTransform& SHCompositeCollider::GetTransform() const noexcept - { - return transform; - } - - const SHVec3& SHCompositeCollider::GetPosition() const noexcept - { - return transform.position; - } - - const SHQuaternion& SHCompositeCollider::GetOrientation() const noexcept - { - return transform.orientation; - } - - const SHVec3& SHCompositeCollider::GetScale() const noexcept - { - return transform.scale; - } - - const SHCompositeCollider::CollisionShapes& SHCompositeCollider::GetCollisionShapes() const noexcept - { - return shapes; - } - - SHCollisionShape* SHCompositeCollider::GetCollisionShape(int index) const - { - const int NUM_SHAPES = static_cast(shapes.size()); - - if (index < 0 || index >= NUM_SHAPES) - throw std::invalid_argument("Out-of-range index!"); - - return shapes[index]; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCompositeCollider::SetIsActive(bool state) noexcept - { - if (active == state) - return; - - active = state; - - if (!broadphase) - return; - - for (auto* shape : shapes) - { - if (active) // Previously inactive - broadphase->Insert(shape->id, shape->ComputeAABB()); - else // Previously active - broadphase->Remove(shape->id); - } - } - - void SHCompositeCollider::SetDebugDrawState(bool state) noexcept - { - debugDraw = state; - - #ifdef SHEDITOR - - // Broadcast event for the Debug Draw system to catch - const SHColliderOnDebugDrawEvent EVENT_DATA - { - .entityID = entityID - , .debugDrawState = debugDraw - }; - - SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_DRAW_EVENT); - - #endif - } - - void SHCompositeCollider::SetRigidBody(SHRigidBody* rb) noexcept - { - rigidBody = rb; - } - - void SHCompositeCollider::SetTransform(const SHTransform& newTransform) noexcept - { - hasMoved = true; - transform = newTransform; - } - - void SHCompositeCollider::SetPosition(const SHVec3& newPosition) noexcept - { - hasMoved = true; - transform.position = newPosition; - } - - void SHCompositeCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept - { - hasMoved = true; - transform.orientation = newOrientation; - } - - void SHCompositeCollider::SetScale(const SHVec3& newScale) noexcept - { - hasMoved = true; - transform.scale = newScale; - } - - void SHCompositeCollider::SetFactory(SHCollisionShapeLibrary* factory) noexcept - { - shapeLibrary = factory; - } - /*-----------------------------------------------------------------------------------*/ /* Public Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHMatrix& SHCompositeCollider::ComputeTransformTRS() noexcept - { - return transform.ComputeTRS(); - } - int SHCompositeCollider::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) { if (!shapeLibrary) @@ -386,106 +173,4 @@ namespace SHADE } - void SHCompositeCollider::RemoveCollisionShape(int index) - { - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with Collider {}. Unable to add remove shape!", entityID) - return; - } - - const int NUM_SHAPES = static_cast(shapes.size()); - - if (index < 0 || index >= NUM_SHAPES) - throw std::invalid_argument("Out-of-range index!"); - - auto shape = shapes.begin(); - for (int i = 0; i < NUM_SHAPES; ++i, ++shape) - { - if (i == index) - break; - } - - const SHPhysicsColliderRemovedEvent EVENT_DATA - { - .entityID = entityID - , .colliderType = (*shape)->GetType() - , .colliderIndex = index - }; - - // Remove from broadphase - if (broadphase) - broadphase->Remove((*shape)->id); - - shapeLibrary->DestroyShape(*shape); - *shape = nullptr; - - // Remove the shape from the container to prevent accessing a nullptr - shape = shapes.erase(shape); - - - - // Broadcast Event for removing a shape - SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); - - if (rigidBody) - rigidBody->ComputeMassData(); - - SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, entityID) - } - - void SHCompositeCollider::RecomputeShapes() noexcept - { - for (auto* shape : shapes) - shape->Update(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCompositeCollider::copyShapes(const SHCompositeCollider& rhsCollider) - { - for (const auto* shape : rhsCollider.shapes) - copyShape(shape); - } - - void SHCompositeCollider::copyShape(const SHCollisionShape* rhsShape) - { - switch (rhsShape->GetType()) - { - case SHCollisionShape::Type::BOX: - { - break; - } - case SHCollisionShape::Type::SPHERE: - { - const SHSphere* RHS_SPHERE = dynamic_cast(rhsShape); - - const SHSphereCreateInfo SPHERE_CREATE_INFO - { - .Center = RHS_SPHERE->Center - , .Radius = RHS_SPHERE->Radius - , .RelativeRadius = RHS_SPHERE->relativeRadius - , .Scale = RHS_SPHERE->scale - }; - - const uint32_t NEW_INDEX = static_cast(shapes.size()); - const SHCollisionShapeID NEW_SHAPE_ID{ entityID, NEW_INDEX }; - - SHSphere* sphere = shapeLibrary->CreateSphere(NEW_SHAPE_ID, SPHERE_CREATE_INFO); - *sphere = *RHS_SPHERE; - - shapes.emplace_back(sphere); - - break; - } - case SHCollisionShape::Type::CAPSULE: - { - break; - } - default: break; - } - } - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h index e5ce8609..8ab71186 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollider.h + * \file SHCompositeCollider.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Base Collider Class. + * \brief Interface for a Composite Collider Class. * * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent @@ -11,63 +11,26 @@ #pragma once // Project Headers -#include "ECS_Base/Entity/SHEntity.h" -#include "Math/Transform/SHTransform.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h" +#include "SHCollider.h" namespace SHADE { - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - class SHRigidBody; - class SHAABBTree; - - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - /** * @brief - * Base class for a collider. - * There are only two collider types supported by SHADE Engine: Composite & Hull + * Encapsulates the behaviour of a collider with composited shapes.
+ * Contains no data members but methods to add multiple shapes. */ - class SH_API SHCompositeCollider + class SH_API SHCompositeCollider : public SHCollider { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHCollisionSpace; - friend struct SHManifold; - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using CollisionShapes = std::vector; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Constructor for a collider. - * @param eid - * The entity this collider belongs to. - * @param worldTransform - * The world transform for the collider. Defaults to the identity transform. - * This is particularly important for composite colliders for offsets & relative sizes. - * @return - */ - SHCompositeCollider (EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; - SHCompositeCollider (const SHCompositeCollider& rhs) noexcept; - SHCompositeCollider (SHCompositeCollider&& rhs) noexcept; - ~SHCompositeCollider () noexcept; + SHCompositeCollider(EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; + SHCompositeCollider(const SHCompositeCollider& rhs) noexcept; + SHCompositeCollider(SHCompositeCollider&& rhs) noexcept; + ~SHCompositeCollider () noexcept override = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ @@ -76,50 +39,10 @@ namespace SHADE SHCompositeCollider& operator=(const SHCompositeCollider& rhs) noexcept; SHCompositeCollider& operator=(SHCompositeCollider&& rhs) noexcept; - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] EntityID GetEntityID () const noexcept; - [[nodiscard]] bool IsActive () const noexcept; - [[nodiscard]] bool GetDebugDrawState () const noexcept; - - [[nodiscard]] const SHTransform& GetTransform () const noexcept; - [[nodiscard]] const SHVec3& GetPosition () const noexcept; - [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; - [[nodiscard]] const SHVec3& GetScale () const noexcept; - - [[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept; - [[nodiscard]] SHCollisionShape* GetCollisionShape (int index) const; - - /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*---------------------------------------------------------------------------------*/ - - void SetIsActive (bool state) noexcept; - void SetDebugDrawState (bool state) noexcept; - - void SetRigidBody (SHRigidBody* rb) noexcept; - - void SetTransform (const SHTransform& newTransform) noexcept; - void SetPosition (const SHVec3& newPosition) noexcept; - void SetOrientation (const SHQuaternion& newOrientation) noexcept; - void SetScale (const SHVec3& newScale) noexcept; - - void SetFactory (SHCollisionShapeLibrary* factory) noexcept; - /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Computes the TRS for the collider's transform - * @return - * The computed TRS. - */ - const SHMatrix& ComputeTransformTRS() noexcept; - /** * @brief * Adds a sphere collision shape. @@ -151,49 +74,7 @@ namespace SHADE int AddBoxCollisionShape (const SHVec3& relativeExtents, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); // TODO: Add Capsule - - /** - * @brief - * Removes a shape from the container. Removal reduces the size of the container. - * If removing all, perform removal from back to front. - * @param index - * The index of the shape to remove. - * @throws - * Invalid argument for out-of-range indices. - */ - void RemoveCollisionShape (int index); - - /** - * @brief - * Recomputes the transforms for all shapes in this composite collider. - */ - void RecomputeShapes () noexcept; - - protected: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - EntityID entityID; - - bool active; - bool debugDraw; - bool hasMoved; - - SHRigidBody* rigidBody; - SHCollisionShapeLibrary* shapeLibrary; - SHAABBTree* broadphase; - - SHTransform transform; - - CollisionShapes shapes; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - void copyShapes (const SHCompositeCollider& rhsCollider); - void copyShape (const SHCollisionShape* rhsShape); }; + } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp similarity index 99% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.cpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp index b46c92da..efe40f7d 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.cpp +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp @@ -16,7 +16,7 @@ // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h similarity index 99% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h index bf250726..044af40f 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHBox.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h @@ -47,6 +47,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ + friend class SHCollider; friend class SHCompositeCollider; friend class SHCollision; friend class SHCollisionShapeLibrary; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp similarity index 99% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp index f089c02c..dfbed047 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.cpp +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp @@ -14,7 +14,7 @@ #include "SHCollisionShape.h" // Project Headers -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Reflection/SHReflectionMetadata.h" #include "Tools/Utilities/SHUtilities.h" diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h similarity index 98% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h index b4ce9529..3e57b74a 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h @@ -41,6 +41,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ + friend class SHCollider; friend class SHCompositeCollider; friend class SHColliderComponent; friend class SHCollisionShapeLibrary; @@ -191,7 +192,7 @@ namespace SHADE SHCollisionShapeID id; - SHCompositeCollider* collider; // The collider it belongs to. + SHCollider* collider; // The collider it belongs to. SHCollisionTag* collisionTag; SHPhysicsMaterial material; // TODO: Change to pointer once instancing is supported diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.h diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.hpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeID.hpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.hpp diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.cpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.h diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.cpp similarity index 66% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.cpp index a2aef745..8cccd837 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.cpp +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.cpp @@ -25,30 +25,14 @@ namespace SHADE {} SHConvexPolyhedron::SHConvexPolyhedron(const SHConvexPolyhedron& rhs) noexcept - : SHCollisionShape (rhs.id, rhs.GetType()) - , halfEdgeStructure { nullptr } - { - 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; - } + : SHCollisionShape ( rhs ) + , halfEdgeStructure { rhs.halfEdgeStructure } + {} SHConvexPolyhedron::SHConvexPolyhedron(SHConvexPolyhedron&& rhs) noexcept - : SHCollisionShape (rhs.id, rhs.GetType()) - , halfEdgeStructure { nullptr } - { - 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; - } + : SHCollisionShape ( rhs ) + , halfEdgeStructure { rhs.halfEdgeStructure } + {} /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ @@ -59,13 +43,7 @@ namespace SHADE if (this == &rhs) return *this; - 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; + SHCollisionShape::operator=(rhs); // Local Properties halfEdgeStructure = rhs.halfEdgeStructure; @@ -75,13 +53,7 @@ namespace SHADE SHConvexPolyhedron& SHConvexPolyhedron::operator=(SHConvexPolyhedron&& rhs) noexcept { - 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; + SHCollisionShape::operator=(rhs); // Local Properties halfEdgeStructure = rhs.halfEdgeStructure; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h similarity index 99% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h index cdc7f45f..dd4595d1 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHConvexPolyhedron.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h @@ -31,7 +31,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHCompositeCollider; + friend class SHCollider; friend class SHCollision; friend class SHCollisionShapeLibrary; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.cpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.cpp diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHHalfEdgeStructure.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.h diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp similarity index 98% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.cpp rename to SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp index 04f8718e..5708bf91 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.cpp +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp @@ -16,7 +16,7 @@ // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHMatrix.h" -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h similarity index 99% rename from SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.h rename to SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h index c4e97fe0..b874d2fe 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHSphere.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h @@ -46,6 +46,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ + friend class SHCollider; friend class SHCompositeCollider; friend class SHCollision; friend class SHCollisionShapeLibrary; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index d5c9b029..3595ec99 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -178,7 +178,7 @@ namespace SHADE rigidBody.collider->SetPosition(rigidBody.motionState.position); rigidBody.collider->SetOrientation(rigidBody.motionState.orientation); - rigidBody.collider->RecomputeShapes(); + rigidBody.collider->Update(); } } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 9688caa2..d76b79b8 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -17,7 +17,7 @@ #include #include -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" #include "Tools/Logger/SHLogger.h" namespace SHADE @@ -296,7 +296,7 @@ namespace SHADE /* Setter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBody::SetCollider(SHCompositeCollider* c) noexcept + void SHRigidBody::SetCollider(SHCollider* c) noexcept { collider = c; } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h index 44ae3f48..3c869ad2 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h @@ -22,7 +22,7 @@ namespace SHADE /* Forward Declarations */ /*-------------------------------------------------------------------------------------*/ - class SHCompositeCollider; + class SHCollider; /*-------------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -113,7 +113,7 @@ namespace SHADE /* Setter Functions */ /*-----------------------------------------------------------------------------------*/ - void SetCollider (SHCompositeCollider* c) noexcept; + void SetCollider (SHCollider* c) noexcept; /** * @brief @@ -229,7 +229,7 @@ namespace SHADE // The entityID here is only meant for linking with the actual component in the engine. EntityID entityID; - SHCompositeCollider* collider; + SHCollider* collider; Type bodyType; diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp index 07e08b78..2353e3f3 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp @@ -13,6 +13,9 @@ // Primary Header #include "SHPhysicsObject.h" +#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCompositeCollider.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -111,7 +114,7 @@ namespace SHADE collider->SetRigidBody(nullptr); } - SHCompositeCollider* SHPhysicsObject::CreateCollider(const SHTransform& transform) + SHCollider* SHPhysicsObject::CreateCompositeCollider(const SHTransform& transform) { if (collider) { @@ -148,13 +151,13 @@ namespace SHADE /* Private Member Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsObject::deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCompositeCollider* rhsCollider) + void SHPhysicsObject::deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCollider* rhsCollider) { if (rhsRigidBody) rigidBody = new SHRigidBody{ *rhsRigidBody }; if (rhsCollider) - collider = new SHCompositeCollider { *rhsCollider }; + collider = new SHCollider { *rhsCollider }; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h index f1ee042d..9736f8d0 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h @@ -11,7 +11,7 @@ #pragma once // Project Headers -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" #include "Physics/Dynamics/SHRigidBody.h" namespace SHADE @@ -33,7 +33,7 @@ namespace SHADE EntityID entityID = MAX_EID; SHRigidBody* rigidBody = nullptr; - SHCompositeCollider* collider = nullptr; + SHCollider* collider = nullptr; /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -61,7 +61,7 @@ namespace SHADE * @return * True if the physics object has neither a rigid body nor a collider. */ - [[nodiscard]] bool IsEmpty () const noexcept; + [[nodiscard]] bool IsEmpty () const noexcept; /** * @brief @@ -72,13 +72,13 @@ namespace SHADE * Pointer to the rigid body that was created. The memory of this rigid body is managed * by the physics object itself. */ - SHRigidBody* CreateRigidBody (SHRigidBody::Type bodyType); + SHRigidBody* CreateRigidBody (SHRigidBody::Type bodyType); /** * @brief * Destroys the rigid body of this physics object and frees the memory. */ - void DestroyRigidBody () noexcept; + void DestroyRigidBody () noexcept; /** * @brief @@ -91,19 +91,19 @@ namespace SHADE * Pointer to the collider that was created. The memory of this collider is managed * by the physics object itself. */ - SHCompositeCollider* CreateCollider (const SHTransform& transform = SHTransform::Identity); + SHCollider* CreateCompositeCollider (const SHTransform& transform = SHTransform::Identity); /** * @brief * Destroys the collider of this physics object and frees the memory. */ - void DestroyCollider () noexcept; + void DestroyCollider () noexcept; private: /*-----------------------------------------------------------------------------------*/ /* Member Functions */ /*-----------------------------------------------------------------------------------*/ - void deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCompositeCollider* rhsCollider); + void deepCopyComponents(const SHRigidBody* rhsRigidBody, const SHCollider* rhsCollider); }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp index 81fb25e1..956f8078 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp @@ -98,7 +98,7 @@ namespace SHADE destroyPhysicsObject(entityID); } - void SHPhysicsObjectManager::AddCollider(EntityID entityID) noexcept + void SHPhysicsObjectManager::AddCollider(EntityID entityID, SHCollider::Type type) noexcept { SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID); @@ -116,11 +116,15 @@ namespace SHADE } // Create a new composite collider in the physics object - physicsObject->CreateCollider(worldTransform); - physicsObject->collider->SetFactory(&shapeLibrary); + if (type == SHCollider::Type::COMPOSITE) + physicsObject->CreateCompositeCollider(worldTransform); + + // TODO: Hull collider + + physicsObject->collider->SetLibrary(&shapeLibrary); // Link with the component - colliderComponent->SetCollider(physicsObject->collider); + colliderComponent->SetCollider(dynamic_cast(physicsObject->collider)); } void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h index 11818316..8b4e79c1 100644 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h +++ b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h @@ -14,7 +14,7 @@ // Project Headers #include "SHPhysicsObject.h" -#include "Physics/Collision/CollisionShapes/SHCollisionShapeLibrary.h" +#include "Physics/Collision/Shapes/SHCollisionShapeLibrary.h" namespace SHADE { @@ -77,7 +77,7 @@ namespace SHADE * @param entityID * The entity to link the new collider to. */ - void AddCollider (EntityID entityID) noexcept; + void AddCollider (EntityID entityID, SHCollider::Type type) noexcept; /** * @brief diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp index 5569c713..a36fb730 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -13,11 +13,6 @@ // Primary Header #include "SHColliderComponent.h" -// Project Headers -#include "ECS_Base/Managers/SHSystemManager.h" -#include "Math/SHMathHelpers.h" -#include "Physics/System/SHPhysicsSystem.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -37,7 +32,7 @@ namespace SHADE return collider; } - const SHCompositeCollider::CollisionShapes* const SHColliderComponent::GetCollisionShapes() const noexcept + const SHCollider::CollisionShapes* const SHColliderComponent::GetCollisionShapes() const noexcept { if (!collider) return nullptr; diff --git a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h index 3c8e6342..39552949 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -54,8 +54,8 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHCompositeCollider* const GetCollider () const noexcept; - [[nodiscard]] const SHCompositeCollider::CollisionShapes* const GetCollisionShapes() const noexcept; + [[nodiscard]] SHCompositeCollider* const GetCollider () const noexcept; + [[nodiscard]] const SHCollider::CollisionShapes* const GetCollisionShapes() const noexcept; [[nodiscard]] SHCollisionShape* const GetCollisionShape (int index) const; // Required for serialisation diff --git a/SHADE_Engine/src/Physics/SHPhysicsEvents.h b/SHADE_Engine/src/Physics/SHPhysicsEvents.h index 2f78b6ee..a192ec3f 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsEvents.h +++ b/SHADE_Engine/src/Physics/SHPhysicsEvents.h @@ -11,7 +11,7 @@ #pragma once // Project Headers -#include "Collision/CollisionShapes/SHCollisionShape.h" +#include "Collision/Shapes/SHCollisionShape.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 17f3f83d..3f2de93f 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -83,7 +83,7 @@ namespace SHADE physicsObject.collider->SetOrientation(WORLD_ROT); physicsObject.collider->SetScale(WORLD_SCL); - physicsObject.collider->RecomputeShapes(); + physicsObject.collider->Update(); } } } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index 1b1055be..ae25216f 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -122,7 +122,7 @@ namespace SHADE return onColliderDrawEvent.get()->handle; } - void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHCompositeCollider& collider) noexcept + void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept { for (const auto* SHAPE : collider.GetCollisionShapes()) { diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h index c284792f..336dff0c 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -18,9 +18,9 @@ #include "ECS_Base/System/SHSystemRoutine.h" #include "Events/SHEvent.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" -#include "Physics/Collision/SHCompositeCollider.h" +#include "Physics/Collision/SHCollider.h" #include "Physics/Collision/SHPhysicsRaycastResult.h" -#include "Physics/Collision/CollisionShapes/SHSphere.h" +#include "Physics/Collision/Shapes/SHSphere.h" namespace SHADE @@ -138,7 +138,7 @@ namespace SHADE SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); - static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCompositeCollider& collider) noexcept; + static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; }; diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index f9e7a3cd..97b555af 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -308,6 +308,8 @@ namespace SHADE const bool IS_RIGID_BODY = ADDED_ID == RIGID_BODY_COMPONENT_ID; const bool IS_COLLIDER = ADDED_ID == COLLIDER_COMPONENT_ID; + // TODO: Hull Collider + // Check if its a physics component const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER; if (!IS_PHYSICS_COMPONENT) @@ -329,7 +331,7 @@ namespace SHADE if (IS_COLLIDER) { - physicsObjectManager.AddCollider(EID); + physicsObjectManager.AddCollider(EID, SHCollider::Type::COMPOSITE); if (collisionSpace) { diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 18d8d63f..6f3b2336 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -1,7 +1,6 @@ #pragma once #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" -#include "Physics/Collision/CollisionShapes/SHSphere.h" #include "Resource/SHResourceManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" @@ -12,6 +11,7 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h" +#include "Physics/Collision/SHCompositeCollider.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" namespace YAML @@ -261,14 +261,14 @@ namespace YAML return false; auto* collider = rhs.GetCollider(); - switch (colliderType) { - case SHCollisionShape::Type::SPHERE: collider->AddSphereCollisionShape(1.0f); break; - case SHCollisionShape::Type::BOX: collider->AddBoxCollisionShape(SHVec3::One); break; - case SHCollisionShape::Type::CAPSULE: break; - default:; + case SHCollisionShape::Type::SPHERE: collider->AddSphereCollisionShape(1.0f); break; + case SHCollisionShape::Type::BOX: collider->AddBoxCollisionShape(SHVec3::One); break; + case SHCollisionShape::Type::CAPSULE: break; + default:; } + YAML::convert::decode(colliderNode, *collider->GetCollisionShape(numColliders++)); } } -- 2.40.1 From c484a088fdc13471a1e16d057dae61409ebeec76 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 01:12:25 +0800 Subject: [PATCH 68/84] Added first half of Gauss Map Optimised SAT --- Assets/Scenes/PhysicsSandbox.shade | 88 ++++++++++- .../Collision/Narrowphase/SHCollision.h | 25 ++- .../Narrowphase/SHConvexVsConvex.cpp | 144 ++++++++++++++++-- .../src/Physics/Collision/Shapes/SHBox.cpp | 24 +++ .../src/Physics/Collision/Shapes/SHBox.h | 11 +- .../Shapes/SHCollisionShapeLibrary.cpp | 8 +- .../Collision/Shapes/SHConvexPolyhedron.h | 20 ++- 7 files changed, 291 insertions(+), 29 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 6dea778f..d0985215 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,7 +45,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 4, z: 5} + Position: {x: 1, y: 10, z: 3} Pitch: 0 Yaw: 0 Roll: 0 @@ -62,7 +62,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.45715916, y: 7, z: 0.227711335} + Translate: {x: -1.45715916, y: 7.37748241, z: 0.227711335} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -77,7 +77,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -273,4 +273,86 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true + Scripts: ~ +- EID: 7 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0.899999976, y: 10, z: 0} + Rotate: {x: -0, y: 0, z: 0.785398185} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Dynamic + Auto Mass: false + Mass: 1 + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: true + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: false + Colliders: + - Is Trigger: true + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 8 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -0.5, y: 10, z: 0} + Rotate: {x: -0, y: 0.785398185, z: -0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + RigidBody Component: + Type: Dynamic + Auto Mass: false + Mass: 1 + Drag: 0.00999999978 + Angular Drag: 0.00999999978 + Use Gravity: true + Gravity Scale: 1 + Interpolate: true + Sleeping Enabled: true + Freeze Position X: false + Freeze Position Y: true + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + IsActive: true + Collider Component: + DrawColliders: false + Colliders: + - Is Trigger: true + Collision Tag: 1 + Type: Box + Half Extents: {x: 1, y: 1, z: 1} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 0ce1f688..8a465d4a 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -13,6 +13,7 @@ // Project Headers #include "Physics/Collision/Contacts/SHManifold.h" #include "Physics/Collision/Contacts/SHCollisionKey.h" +#include "Physics/Collision/Shapes/SHHalfEdgeStructure.h" namespace SHADE @@ -72,11 +73,18 @@ namespace SHADE struct FaceQuery { - bool colliding = false; + bool colliding = false; // Allows for early out int32_t closestFace = -1; float bestDistance = std::numeric_limits::lowest(); }; + struct EdgeQuery + { + int32_t halfEdgeA = -1; + int32_t halfEdgeB = -1; + float bestDistance = std::numeric_limits::lowest(); + }; + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ @@ -93,14 +101,19 @@ namespace SHADE // Convex VS Convex - static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; + static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + + static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; + static float distanceBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; /* * TODO: - * static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - * static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - * static bool buildMinkowskiFace (const SHConvexPolyhedron::HalfEdge& edgeA, const SHConvexPolyhedron::HalfEdge& edgeB) noexcept; - * static float distanceBetweenEdges(const SHConvexPolyhedron::HalfEdge& edgeA, const SHConvexPolyhedron::HalfEdge& edgeB, SHConvexPolyhedron& poly) noexcept; + * + * + * + * * static int32_t findIncidentFace (SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; * static uint32_t clip [sutherland-hodgemann clipping] * diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 6753c453..5eedc2c3 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -15,9 +15,9 @@ // Project Headers #include "Math/SHMathHelpers.h" +#include "Math/Geometry/SHPlane.h" #include "Physics/Collision/Shapes/SHConvexPolyhedron.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -26,15 +26,22 @@ namespace SHADE bool SHCollision::ConvexVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - /* - * TODO: - * - * 1. Query face directiosn of a to b. Exit early if separation found. - * 2. query face directions of b to a. Exit early if separation found. - * 3. Query edge directions of a & b. Exit early if separation found. - */ + const SHConvexPolyhedron& POLY_A = dynamic_cast(A); + const SHConvexPolyhedron& POLY_B = dynamic_cast(B); - return false; + const FaceQuery FACE_QUERY_A = queryFaceDirections(POLY_A, POLY_B); + if (FACE_QUERY_A.bestDistance > 0.0f) + return false; + + const FaceQuery FACE_QUERY_B = queryFaceDirections(POLY_B, POLY_A); + if (FACE_QUERY_B.bestDistance > 0.0f) + return false; + + const EdgeQuery EDGE_QUERY = queryEdgeDirections(POLY_A, POLY_B); + if (EDGE_QUERY.bestDistance > 0.0f) + return false; + + return true; } bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept @@ -61,4 +68,123 @@ namespace SHADE return false; } + /*-----------------------------------------------------------------------------------*/ + /* Private Member Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollision::FaceQuery SHCollision::queryFaceDirections(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept + { + FaceQuery faceQuery; + + const int32_t NUM_FACES = A.GetFaceCount(); + for (const int32_t i : std::views::iota(0, NUM_FACES)) + { + const SHHalfEdgeStructure::Face& FACE_A = A.GetFace(i); + const SHVec3 NORMAL_A = A.GetNormal(i); + + // Smallest penetration is point closest to face normal + const SHVec3 SUPPORT_POINT = B.FindSupportPoint(-NORMAL_A); + + const SHVec3 VERTEX_A = A.GetVertex(FACE_A.vertexIndices[0].index); + + const SHPlane FACE_PLANE { VERTEX_A, NORMAL_A }; + const float DISTANCE = FACE_PLANE.SignedDistance(SUPPORT_POINT); + + if (DISTANCE > faceQuery.bestDistance) + { + faceQuery.bestDistance = DISTANCE; + faceQuery.closestFace = i; + } + } + + return faceQuery; + } + + SHCollision::EdgeQuery SHCollision::queryEdgeDirections(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept + { + EdgeQuery edgeQuery; + + const int32_t EDGE_COUNT_A = A.GetHalfEdgeCount(); + const int32_t EDGE_COUNT_B = B.GetHalfEdgeCount(); + + for (int32_t i = 0; i < EDGE_COUNT_A; i += 2) + { + for (int32_t j = 0; j < EDGE_COUNT_B; j += 2) + { + const bool IS_MINKOWSKI_FACE = buildMinkowskiFace(A, B, i, j); + if (!IS_MINKOWSKI_FACE) + continue; + + const float SEPARATION = distanceBetweenEdges(A, B, i, j); + if (SEPARATION > edgeQuery.bestDistance) + { + edgeQuery.bestDistance = SEPARATION; + edgeQuery.halfEdgeA = i; + edgeQuery.halfEdgeB = j; + } + } + } + + return edgeQuery; + } + + bool SHCollision::buildMinkowskiFace(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept + { + // Get Half Edge from both polygons + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(edgeA); + const SHHalfEdgeStructure::HalfEdge& TWIN_EDGE_A = A.GetHalfEdge(HALF_EDGE_A.twinEdgeIndex); + + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = B.GetHalfEdge(edgeB); + const SHHalfEdgeStructure::HalfEdge& TWIN_EDGE_B = B.GetHalfEdge(HALF_EDGE_B.twinEdgeIndex); + + + + // Get normals from face and twin edge face + const SHVec3 NA = A.GetNormal(HALF_EDGE_A.faceIndex); + const SHVec3 NB = A.GetNormal(TWIN_EDGE_A.faceIndex); + const SHVec3 NC = B.GetNormal(HALF_EDGE_B.faceIndex); + const SHVec3 ND = B.GetNormal(TWIN_EDGE_B.faceIndex); + + return isMinkowskiFace(NA, NB, -NC, -ND); + } + + bool SHCollision::isMinkowskiFace(const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept + { + const SHVec3 BXA = SHVec3::Cross(b, a); + const SHVec3 DXC = SHVec3::Cross(d, c); + + const float CBA = SHVec3::Dot(c, BXA); + const float DBA = SHVec3::Dot(d, BXA); + const float ADC = SHVec3::Dot(a, DXC); + const float BDC = SHVec3::Dot(b, DXC); + + return CBA * DBA < 0.0f && ADC * BDC < 0.0f && CBA * BDC > 0.0f; + } + + float SHCollision::distanceBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept + { + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(edgeA); + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = B.GetHalfEdge(edgeB); + + const SHVec3 HEAD_A = A.GetVertex(HALF_EDGE_A.headVertexIndex); + const SHVec3 TAIL_A = A.GetVertex(HALF_EDGE_A.tailVertexIndex); + const SHVec3 HEAD_B = B.GetVertex(HALF_EDGE_B.headVertexIndex); + const SHVec3 TAIL_B = B.GetVertex(HALF_EDGE_B.tailVertexIndex); + + const SHVec3 DIR_A = SHVec3::Normalise(HEAD_A - TAIL_A); + const SHVec3 DIR_B = SHVec3::Normalise(HEAD_B - TAIL_B); + + // Check if the edges are parallel (abs dot product is 1) + const float DOT_BETWEEN_EDGES = std::fabs(SHVec3::Dot(DIR_A, DIR_B)); + if (SHMath::CompareFloat(DOT_BETWEEN_EDGES, 1.0f)) + return std::numeric_limits::lowest(); + + SHVec3 normal = SHVec3::Cross(DIR_A, DIR_B); + // Flip normal if need to ( A -> B) + if (SHVec3::Dot(normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) + normal = -normal; + + return SHVec3::Dot(normal, HEAD_B - HEAD_A); + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp index efe40f7d..8022e487 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp @@ -291,5 +291,29 @@ namespace SHADE return SHAABB{ CENTROID, HALF_EXTENTS }; } + SHVec3 SHBox::FindSupportPoint(const SHVec3& direction) const noexcept + { + float bestDistance = std::numeric_limits::lowest(); + + + SHVec3 vertices[NUM_VERTICES]; + GetCorners(vertices); + + // No reason to put the center really.. + SHVec3 bestPoint = Center; + for (auto& vertex : vertices) + { + const float PROJECTION = SHVec3::Dot(vertex, direction); + + if (PROJECTION > bestDistance) + { + bestDistance = PROJECTION; + bestPoint = vertex; + } + } + + return bestPoint; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h index 044af40f..480b2501 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h @@ -109,11 +109,12 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void Update () noexcept override; - [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; - [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; - [[nodiscard]] SHMatrix GetTRS () const noexcept override; - [[nodiscard]] SHAABB ComputeAABB () const noexcept override; + void Update () noexcept override; + [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; + [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; + [[nodiscard]] SHMatrix GetTRS () const noexcept override; + [[nodiscard]] SHAABB ComputeAABB () const noexcept override; + [[nodiscard]] SHVec3 FindSupportPoint (const SHVec3& direction) const noexcept override; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp index e0202d67..c70728f3 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp @@ -150,11 +150,11 @@ namespace SHADE const int32_t FACE_VERTICES[NUM_FACES][NUM_VERTICES_PER_FACE] { { 0, 1, 2, 3 } - , { 1, 5, 6, 2 } + , { 5, 6, 2, 1 } , { 5, 4, 7, 6 } - , { 4, 0, 3, 7 } - , { 3, 2, 6, 7 } - , { 4, 5, 1, 0 } + , { 0, 3, 7, 4 } + , { 2, 6, 7, 3 } + , { 5, 1, 0, 4 } }; for (int i = 0; i < NUM_FACES; ++i) diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h index dd4595d1..3944c556 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h +++ b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h @@ -63,8 +63,24 @@ namespace SHADE [[nodiscard]] int32_t GetHalfEdgeCount () const noexcept; [[nodiscard]] const SHHalfEdgeStructure::HalfEdge& GetHalfEdge (int index) const; - [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; - [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; + // Virtual Methods + + [[nodiscard]] virtual SHVec3 GetVertex (int index) const = 0; + [[nodiscard]] virtual SHVec3 GetNormal (int faceIndex) const = 0; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief + * Finds the most extreme point on the polygon in a given direction. + * @param direction + * The direction to find the support point in. + * @return + * The most extreme vertex in the given direction. + */ + [[nodiscard]] virtual SHVec3 FindSupportPoint (const SHVec3& direction) const noexcept = 0; protected: /*---------------------------------------------------------------------------------*/ -- 2.40.1 From 68e11ba48ed0d27d7ea78fc180738b787920acd9 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 13:42:17 +0800 Subject: [PATCH 69/84] Added edge vs edge contacts for convex polyhedron collisions --- Assets/Scenes/PhysicsSandbox.shade | 26 ++--- .../Collision/Narrowphase/SHCollision.h | 11 +- .../Narrowphase/SHConvexVsConvex.cpp | 100 ++++++++++++++++++ 3 files changed, 119 insertions(+), 18 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index d0985215..b405fac2 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,9 +45,9 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 1, y: 10, z: 3} + Position: {x: -0.5, y: 10, z: -3} Pitch: 0 - Yaw: 0 + Yaw: 180 Roll: 0 Width: 1920 Height: 1080 @@ -84,7 +84,7 @@ Freeze Rotation Z: false IsActive: true Collider Component: - DrawColliders: false + DrawColliders: true Colliders: - Is Trigger: false Collision Tag: 1 @@ -95,7 +95,7 @@ Density: 1 Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} - - Is Trigger: false + - Is Trigger: true Collision Tag: 1 Type: Sphere Radius: 0.5 @@ -280,9 +280,9 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.899999976, y: 10, z: 0} - Rotate: {x: -0, y: 0, z: 0.785398185} - Scale: {x: 1, y: 1, z: 1} + Translate: {x: 0.524352431, y: 11.1989822, z: 0.0463808179} + Rotate: {x: -0, y: 0.785398066, z: 0.785398185} + Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} IsActive: true RigidBody Component: Type: Dynamic @@ -295,7 +295,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -304,7 +304,7 @@ Collider Component: DrawColliders: false Colliders: - - Is Trigger: true + - Is Trigger: false Collision Tag: 1 Type: Box Half Extents: {x: 1, y: 1, z: 1} @@ -322,13 +322,13 @@ Components: Transform Component: Translate: {x: -0.5, y: 10, z: 0} - Rotate: {x: -0, y: 0.785398185, z: -0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: - Type: Dynamic + Type: Static Auto Mass: false - Mass: 1 + Mass: .inf Drag: 0.00999999978 Angular Drag: 0.00999999978 Use Gravity: true @@ -345,7 +345,7 @@ Collider Component: DrawColliders: false Colliders: - - Is Trigger: true + - Is Trigger: false Collision Tag: 1 Type: Box Half Extents: {x: 1, y: 1, z: 1} diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 8a465d4a..57777cca 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -101,12 +101,13 @@ namespace SHADE // Convex VS Convex - static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; - static float distanceBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; + static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB, SHVec3& normal) noexcept; /* * TODO: diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 5eedc2c3..0f899443 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -17,6 +17,7 @@ #include "Math/SHMathHelpers.h" #include "Math/Geometry/SHPlane.h" #include "Physics/Collision/Shapes/SHConvexPolyhedron.h" +#include "Tools/Utilities/SHUtilities.h" namespace SHADE { @@ -65,6 +66,55 @@ namespace SHADE * */ + const SHConvexPolyhedron& POLY_A = dynamic_cast(A); + const SHConvexPolyhedron& POLY_B = dynamic_cast(B); + + const FaceQuery FACE_QUERY_A = queryFaceDirections(POLY_A, POLY_B); + if (FACE_QUERY_A.bestDistance > 0.0f) + return false; + + const FaceQuery FACE_QUERY_B = queryFaceDirections(POLY_B, POLY_A); + if (FACE_QUERY_B.bestDistance > 0.0f) + return false; + + const EdgeQuery EDGE_QUERY = queryEdgeDirections(POLY_A, POLY_B); + if (EDGE_QUERY.bestDistance > 0.0f) + return false; + + const FaceQuery& BEST_FACE_QUERY = FACE_QUERY_A.bestDistance > FACE_QUERY_B.bestDistance ? FACE_QUERY_A : FACE_QUERY_B; + + // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on + // each edge and use that as the contact point. + // Artificially increase the depth of this collision by a small tolerance to tend towards picking a face query in the next frame. + if (EDGE_QUERY.bestDistance > BEST_FACE_QUERY.bestDistance) + { + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); + + // In this scenario, we only have one contact + + SHContactFeatures featurePair; + featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); + featurePair.indexA = HALF_EDGE_A.tailVertexIndex; + featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); + featurePair.indexB = HALF_EDGE_B.tailVertexIndex; + + SHContact contact; + contact.featurePair = featurePair; + + contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB, manifold.normal); + contact.penetration = EDGE_QUERY.bestDistance; + + manifold.contacts[0] = contact; + manifold.numContacts = 1; + + return true; + } + + // Use a bias to favour a normal in the direction of A -> B + + + return false; } @@ -187,4 +237,54 @@ namespace SHADE return SHVec3::Dot(normal, HEAD_B - HEAD_A); } + SHVec3 SHCollision::findClosestPointBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB, SHVec3& normal) noexcept + { + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(edgeA); + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = B.GetHalfEdge(edgeB); + + const SHVec3 HEAD_A = A.GetVertex(HALF_EDGE_A.headVertexIndex); + const SHVec3 TAIL_A = A.GetVertex(HALF_EDGE_A.tailVertexIndex); + const SHVec3 HEAD_B = B.GetVertex(HALF_EDGE_B.headVertexIndex); + const SHVec3 TAIL_B = B.GetVertex(HALF_EDGE_B.tailVertexIndex); + + const SHVec3 VA = SHVec3::Normalise(HEAD_A - TAIL_A); + const SHVec3 VB = SHVec3::Normalise(HEAD_B - TAIL_B); + + normal = SHVec3::Cross(VB, VA); + // Flip normal if need to ( A -> B) + if (SHVec3::Dot(normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) + normal = -normal; + + + /* + * Find a1, a2, b1, b2, c1, c2 to solve the simultaneous equation + * C' = TAIL_B - TAIL_A + * U = VA / VB + * + * a = VBxUx + VByUy + VBzUz + * b = -VAxUx - VAyUy - VAzUz + * c = (Cx'Ux + Cy'Uy + Cz'Uz) + */ + + const SHVec3 C = TAIL_B - TAIL_A; + + const float A1 = VB.x * VA.x + VB.y * VA.y + VB.z * VA.z; + const float A2 = VB.x * VB.x + VB.y * VB.y + VB.z * VB.z; + const float B1 = -VA.x * VA.x + -VA.y * VA.y + -VA.z * VA.z; + const float B2 = -VA.x * VB.x + -VA.y * VB.y + -VA.z * VB.z; + const float C1 = C.x * VA.x + C.y + VA.y + C.z + VA.z; + const float C2 = C.x * VB.x + C.y + VB.y + C.z + VB.z; + + /* + * R = -c2 / ( b2 - (a2 * (c1 + b1)) / a1 ) + * S = (b1 / a1) * (c2 / ( b2 - (a2 * b1) / a1 )) - (c1 / a1) + */ + + const float R = -C2 / (B2 - (A2 * (C1 + B1)) / A1); + + // Just take a point from A since it's A -> B + return TAIL_A + R * VA; + } + + } // namespace SHADE \ No newline at end of file -- 2.40.1 From 016f6c804da9cb64c3721bcbdb5191e1ae2120bd Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 14:40:06 +0800 Subject: [PATCH 70/84] Added more comments and clarity for --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../Collision/Narrowphase/SHCollision.h | 2 +- .../Narrowphase/SHConvexVsConvex.cpp | 83 ++++++++++++------- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index b405fac2..0b732f64 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -280,7 +280,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.524352431, y: 11.1989822, z: 0.0463808179} + Translate: {x: 0.524352431, y: 11.5, z: 0.0463808179} Rotate: {x: -0, y: 0.785398066, z: 0.785398185} Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 57777cca..0fe0b3f7 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -107,7 +107,7 @@ namespace SHADE static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB, SHVec3& normal) noexcept; + static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; /* * TODO: diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 0f899443..5924ee73 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -83,6 +83,8 @@ namespace SHADE const FaceQuery& BEST_FACE_QUERY = FACE_QUERY_A.bestDistance > FACE_QUERY_B.bestDistance ? FACE_QUERY_A : FACE_QUERY_B; + uint32_t numContacts = 0; + // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on // each edge and use that as the contact point. // Artificially increase the depth of this collision by a small tolerance to tend towards picking a face query in the next frame. @@ -91,22 +93,31 @@ namespace SHADE const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); + const SHVec3 HEAD_A = POLY_A.GetVertex(HALF_EDGE_A.headVertexIndex); + const SHVec3 TAIL_A = POLY_A.GetVertex(HALF_EDGE_A.tailVertexIndex); + const SHVec3 HEAD_B = POLY_B.GetVertex(HALF_EDGE_B.headVertexIndex); + const SHVec3 TAIL_B = POLY_B.GetVertex(HALF_EDGE_B.tailVertexIndex); + + const SHVec3 VA = SHVec3::Normalise(HEAD_A - TAIL_A); + const SHVec3 VB = SHVec3::Normalise(HEAD_B - TAIL_B); + + manifold.normal = SHVec3::Cross(VB, VA); + // Flip normal if need to ( A -> B) + if (SHVec3::Dot(manifold.normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) + manifold.normal = -manifold.normal; + // In this scenario, we only have one contact - - SHContactFeatures featurePair; - featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - featurePair.indexA = HALF_EDGE_A.tailVertexIndex; - featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - featurePair.indexB = HALF_EDGE_B.tailVertexIndex; - SHContact contact; - contact.featurePair = featurePair; + contact.featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); + contact.featurePair.indexA = HALF_EDGE_A.tailVertexIndex; + contact.featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); + contact.featurePair.indexB = HALF_EDGE_B.tailVertexIndex; - contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB, manifold.normal); + contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); contact.penetration = EDGE_QUERY.bestDistance; - manifold.contacts[0] = contact; - manifold.numContacts = 1; + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; return true; } @@ -237,8 +248,22 @@ namespace SHADE return SHVec3::Dot(normal, HEAD_B - HEAD_A); } - SHVec3 SHCollision::findClosestPointBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB, SHVec3& normal) noexcept + SHVec3 SHCollision::findClosestPointBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept { + /* + * The two edges can be parameterised in the form p + tv + * + * LA(r) = A + rVA + * LB(s) = B + sVB + * + * The vector between the closest points is the cross product of VA and VB. + * Since the cross product is orthogonal to VA and VB, we can generalise this as: + * (LB(s) - LA(r)) /dot VA = 0 + * (LB(s) - LA(r)) /dot VB = 0 + * + * Where LB(s) - LA(r) is the same vector as VB X VA. + */ + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(edgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = B.GetHalfEdge(edgeB); @@ -250,37 +275,35 @@ namespace SHADE const SHVec3 VA = SHVec3::Normalise(HEAD_A - TAIL_A); const SHVec3 VB = SHVec3::Normalise(HEAD_B - TAIL_B); - normal = SHVec3::Cross(VB, VA); - // Flip normal if need to ( A -> B) - if (SHVec3::Dot(normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) - normal = -normal; - - /* * Find a1, a2, b1, b2, c1, c2 to solve the simultaneous equation - * C' = TAIL_B - TAIL_A - * U = VA / VB * - * a = VBxUx + VByUy + VBzUz - * b = -VAxUx - VAyUy - VAzUz - * c = (Cx'Ux + Cy'Uy + Cz'Uz) + * C' = TAIL_B - TAIL_A + * + * a = VB /dot U + * b = -VA /dot U + * c = C' /dot U + * + * U is either VA or VB */ const SHVec3 C = TAIL_B - TAIL_A; - const float A1 = VB.x * VA.x + VB.y * VA.y + VB.z * VA.z; - const float A2 = VB.x * VB.x + VB.y * VB.y + VB.z * VB.z; - const float B1 = -VA.x * VA.x + -VA.y * VA.y + -VA.z * VA.z; - const float B2 = -VA.x * VB.x + -VA.y * VB.y + -VA.z * VB.z; - const float C1 = C.x * VA.x + C.y + VA.y + C.z + VA.z; - const float C2 = C.x * VB.x + C.y + VB.y + C.z + VB.z; + const float VB_DOT_VA = SHVec3::Dot(VB, VA); + const float VB_DOT_VB = SHVec3::Dot(VB, VB); + const float AV_DOT_VA = SHVec3::Dot(-VA, VA); + const float AV_DOT_VB = SHVec3::Dot(-VA, VB); + const float C_DOT_VA = SHVec3::Dot(C, VA); + const float C_DOT_VB = SHVec3::Dot(C, VB); /* * R = -c2 / ( b2 - (a2 * (c1 + b1)) / a1 ) * S = (b1 / a1) * (c2 / ( b2 - (a2 * b1) / a1 )) - (c1 / a1) + * + * We only need to solve for R */ - const float R = -C2 / (B2 - (A2 * (C1 + B1)) / A1); + const float R = -C_DOT_VB / (AV_DOT_VB - (VB_DOT_VB * (C_DOT_VA + AV_DOT_VA)) / VB_DOT_VA); // Just take a point from A since it's A -> B return TAIL_A + R * VA; -- 2.40.1 From 0c92e7ff6cee8ff37d9da3d7c52e4fe270915635 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 14:40:06 +0800 Subject: [PATCH 71/84] Added more comments and clarity for polyhedron edge contacts --- Assets/Scenes/PhysicsSandbox.shade | 2 +- .../Collision/Narrowphase/SHCollision.h | 2 +- .../Narrowphase/SHConvexVsConvex.cpp | 83 ++++++++++++------- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index b405fac2..0b732f64 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -280,7 +280,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.524352431, y: 11.1989822, z: 0.0463808179} + Translate: {x: 0.524352431, y: 11.5, z: 0.0463808179} Rotate: {x: -0, y: 0.785398066, z: 0.785398185} Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 57777cca..0fe0b3f7 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -107,7 +107,7 @@ namespace SHADE static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB, SHVec3& normal) noexcept; + static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; /* * TODO: diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 0f899443..5924ee73 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -83,6 +83,8 @@ namespace SHADE const FaceQuery& BEST_FACE_QUERY = FACE_QUERY_A.bestDistance > FACE_QUERY_B.bestDistance ? FACE_QUERY_A : FACE_QUERY_B; + uint32_t numContacts = 0; + // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on // each edge and use that as the contact point. // Artificially increase the depth of this collision by a small tolerance to tend towards picking a face query in the next frame. @@ -91,22 +93,31 @@ namespace SHADE const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); + const SHVec3 HEAD_A = POLY_A.GetVertex(HALF_EDGE_A.headVertexIndex); + const SHVec3 TAIL_A = POLY_A.GetVertex(HALF_EDGE_A.tailVertexIndex); + const SHVec3 HEAD_B = POLY_B.GetVertex(HALF_EDGE_B.headVertexIndex); + const SHVec3 TAIL_B = POLY_B.GetVertex(HALF_EDGE_B.tailVertexIndex); + + const SHVec3 VA = SHVec3::Normalise(HEAD_A - TAIL_A); + const SHVec3 VB = SHVec3::Normalise(HEAD_B - TAIL_B); + + manifold.normal = SHVec3::Cross(VB, VA); + // Flip normal if need to ( A -> B) + if (SHVec3::Dot(manifold.normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) + manifold.normal = -manifold.normal; + // In this scenario, we only have one contact - - SHContactFeatures featurePair; - featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - featurePair.indexA = HALF_EDGE_A.tailVertexIndex; - featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - featurePair.indexB = HALF_EDGE_B.tailVertexIndex; - SHContact contact; - contact.featurePair = featurePair; + contact.featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); + contact.featurePair.indexA = HALF_EDGE_A.tailVertexIndex; + contact.featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); + contact.featurePair.indexB = HALF_EDGE_B.tailVertexIndex; - contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB, manifold.normal); + contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); contact.penetration = EDGE_QUERY.bestDistance; - manifold.contacts[0] = contact; - manifold.numContacts = 1; + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; return true; } @@ -237,8 +248,22 @@ namespace SHADE return SHVec3::Dot(normal, HEAD_B - HEAD_A); } - SHVec3 SHCollision::findClosestPointBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB, SHVec3& normal) noexcept + SHVec3 SHCollision::findClosestPointBetweenEdges(const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept { + /* + * The two edges can be parameterised in the form p + tv + * + * LA(r) = A + rVA + * LB(s) = B + sVB + * + * The vector between the closest points is the cross product of VA and VB. + * Since the cross product is orthogonal to VA and VB, we can generalise this as: + * (LB(s) - LA(r)) /dot VA = 0 + * (LB(s) - LA(r)) /dot VB = 0 + * + * Where LB(s) - LA(r) is the same vector as VB X VA. + */ + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(edgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = B.GetHalfEdge(edgeB); @@ -250,37 +275,35 @@ namespace SHADE const SHVec3 VA = SHVec3::Normalise(HEAD_A - TAIL_A); const SHVec3 VB = SHVec3::Normalise(HEAD_B - TAIL_B); - normal = SHVec3::Cross(VB, VA); - // Flip normal if need to ( A -> B) - if (SHVec3::Dot(normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) - normal = -normal; - - /* * Find a1, a2, b1, b2, c1, c2 to solve the simultaneous equation - * C' = TAIL_B - TAIL_A - * U = VA / VB * - * a = VBxUx + VByUy + VBzUz - * b = -VAxUx - VAyUy - VAzUz - * c = (Cx'Ux + Cy'Uy + Cz'Uz) + * C' = TAIL_B - TAIL_A + * + * a = VB /dot U + * b = -VA /dot U + * c = C' /dot U + * + * U is either VA or VB */ const SHVec3 C = TAIL_B - TAIL_A; - const float A1 = VB.x * VA.x + VB.y * VA.y + VB.z * VA.z; - const float A2 = VB.x * VB.x + VB.y * VB.y + VB.z * VB.z; - const float B1 = -VA.x * VA.x + -VA.y * VA.y + -VA.z * VA.z; - const float B2 = -VA.x * VB.x + -VA.y * VB.y + -VA.z * VB.z; - const float C1 = C.x * VA.x + C.y + VA.y + C.z + VA.z; - const float C2 = C.x * VB.x + C.y + VB.y + C.z + VB.z; + const float VB_DOT_VA = SHVec3::Dot(VB, VA); + const float VB_DOT_VB = SHVec3::Dot(VB, VB); + const float AV_DOT_VA = SHVec3::Dot(-VA, VA); + const float AV_DOT_VB = SHVec3::Dot(-VA, VB); + const float C_DOT_VA = SHVec3::Dot(C, VA); + const float C_DOT_VB = SHVec3::Dot(C, VB); /* * R = -c2 / ( b2 - (a2 * (c1 + b1)) / a1 ) * S = (b1 / a1) * (c2 / ( b2 - (a2 * b1) / a1 )) - (c1 / a1) + * + * We only need to solve for R */ - const float R = -C2 / (B2 - (A2 * (C1 + B1)) / A1); + const float R = -C_DOT_VB / (AV_DOT_VB - (VB_DOT_VB * (C_DOT_VA + AV_DOT_VA)) / VB_DOT_VA); // Just take a point from A since it's A -> B return TAIL_A + R * VA; -- 2.40.1 From 8ca4045d555d3002d66ff6d358c758dd606b0145 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 17:53:48 +0800 Subject: [PATCH 72/84] R for retard --- Assets/Scenes/PhysicsSandbox.shade | 4 +- .../Collision/Narrowphase/SHCollision.h | 3 +- .../Narrowphase/SHConvexVsConvex.cpp | 109 ++++++++++++------ .../Narrowphase/SHSphereVsConvex.cpp | 1 + .../src/Physics/Dynamics/SHContactSolver.cpp | 5 +- .../src/Physics/Dynamics/SHContactSolver.h | 3 - SHADE_Engine/src/Physics/SHPhysicsConstants.h | 44 +++++++ 7 files changed, 128 insertions(+), 41 deletions(-) create mode 100644 SHADE_Engine/src/Physics/SHPhysicsConstants.h diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 0b732f64..d30c8f07 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -280,7 +280,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.524352431, y: 11.5, z: 0.0463808179} + Translate: {x: 0.524352431, y: 13.5, z: 0.0463808179} Rotate: {x: -0, y: 0.785398066, z: 0.785398185} Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} IsActive: true @@ -291,7 +291,7 @@ Drag: 0.00999999978 Angular Drag: 0.00999999978 Use Gravity: true - Gravity Scale: 1 + Gravity Scale: 0.5 Interpolate: true Sleeping Enabled: true Freeze Position X: false diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 0fe0b3f7..980914c1 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -108,6 +108,7 @@ namespace SHADE static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; /* * TODO: @@ -115,7 +116,7 @@ namespace SHADE * * * - * static int32_t findIncidentFace (SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; + * * static uint32_t clip [sutherland-hodgemann clipping] * * ! References diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 5924ee73..be43af8f 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -17,6 +17,7 @@ #include "Math/SHMathHelpers.h" #include "Math/Geometry/SHPlane.h" #include "Physics/Collision/Shapes/SHConvexPolyhedron.h" +#include "Physics/SHPhysicsConstants.h" #include "Tools/Utilities/SHUtilities.h" namespace SHADE @@ -47,24 +48,7 @@ namespace SHADE bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - /* - * TODO: - * - * 1. Query face directions of a to b. Exit early if separation found. - * 2. Query face directions of b to a. Exit early if separation found. - * 3. Query edge directions of a & b. Exit early if separation found. - * - * (*)!! Apply weight to improve frame coherence of normal directions. DONT FORGET FLIP FLOP! - * 4. From above, save the axis of minimum penetration (reference face) - * 5. Find the most anti-parallel face on other shape (incident face) - * 6. Clip incident face against side planes of reference face. (Sutherland-Hodgeman Clipping). - * Keep all vertices below reference face. - * 7. Reduce manifold to 4 contact points. We only need 4 contact points for a stable manifold. - * - * Remember to save IDs in queries. - * During generation of incident face, store IDs of face. - * - */ + static constexpr float TOLERANCE = 0.1f + SHPHYSICS_LINEAR_SLOP; const SHConvexPolyhedron& POLY_A = dynamic_cast(A); const SHConvexPolyhedron& POLY_B = dynamic_cast(B); @@ -81,14 +65,33 @@ namespace SHADE if (EDGE_QUERY.bestDistance > 0.0f) return false; - const FaceQuery& BEST_FACE_QUERY = FACE_QUERY_A.bestDistance > FACE_QUERY_B.bestDistance ? FACE_QUERY_A : FACE_QUERY_B; + // Apply weight to improve frame coherence of normal directions. + // We want a normal in the direction from A -> B, so we flip the normal if needed. + bool flipNormal = false; + const SHConvexPolyhedron* referencePoly = nullptr; + const SHConvexPolyhedron* incidentPoly = nullptr; + + FaceQuery minFaceQuery; + if (FACE_QUERY_A.bestDistance + TOLERANCE > FACE_QUERY_B.bestDistance) + { + minFaceQuery = FACE_QUERY_A; + referencePoly = &POLY_A; + incidentPoly = &POLY_B; + } + else + { + minFaceQuery = FACE_QUERY_B; + referencePoly = &POLY_B; + incidentPoly = &POLY_A; + flipNormal = true; + } uint32_t numContacts = 0; + // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on // each edge and use that as the contact point. - // Artificially increase the depth of this collision by a small tolerance to tend towards picking a face query in the next frame. - if (EDGE_QUERY.bestDistance > BEST_FACE_QUERY.bestDistance) + if (EDGE_QUERY.bestDistance > minFaceQuery.bestDistance + TOLERANCE) { const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); @@ -122,7 +125,24 @@ namespace SHADE return true; } - // Use a bias to favour a normal in the direction of A -> B + const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace); + const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL); + + + /* + * TODO: + * + * !! + * 4. From above, save the axis of minimum penetration (reference face) + * 5. Find the most anti-parallel face on other shape (incident face) + * 6. Clip incident face against side planes of reference face. (Sutherland-Hodgeman Clipping). + * Keep all vertices below reference face. + * 7. Reduce manifold to 4 contact points. We only need 4 contact points for a stable manifold. + * + * Remember to save IDs in queries. + * During generation of incident face, store IDs of face. + * + */ @@ -289,25 +309,48 @@ namespace SHADE const SHVec3 C = TAIL_B - TAIL_A; - const float VB_DOT_VA = SHVec3::Dot(VB, VA); - const float VB_DOT_VB = SHVec3::Dot(VB, VB); - const float AV_DOT_VA = SHVec3::Dot(-VA, VA); - const float AV_DOT_VB = SHVec3::Dot(-VA, VB); - const float C_DOT_VA = SHVec3::Dot(C, VA); - const float C_DOT_VB = SHVec3::Dot(C, VB); + const float VB_DOT_VA = SHVec3::Dot(VB, VA); // a1 + const float VB_DOT_VB = SHVec3::Dot(VB, VB); // a2 + const float AV_DOT_VA = SHVec3::Dot(-VA, VA); // b1 + const float AV_DOT_VB = SHVec3::Dot(-VA, VB); // b2 + const float C_DOT_VA = SHVec3::Dot(C, VA); // c1 + const float C_DOT_VB = SHVec3::Dot(C, VB); // c2 /* - * R = -c2 / ( b2 - (a2 * (c1 + b1)) / a1 ) - * S = (b1 / a1) * (c2 / ( b2 - (a2 * b1) / a1 )) - (c1 / a1) - * * We only need to solve for R + * R = (c1a2 / a1 - c2) / ( b2 - a2b1/a1 ) */ - - const float R = -C_DOT_VB / (AV_DOT_VB - (VB_DOT_VB * (C_DOT_VA + AV_DOT_VA)) / VB_DOT_VA); + + const float A2_OVER_A1 = VB_DOT_VB / VB_DOT_VA; + const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB; + const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; + const float R = NUMERATOR / DENOMINATOR; // Just take a point from A since it's A -> B return TAIL_A + R * VA; } + int32_t SHCollision::findIncidentFace(const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept + { + // Get the most anti-parallel face to the normal + int32_t bestFace = 0; + float bestProjection = std::numeric_limits::max(); + + const int32_t NUM_FACES = poly.GetFaceCount(); + for (const int32_t i : std::views::iota(0, NUM_FACES)) + { + const SHVec3 INC_NORMAL = poly.GetNormal(i); + const float PROJECTION = SHVec3::Dot(INC_NORMAL, normal); + + if (PROJECTION < bestProjection) + { + bestProjection = PROJECTION; + bestFace = i; + } + } + + return bestFace; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index 2b08313b..e6a961e0 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -19,6 +19,7 @@ #include "Math/SHMathHelpers.h" #include "Physics/Collision/Shapes/SHSphere.h" #include "Physics/Collision/Shapes/SHConvexPolyhedron.h" +#include "Physics/SHPhysicsConstants.h" namespace SHADE { diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index ed4c9aa8..fa6f1266 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -15,6 +15,7 @@ // Project Headers #include "Math/SHMathHelpers.h" +#include "Physics/SHPhysicsConstants.h" namespace SHADE { @@ -190,8 +191,8 @@ namespace SHADE const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); - const float ERROR_BIAS = BAUMGARTE_FACTOR * INV_DT * std::min(0.0f, -contact.penetration + PENETRATION_SLOP); - const float RESTITUTION_BIAS = -constraint.restitution * RV_N; + const float ERROR_BIAS = SHPHYSICS_BAUMGARTE * INV_DT * std::min(0.0f, -contact.penetration + SHPHYSICS_LINEAR_SLOP); + const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f; contact.bias = ERROR_BIAS + RESTITUTION_BIAS; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h index 56955f74..3146a743 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h @@ -78,9 +78,6 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr float BAUMGARTE_FACTOR = 0.2f; - static constexpr float PENETRATION_SLOP = 0.05f; - VelocityStates velocityStates; ContactConstraints contactConstraints; diff --git a/SHADE_Engine/src/Physics/SHPhysicsConstants.h b/SHADE_Engine/src/Physics/SHPhysicsConstants.h new file mode 100644 index 00000000..0d8f6fc8 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsConstants.h @@ -0,0 +1,44 @@ +/**************************************************************************************** + * \file SHPhysicsConstants.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Definitions for constants used in physics simulations + * + * \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 Includes +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /** + * @brief + * The number of simulations length for every real world unit meter.
+ * Modify this to change the global scale of the simulation. + */ + static constexpr float SHPHYSICS_LENGTHS_PER_UNIT_METER = 1.0f; + + /** + * @brief + * Linear Collision & Constraint tolerance. + */ + static constexpr float SHPHYSICS_LINEAR_SLOP = 0.005f * SHPHYSICS_LENGTHS_PER_UNIT_METER; + + /** + * @brief + * Velocity threshold for restitution to be applied. + */ + static constexpr float SHPHYSICS_RESTITUTION_THRESHOLD = 1.0f; + + /** + * @brief + * Scaling factor to control how fast overlaps are resolved.
+ * 1 is ideal for instant correction, but values close to 1 can lead to overshoot. + */ + static constexpr float SHPHYSICS_BAUMGARTE = 0.2f; + +} -- 2.40.1 From 13d562505533707e921a7f900717ed49a163bef7 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 13 Jan 2023 15:18:35 +0800 Subject: [PATCH 73/84] Reverted changes to inertia tensors Created a new branch since I reverted to an older commit but kept some new updates --- Assets/Scenes/PhysicsSandbox.shade | 19 ++++---------- .../Broadphase/SHDynamicAABBTree.cpp | 2 +- .../Physics/Collision/Contacts/SHContact.h | 14 +++-------- .../Collision/Narrowphase/SHCollision.h | 1 + .../Narrowphase/SHConvexVsConvex.cpp | 25 ++++++++++--------- .../Narrowphase/SHSphereVsConvex.cpp | 14 ++++++++++- .../src/Physics/Dynamics/SHContactManager.cpp | 4 ++- .../src/Physics/Dynamics/SHContactSolver.cpp | 15 +++++------ SHADE_Engine/src/Physics/SHPhysicsConstants.h | 2 +- 9 files changed, 49 insertions(+), 47 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index d30c8f07..6d15850b 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,9 +45,9 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: -0.5, y: 10, z: -3} + Position: {x: 0, y: 0, z: 7} Pitch: 0 - Yaw: 180 + Yaw: 0 Roll: 0 Width: 1920 Height: 1080 @@ -71,7 +71,7 @@ Auto Mass: false Mass: 10 Drag: 0.00999999978 - Angular Drag: 0.00999999978 + Angular Drag: 0 Use Gravity: true Gravity Scale: 1 Interpolate: true @@ -95,15 +95,6 @@ Density: 1 Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} - - Is Trigger: true - Collision Tag: 1 - Type: Sphere - Radius: 0.5 - Friction: 0.400000006 - Bounciness: 0 - Density: 1 - Position Offset: {x: 0.75, y: 0.5, z: 0} - Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true Scripts: - Type: PhysicsTestObj @@ -280,7 +271,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.524352431, y: 13.5, z: 0.0463808179} + Translate: {x: 1, y: 2, z: 3} Rotate: {x: -0, y: 0.785398066, z: 0.785398185} Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} IsActive: true @@ -321,7 +312,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -0.5, y: 10, z: 0} + Translate: {x: 0, y: 0, z: 3} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index dc87d706..7177e517 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -337,7 +337,7 @@ namespace SHADE { SHASSERT(index >= 0 && index < capacity, "Trying to free an invalid AABB Tree node!") - nodes[index].next = NULL_NODE; + nodes[index].next = freeList; nodes[index].height = NULL_NODE; // Put it back on the free list diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h index 70e53794..0337eedc 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -31,22 +31,16 @@ namespace SHADE /* Type Definit */ /*---------------------------------------------------------------------------------*/ - enum class Type : uint8_t - { - VERTEX = 0 - , FACE = 1 - }; - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ struct { - uint8_t indexA; - uint8_t indexB; - uint8_t typeA; - uint8_t typeB; + uint8_t inI; + uint8_t outI; + uint8_t inR; + uint8_t outR; }; uint32_t key = std::numeric_limits::max(); diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 980914c1..2a4503ce 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -82,6 +82,7 @@ namespace SHADE { int32_t halfEdgeA = -1; int32_t halfEdgeB = -1; + int32_t axis = -1; float bestDistance = std::numeric_limits::lowest(); }; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index be43af8f..97e9dbd4 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -48,7 +48,8 @@ namespace SHADE bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - static constexpr float TOLERANCE = 0.1f + SHPHYSICS_LINEAR_SLOP; + static constexpr float ABSOLUTE_TOLERANCE = 0.01f; + static constexpr float RELATIVE_TOLERANCE = 0.95f; const SHConvexPolyhedron& POLY_A = dynamic_cast(A); const SHConvexPolyhedron& POLY_B = dynamic_cast(B); @@ -72,7 +73,7 @@ namespace SHADE const SHConvexPolyhedron* incidentPoly = nullptr; FaceQuery minFaceQuery; - if (FACE_QUERY_A.bestDistance + TOLERANCE > FACE_QUERY_B.bestDistance) + if (FACE_QUERY_A.bestDistance + ABSOLUTE_TOLERANCE > FACE_QUERY_B.bestDistance * RELATIVE_TOLERANCE) { minFaceQuery = FACE_QUERY_A; referencePoly = &POLY_A; @@ -91,7 +92,7 @@ namespace SHADE // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on // each edge and use that as the contact point. - if (EDGE_QUERY.bestDistance > minFaceQuery.bestDistance + TOLERANCE) + if (EDGE_QUERY.bestDistance * RELATIVE_TOLERANCE > minFaceQuery.bestDistance + ABSOLUTE_TOLERANCE) { const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); @@ -111,13 +112,9 @@ namespace SHADE // In this scenario, we only have one contact SHContact contact; - contact.featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - contact.featurePair.indexA = HALF_EDGE_A.tailVertexIndex; - contact.featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - contact.featurePair.indexB = HALF_EDGE_B.tailVertexIndex; - - contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); - contact.penetration = EDGE_QUERY.bestDistance; + contact.featurePair.key = EDGE_QUERY.axis; + contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); + contact.penetration = EDGE_QUERY.bestDistance; manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; @@ -188,6 +185,7 @@ namespace SHADE const int32_t EDGE_COUNT_A = A.GetHalfEdgeCount(); const int32_t EDGE_COUNT_B = B.GetHalfEdgeCount(); + int32_t axis = -1; for (int32_t i = 0; i < EDGE_COUNT_A; i += 2) { for (int32_t j = 0; j < EDGE_COUNT_B; j += 2) @@ -196,12 +194,15 @@ namespace SHADE if (!IS_MINKOWSKI_FACE) continue; + ++axis; + const float SEPARATION = distanceBetweenEdges(A, B, i, j); if (SEPARATION > edgeQuery.bestDistance) { edgeQuery.bestDistance = SEPARATION; edgeQuery.halfEdgeA = i; edgeQuery.halfEdgeB = j; + edgeQuery.axis = axis; } } } @@ -321,10 +322,10 @@ namespace SHADE * R = (c1a2 / a1 - c2) / ( b2 - a2b1/a1 ) */ - const float A2_OVER_A1 = VB_DOT_VB / VB_DOT_VA; + const float A2_OVER_A1 = VB_DOT_VA == 0.0f ? 0.0f : VB_DOT_VB / VB_DOT_VA; const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB; const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; - const float R = NUMERATOR / DENOMINATOR; + const float R = DENOMINATOR == 0.0f ? NUMERATOR : NUMERATOR / DENOMINATOR; // Just take a point from A since it's A -> B return TAIL_A + R * VA; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index e6a961e0..07466ab1 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -179,7 +179,13 @@ namespace SHADE bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - return SphereVsConvex(manifold, B, A); + if (SphereVsConvex(manifold, B, A)) + { + manifold.normal = -manifold.normal; + return true; + }; + + return false; } /*-----------------------------------------------------------------------------------*/ @@ -326,7 +332,13 @@ namespace SHADE // Face to vertex is in the opposite direction of any tangent. const float PROJECTION = SHVec3::Dot(FACE_TO_CENTER, tangent1); if (PROJECTION < 0) + { + const float DISTANCE_SQUARED = SHVec3::DistanceSquared(faceVertex, CENTER); + if (DISTANCE_SQUARED > RADIUS * RADIUS) + return 0; + return 3; + } // Belongs in region D by default return 4; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 34e3dabf..ade7b482 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -238,6 +238,8 @@ namespace SHADE void SHContactManager::updateManifold(SHManifold& manifold, const SHManifold& oldManifold) noexcept { + static const float SQRT_ONE_THIRD = std::sqrtf(1.0f / 3.0f); + // Early out since exiting a collision does not require an update beyond updating the state if (manifold.state == SHCollisionState::EXIT) return; @@ -250,7 +252,7 @@ namespace SHADE const SHVec3& OLD_TANGENT_1 = oldManifold.tangents[1]; // Compute tangents - if (std::fabs(NORMAL.x) >= SHMath::EULER_CONSTANT) + if (std::fabs(NORMAL.x) >= SQRT_ONE_THIRD) tangent0 = SHVec3{ NORMAL.y, -NORMAL.x, 0.0f }; else tangent0 = SHVec3{ 0.0f, NORMAL.z, -NORMAL.y }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index fa6f1266..b5d7c2cc 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -187,14 +187,7 @@ namespace SHADE * restituion bias = restitution * (relative velocity /dot normal) */ - const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA); - const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); - const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); - const float ERROR_BIAS = SHPHYSICS_BAUMGARTE * INV_DT * std::min(0.0f, -contact.penetration + SHPHYSICS_LINEAR_SLOP); - const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f; - - contact.bias = ERROR_BIAS + RESTITUTION_BIAS; // Warm starting // Compute impulses @@ -208,6 +201,14 @@ namespace SHADE vB += impulse * constraint.invMassB * LINEAR_LOCK_B; wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse) * ANGULAR_LOCK_B; + + const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA); + const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); + const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); + + const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f; + + contact.bias = ERROR_BIAS + RESTITUTION_BIAS; } velocityStateA.LinearVelocity = vA; diff --git a/SHADE_Engine/src/Physics/SHPhysicsConstants.h b/SHADE_Engine/src/Physics/SHPhysicsConstants.h index 0d8f6fc8..a6cbd608 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsConstants.h +++ b/SHADE_Engine/src/Physics/SHPhysicsConstants.h @@ -26,7 +26,7 @@ namespace SHADE * @brief * Linear Collision & Constraint tolerance. */ - static constexpr float SHPHYSICS_LINEAR_SLOP = 0.005f * SHPHYSICS_LENGTHS_PER_UNIT_METER; + static constexpr float SHPHYSICS_LINEAR_SLOP = 0.05f * SHPHYSICS_LENGTHS_PER_UNIT_METER; /** * @brief -- 2.40.1 From ef5016351b2e10e37a51361b32426b2855499006 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 13 Jan 2023 15:18:35 +0800 Subject: [PATCH 74/84] Reverted changes to inertia tensors Created a new branch since I reverted to an older commit but kept some new updates. This will be the main branch moving forward. --- Assets/Scenes/PhysicsSandbox.shade | 19 ++++---------- .../Broadphase/SHDynamicAABBTree.cpp | 2 +- .../Physics/Collision/Contacts/SHContact.h | 14 +++-------- .../Collision/Narrowphase/SHCollision.h | 1 + .../Narrowphase/SHConvexVsConvex.cpp | 25 ++++++++++--------- .../Narrowphase/SHSphereVsConvex.cpp | 14 ++++++++++- .../src/Physics/Dynamics/SHContactManager.cpp | 4 ++- .../src/Physics/Dynamics/SHContactSolver.cpp | 15 +++++------ SHADE_Engine/src/Physics/SHPhysicsConstants.h | 2 +- 9 files changed, 49 insertions(+), 47 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index d30c8f07..6d15850b 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,9 +45,9 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: -0.5, y: 10, z: -3} + Position: {x: 0, y: 0, z: 7} Pitch: 0 - Yaw: 180 + Yaw: 0 Roll: 0 Width: 1920 Height: 1080 @@ -71,7 +71,7 @@ Auto Mass: false Mass: 10 Drag: 0.00999999978 - Angular Drag: 0.00999999978 + Angular Drag: 0 Use Gravity: true Gravity Scale: 1 Interpolate: true @@ -95,15 +95,6 @@ Density: 1 Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} - - Is Trigger: true - Collision Tag: 1 - Type: Sphere - Radius: 0.5 - Friction: 0.400000006 - Bounciness: 0 - Density: 1 - Position Offset: {x: 0.75, y: 0.5, z: 0} - Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true Scripts: - Type: PhysicsTestObj @@ -280,7 +271,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0.524352431, y: 13.5, z: 0.0463808179} + Translate: {x: 1, y: 2, z: 3} Rotate: {x: -0, y: 0.785398066, z: 0.785398185} Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} IsActive: true @@ -321,7 +312,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -0.5, y: 10, z: 0} + Translate: {x: 0, y: 0, z: 3} Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp index dc87d706..7177e517 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp @@ -337,7 +337,7 @@ namespace SHADE { SHASSERT(index >= 0 && index < capacity, "Trying to free an invalid AABB Tree node!") - nodes[index].next = NULL_NODE; + nodes[index].next = freeList; nodes[index].height = NULL_NODE; // Put it back on the free list diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h index 70e53794..0337eedc 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -31,22 +31,16 @@ namespace SHADE /* Type Definit */ /*---------------------------------------------------------------------------------*/ - enum class Type : uint8_t - { - VERTEX = 0 - , FACE = 1 - }; - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ struct { - uint8_t indexA; - uint8_t indexB; - uint8_t typeA; - uint8_t typeB; + uint8_t inI; + uint8_t outI; + uint8_t inR; + uint8_t outR; }; uint32_t key = std::numeric_limits::max(); diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 980914c1..2a4503ce 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -82,6 +82,7 @@ namespace SHADE { int32_t halfEdgeA = -1; int32_t halfEdgeB = -1; + int32_t axis = -1; float bestDistance = std::numeric_limits::lowest(); }; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index be43af8f..97e9dbd4 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -48,7 +48,8 @@ namespace SHADE bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - static constexpr float TOLERANCE = 0.1f + SHPHYSICS_LINEAR_SLOP; + static constexpr float ABSOLUTE_TOLERANCE = 0.01f; + static constexpr float RELATIVE_TOLERANCE = 0.95f; const SHConvexPolyhedron& POLY_A = dynamic_cast(A); const SHConvexPolyhedron& POLY_B = dynamic_cast(B); @@ -72,7 +73,7 @@ namespace SHADE const SHConvexPolyhedron* incidentPoly = nullptr; FaceQuery minFaceQuery; - if (FACE_QUERY_A.bestDistance + TOLERANCE > FACE_QUERY_B.bestDistance) + if (FACE_QUERY_A.bestDistance + ABSOLUTE_TOLERANCE > FACE_QUERY_B.bestDistance * RELATIVE_TOLERANCE) { minFaceQuery = FACE_QUERY_A; referencePoly = &POLY_A; @@ -91,7 +92,7 @@ namespace SHADE // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on // each edge and use that as the contact point. - if (EDGE_QUERY.bestDistance > minFaceQuery.bestDistance + TOLERANCE) + if (EDGE_QUERY.bestDistance * RELATIVE_TOLERANCE > minFaceQuery.bestDistance + ABSOLUTE_TOLERANCE) { const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); @@ -111,13 +112,9 @@ namespace SHADE // In this scenario, we only have one contact SHContact contact; - contact.featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - contact.featurePair.indexA = HALF_EDGE_A.tailVertexIndex; - contact.featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); - contact.featurePair.indexB = HALF_EDGE_B.tailVertexIndex; - - contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); - contact.penetration = EDGE_QUERY.bestDistance; + contact.featurePair.key = EDGE_QUERY.axis; + contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); + contact.penetration = EDGE_QUERY.bestDistance; manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; @@ -188,6 +185,7 @@ namespace SHADE const int32_t EDGE_COUNT_A = A.GetHalfEdgeCount(); const int32_t EDGE_COUNT_B = B.GetHalfEdgeCount(); + int32_t axis = -1; for (int32_t i = 0; i < EDGE_COUNT_A; i += 2) { for (int32_t j = 0; j < EDGE_COUNT_B; j += 2) @@ -196,12 +194,15 @@ namespace SHADE if (!IS_MINKOWSKI_FACE) continue; + ++axis; + const float SEPARATION = distanceBetweenEdges(A, B, i, j); if (SEPARATION > edgeQuery.bestDistance) { edgeQuery.bestDistance = SEPARATION; edgeQuery.halfEdgeA = i; edgeQuery.halfEdgeB = j; + edgeQuery.axis = axis; } } } @@ -321,10 +322,10 @@ namespace SHADE * R = (c1a2 / a1 - c2) / ( b2 - a2b1/a1 ) */ - const float A2_OVER_A1 = VB_DOT_VB / VB_DOT_VA; + const float A2_OVER_A1 = VB_DOT_VA == 0.0f ? 0.0f : VB_DOT_VB / VB_DOT_VA; const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB; const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; - const float R = NUMERATOR / DENOMINATOR; + const float R = DENOMINATOR == 0.0f ? NUMERATOR : NUMERATOR / DENOMINATOR; // Just take a point from A since it's A -> B return TAIL_A + R * VA; diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp index e6a961e0..07466ab1 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp @@ -179,7 +179,13 @@ namespace SHADE bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - return SphereVsConvex(manifold, B, A); + if (SphereVsConvex(manifold, B, A)) + { + manifold.normal = -manifold.normal; + return true; + }; + + return false; } /*-----------------------------------------------------------------------------------*/ @@ -326,7 +332,13 @@ namespace SHADE // Face to vertex is in the opposite direction of any tangent. const float PROJECTION = SHVec3::Dot(FACE_TO_CENTER, tangent1); if (PROJECTION < 0) + { + const float DISTANCE_SQUARED = SHVec3::DistanceSquared(faceVertex, CENTER); + if (DISTANCE_SQUARED > RADIUS * RADIUS) + return 0; + return 3; + } // Belongs in region D by default return 4; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index 34e3dabf..ade7b482 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -238,6 +238,8 @@ namespace SHADE void SHContactManager::updateManifold(SHManifold& manifold, const SHManifold& oldManifold) noexcept { + static const float SQRT_ONE_THIRD = std::sqrtf(1.0f / 3.0f); + // Early out since exiting a collision does not require an update beyond updating the state if (manifold.state == SHCollisionState::EXIT) return; @@ -250,7 +252,7 @@ namespace SHADE const SHVec3& OLD_TANGENT_1 = oldManifold.tangents[1]; // Compute tangents - if (std::fabs(NORMAL.x) >= SHMath::EULER_CONSTANT) + if (std::fabs(NORMAL.x) >= SQRT_ONE_THIRD) tangent0 = SHVec3{ NORMAL.y, -NORMAL.x, 0.0f }; else tangent0 = SHVec3{ 0.0f, NORMAL.z, -NORMAL.y }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index fa6f1266..b5d7c2cc 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -187,14 +187,7 @@ namespace SHADE * restituion bias = restitution * (relative velocity /dot normal) */ - const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA); - const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); - const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); - const float ERROR_BIAS = SHPHYSICS_BAUMGARTE * INV_DT * std::min(0.0f, -contact.penetration + SHPHYSICS_LINEAR_SLOP); - const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f; - - contact.bias = ERROR_BIAS + RESTITUTION_BIAS; // Warm starting // Compute impulses @@ -208,6 +201,14 @@ namespace SHADE vB += impulse * constraint.invMassB * LINEAR_LOCK_B; wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse) * ANGULAR_LOCK_B; + + const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA); + const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB); + const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal); + + const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f; + + contact.bias = ERROR_BIAS + RESTITUTION_BIAS; } velocityStateA.LinearVelocity = vA; diff --git a/SHADE_Engine/src/Physics/SHPhysicsConstants.h b/SHADE_Engine/src/Physics/SHPhysicsConstants.h index 0d8f6fc8..a6cbd608 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsConstants.h +++ b/SHADE_Engine/src/Physics/SHPhysicsConstants.h @@ -26,7 +26,7 @@ namespace SHADE * @brief * Linear Collision & Constraint tolerance. */ - static constexpr float SHPHYSICS_LINEAR_SLOP = 0.005f * SHPHYSICS_LENGTHS_PER_UNIT_METER; + static constexpr float SHPHYSICS_LINEAR_SLOP = 0.05f * SHPHYSICS_LENGTHS_PER_UNIT_METER; /** * @brief -- 2.40.1 From dab109bc771b950548087178194c1180cf739671 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 02:43:31 +0800 Subject: [PATCH 75/84] Fixed a fatal error with rigid body rotations. --- .../src/Physics/Dynamics/SHMotionState.cpp | 5 +- .../src/Physics/Dynamics/SHPhysicsWorld.cpp | 2 +- .../src/Physics/Dynamics/SHRigidBody.cpp | 13 +-- .../Routines/SHPhysicsPostUpdateRoutine.cpp | 82 ++++++++++--------- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp index cc014050..89c8ad32 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp @@ -109,10 +109,7 @@ namespace SHADE prevOrientation = orientation; - SHQuaternion qv{ velocity.x * dt, velocity.y * dt, velocity.z * dt, 0.0f }; - qv *= orientation; - - orientation += qv * 0.5f; + orientation += orientation * SHQuaternion{ velocity.x, velocity.y, velocity.z, 0.0f } * dt * 0.5f; orientation = SHQuaternion::Normalise(orientation); } diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 3595ec99..ed00e80e 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -142,7 +142,7 @@ namespace SHADE rigidBody.linearVelocity += (LINEAR_ACCELERATION + GRAVITATIONAL_ACCELERATION) * dt; // Integrate torque into angular velocity - rigidBody.angularVelocity += rigidBody.worldInvInertia * (rigidBody.accumulatedTorque * dt); + rigidBody.angularVelocity += rigidBody.worldInvInertia * rigidBody.accumulatedTorque * dt; // Apply drag (exponentially applied) rigidBody.linearVelocity *= 1.0f / (1.0f + dt * rigidBody.linearDrag); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index d76b79b8..1de9e543 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -637,16 +637,17 @@ namespace SHADE void SHRigidBody::ComputeWorldData() noexcept { + const SHMatrix R = SHMatrix::Rotate(motionState.orientation); + const SHMatrix RT = SHMatrix::Transpose(R); + + // Compute world centroid + worldCentroid = (R * localCentroid) + motionState.position; + if (bodyType == Type::STATIC) return; - const SHMatrix ROTATION = SHMatrix::Rotate(motionState.orientation); - // Compute world inertia - worldInvInertia = SHMatrix::Transpose(ROTATION) * localInvInertia * ROTATION; - - // Compute world centroid - worldCentroid = (ROTATION * localCentroid) + motionState.position; + worldInvInertia = R * (localInvInertia * RT); } void SHRigidBody::ComputeMassData() noexcept diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 5b0e5563..a08b943b 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -19,7 +19,6 @@ #include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -48,50 +47,55 @@ namespace SHADE // Interpolate transforms for rendering. // Only rigid bodies can move due to physics, so we run through the rigid body component dense set. - const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); - for (auto& rigidBodyComponent : RIGIDBODY_DENSE) + if (physicsSystem->worldUpdated) { - const EntityID EID = rigidBodyComponent.GetEID(); - - // Skip missing transforms - auto* transformComponent = SHComponentManager::GetComponent_s(EID); - if (!transformComponent) - continue; - - // Skip invalid bodies (Should not occur) - if (!rigidBodyComponent.rigidBody) - continue; - - // Skip inactive bodies - const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); - if (!IS_ACTIVE) - continue; - - const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); - - // Skip objects that have not moved - if (!MOTION_STATE) - continue; - - if (rigidBodyComponent.IsInterpolating()) + const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); + for (auto& rigidBodyComponent : RIGIDBODY_DENSE) { - const SHVec3 RENDER_POSITION = MOTION_STATE.InterpolatePositions(FACTOR); - const SHQuaternion RENDER_ORIENTATION = MOTION_STATE.InterpolateOrientations(FACTOR); + const EntityID EID = rigidBodyComponent.GetEID(); - transformComponent->SetWorldPosition(RENDER_POSITION); - transformComponent->SetWorldOrientation(RENDER_ORIENTATION); - } - else - { - transformComponent->SetWorldPosition(MOTION_STATE.position); - transformComponent->SetWorldOrientation(MOTION_STATE.orientation); - } + // Skip missing transforms + auto* transformComponent = SHComponentManager::GetComponent_s(EID); + if (!transformComponent) + continue; - /* - * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. - */ + // Skip invalid bodies (Should not occur) + if (!rigidBodyComponent.rigidBody) + continue; + + // Skip inactive bodies + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); + if (!IS_ACTIVE) + continue; + + const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); + + // Skip objects that have not moved + if (!MOTION_STATE) + continue; + + if (rigidBodyComponent.IsInterpolating()) + { + const SHVec3 RENDER_POSITION = MOTION_STATE.InterpolatePositions(FACTOR); + const SHQuaternion RENDER_ORIENTATION = MOTION_STATE.InterpolateOrientations(FACTOR); + + transformComponent->SetWorldPosition(RENDER_POSITION); + transformComponent->SetWorldOrientation(RENDER_ORIENTATION); + } + else + { + transformComponent->SetWorldPosition(MOTION_STATE.position); + transformComponent->SetWorldOrientation(MOTION_STATE.orientation); + } + + /* + * TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy. + */ + } } + + // Collision & Trigger messages if (scriptingSystem != nullptr) scriptingSystem->ExecuteCollisionFunctions(); -- 2.40.1 From 19bffc91247f92774083390d1e318179972cadb8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 02:44:27 +0800 Subject: [PATCH 76/84] First half of re-implementing face-face contact derivation --- Assets/Scenes/PhysicsSandbox.shade | 32 ++-- SHADE_Engine/src/Math/SHMathHelpers.h | 2 +- .../Physics/Collision/Contacts/SHContact.h | 12 +- .../Collision/Narrowphase/SHCollision.h | 40 ++--- .../Narrowphase/SHConvexVsConvex.cpp | 149 ++++++++++++++++-- .../src/Physics/Dynamics/SHContactSolver.cpp | 52 +++--- SHADE_Engine/src/Physics/SHPhysicsConstants.h | 2 +- 7 files changed, 202 insertions(+), 87 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 6d15850b..c9104ab3 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,7 +45,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 0, z: 7} + Position: {x: 0, y: 2, z: 7} Pitch: 0 Yaw: 0 Roll: 0 @@ -62,14 +62,14 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.45715916, y: 7.37748241, z: 0.227711335} - Rotate: {x: -0, y: 0, z: -0} + Translate: {x: -1.5, y: 7.5, z: 0} + Rotate: {x: -0, y: 0, z: 0.785398185} Scale: {x: 1, y: 1, z: 1} IsActive: true RigidBody Component: Type: Dynamic Auto Mass: false - Mass: 10 + Mass: 0.52359879 Drag: 0.00999999978 Angular Drag: 0 Use Gravity: true @@ -84,7 +84,7 @@ Freeze Rotation Z: false IsActive: true Collider Component: - DrawColliders: true + DrawColliders: false Colliders: - Is Trigger: false Collision Tag: 1 @@ -96,18 +96,14 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: - - Type: PhysicsTestObj - Enabled: true - forceAmount: 50 - torqueAmount: 500 + Scripts: ~ - EID: 2 Name: Default IsActive: true NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 4.09544182, z: 0} + Translate: {x: 0, y: 4, z: 0} Rotate: {x: -0, y: 0, z: -0.436332315} Scale: {x: 4.61071014, y: 0.999995887, z: 1} IsActive: true @@ -272,17 +268,17 @@ Components: Transform Component: Translate: {x: 1, y: 2, z: 3} - Rotate: {x: -0, y: 0.785398066, z: 0.785398185} - Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} + Rotate: {x: 0, y: 0.785398185, z: 0.785397708} + Scale: {x: 0.999990404, y: 0.999994516, z: 0.999985456} IsActive: true RigidBody Component: Type: Dynamic Auto Mass: false Mass: 1 Drag: 0.00999999978 - Angular Drag: 0.00999999978 + Angular Drag: 0 Use Gravity: true - Gravity Scale: 0.5 + Gravity Scale: 1 Interpolate: true Sleeping Enabled: true Freeze Position X: false @@ -305,7 +301,11 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true - Scripts: ~ + Scripts: + - Type: PhysicsTestObj + Enabled: true + forceAmount: 50 + torqueAmount: 5 - EID: 8 Name: Default IsActive: true diff --git a/SHADE_Engine/src/Math/SHMathHelpers.h b/SHADE_Engine/src/Math/SHMathHelpers.h index b053beff..1d65eb91 100644 --- a/SHADE_Engine/src/Math/SHMathHelpers.h +++ b/SHADE_Engine/src/Math/SHMathHelpers.h @@ -46,7 +46,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /** Standard Epsilon value for comparing Single-Precision Floating-Point values. */ - static constexpr float EPSILON = 0.001f; + static constexpr float EPSILON = 0.0001f; /** Single-Precision Floating-Point value of infinity */ static constexpr float INF = std::numeric_limits::infinity(); diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h index 0337eedc..bacf2255 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h @@ -27,20 +27,16 @@ namespace SHADE union SHContactFeatures { public: - /*---------------------------------------------------------------------------------*/ - /* Type Definit */ - /*---------------------------------------------------------------------------------*/ - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ struct { - uint8_t inI; - uint8_t outI; - uint8_t inR; - uint8_t outR; + uint8_t inI; // Incoming Incident Edge + uint8_t outI; // Outgoing Incident Edge + uint8_t inR; // Incoming Reference Edge + uint8_t outR; // Outgoing Reference Edge }; uint32_t key = std::numeric_limits::max(); diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 2a4503ce..8012392b 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -11,6 +11,7 @@ #pragma once // Project Headers +#include "Math/Geometry/SHPlane.h" #include "Physics/Collision/Contacts/SHManifold.h" #include "Physics/Collision/Contacts/SHCollisionKey.h" #include "Physics/Collision/Shapes/SHHalfEdgeStructure.h" @@ -86,15 +87,21 @@ namespace SHADE float bestDistance = std::numeric_limits::lowest(); }; + struct ClipVertex + { + SHVec3 position; + SHContactFeatures featurePair; + }; + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ // Sphere VS Convex - static FaceQuery findClosestFace (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron) noexcept; - static int32_t findClosestPoint (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron, int32_t faceIndex) noexcept; - static int32_t findVoronoiRegion (const SHSphere& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; + static FaceQuery findClosestFace (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron) noexcept; + static int32_t findClosestPoint (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron, int32_t faceIndex) noexcept; + static int32_t findVoronoiRegion (const SHSphere& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; // Capsule VS Convex @@ -102,29 +109,22 @@ namespace SHADE // Convex VS Convex - static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - - static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; - static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; - /* - * TODO: - * - * - * - * - * - * static uint32_t clip [sutherland-hodgemann clipping] - * * ! References * https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf * https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp */ + static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + + static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; + static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; + static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; + static std::vector clipPolygonWithPlane (const std::vector& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept; + static std::vector reduceContacts (const std::vector& in) noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 97e9dbd4..52cc2c81 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -54,6 +54,8 @@ namespace SHADE const SHConvexPolyhedron& POLY_A = dynamic_cast(A); const SHConvexPolyhedron& POLY_B = dynamic_cast(B); + // TODO: Check against cached separating axis. + const FaceQuery FACE_QUERY_A = queryFaceDirections(POLY_A, POLY_B); if (FACE_QUERY_A.bestDistance > 0.0f) return false; @@ -78,6 +80,7 @@ namespace SHADE minFaceQuery = FACE_QUERY_A; referencePoly = &POLY_A; incidentPoly = &POLY_B; + flipNormal = false; } else { @@ -114,7 +117,7 @@ namespace SHADE SHContact contact; contact.featurePair.key = EDGE_QUERY.axis; contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); - contact.penetration = EDGE_QUERY.bestDistance; + contact.penetration = -EDGE_QUERY.bestDistance; manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; @@ -125,23 +128,67 @@ namespace SHADE const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace); const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL); + const SHHalfEdgeStructure::Face& INCIDENT_FACE = incidentPoly->GetFace(INCIDENT_FACE_IDX); + const SHHalfEdgeStructure::Face& REFERENCE_FACE = referencePoly->GetFace(minFaceQuery.closestFace); - /* - * TODO: - * - * !! - * 4. From above, save the axis of minimum penetration (reference face) - * 5. Find the most anti-parallel face on other shape (incident face) - * 6. Clip incident face against side planes of reference face. (Sutherland-Hodgeman Clipping). - * Keep all vertices below reference face. - * 7. Reduce manifold to 4 contact points. We only need 4 contact points for a stable manifold. - * - * Remember to save IDs in queries. - * During generation of incident face, store IDs of face. - * - */ + const int32_t NUM_INCIDENT_VERTICES = static_cast(INCIDENT_FACE.vertexIndices.size()); + const int32_t NUM_REFERENCE_VERTICES = static_cast(REFERENCE_FACE.vertexIndices.size()); + // Build incoming vertices to clip + std::vector clipIn; + clipIn.resize(NUM_INCIDENT_VERTICES * 2, ClipVertex{}); + int32_t numClipIn = 0; + for (int32_t i = 0; i < NUM_INCIDENT_VERTICES; ++i) + { + const int32_t prevI = i - 1 < 0 ? NUM_INCIDENT_VERTICES - 1 : i - 1; + + const int32_t V_INDEX = INCIDENT_FACE.vertexIndices[i].index; + + // The incoming id is the previous edge + // The outgoing id is the current edge (where this vertex is the tail of) + + ClipVertex v; + v.position = incidentPoly->GetVertex(V_INDEX); + v.featurePair.inI = INCIDENT_FACE.vertexIndices[prevI].edgeIndex; + v.featurePair.outI = INCIDENT_FACE.vertexIndices[i].edgeIndex; + v.featurePair.inR = 0; + v.featurePair.outR = 0; + + clipIn[numClipIn++] = v; + } + + // Clip the vertices against the reference face side planes. + // Number of side planes == number of edges == number of vertices + for (int32_t i = 0; i < NUM_REFERENCE_VERTICES; ++i) + { + // Side plane can be built with the vertex on the edge and the plane's normal + // Plane normal = faceNormal X tangent (v2 - v1) + + const int32_t V1_INDEX = REFERENCE_FACE.vertexIndices[i].index; + const int32_t V2_INDEX = REFERENCE_FACE.vertexIndices[(i + 1) % NUM_REFERENCE_VERTICES].index; + + const SHVec3 V1 = referencePoly->GetVertex(V1_INDEX); + const SHVec3 V2 = referencePoly->GetVertex(V2_INDEX); + + const SHVec3 TANGENT = SHVec3::Normalise(V2 - V1); + const SHPlane CLIP_PLANE { V1, SHVec3::Cross(REFERENCE_NORMAL, TANGENT) }; + + std::vector clipOut = clipPolygonWithPlane(clipIn, numClipIn, CLIP_PLANE, REFERENCE_FACE.vertexIndices[i].edgeIndex); + if (clipOut.empty()) + return false; + + // Replace the clip container's contents with the clipped points for the next clipping pass + const int32_t NUM_CLIPPED = static_cast(clipOut.size()); + for (int32_t clippedIndex = 0; clippedIndex < NUM_CLIPPED; ++clippedIndex) + { + clipIn[clippedIndex].position = clipOut[clippedIndex].position; + clipIn[clippedIndex].featurePair.key = clipOut[clippedIndex].featurePair.key; + } + numClipIn = NUM_CLIPPED; + } + + // From the final set of clipped points, only keep the points that are below the reference plane. return false; } @@ -353,5 +400,77 @@ namespace SHADE return bestFace; } + std::vector SHCollision::clipPolygonWithPlane(const std::vector& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept + { + std::vector out; + + int32_t v1Index = numIn - 1; + int32_t v2Index = 0; + + float v1Distance = plane.SignedDistance(in[v1Index].position); + float v2Distance = 0.0f; + + for (int32_t i = 0; i < numIn; ++i) + { + v2Index = i; + + const SHVec3 v1Pos = in[v1Index].position; + const SHVec3 v2Pos = in[v2Index].position; + + v2Distance = plane.SignedDistance(v2Pos); + + // v1 in front, v2 behind + // keep the intersection point + if (v1Distance >= 0.0f && v2Distance < 0.0f) + { + ClipVertex intersection; + + // In case the edge is parallel, the intersection is just the start point + const bool IS_PARALLEL = SHMath::CompareFloat(SHVec3::Dot(v2Pos - v1Pos, plane.GetNormal()), 0.0f); + const float ALPHA = IS_PARALLEL ? 0.0f : v1Distance / SHVec3::Distance(v1Pos, v2Pos); + + intersection.position = SHVec3::ClampedLerp(v1Pos, v2Pos, ALPHA); + intersection.featurePair.inI = in[v1Index].featurePair.outI; + intersection.featurePair.outI = 0; + intersection.featurePair.inR = 0; + intersection.featurePair.outR = planeIdx; + + out.emplace_back(intersection); + } + + // v1 behind, v2 in front + // keep intersection point & v2 + if(v1Distance < 0.0f && v2Distance >= 0.0f) + { + ClipVertex intersection; + + // In case the edge is parallel, the intersection is just the start point + const bool IS_PARALLEL = SHMath::CompareFloat(SHVec3::Dot(v2Pos - v1Pos, plane.GetNormal()), 0.0f); + const float ALPHA = IS_PARALLEL ? 0.0f : -v1Distance / SHVec3::Distance(v1Pos, v2Pos); + + intersection.position = SHVec3::ClampedLerp(v1Pos, v2Pos, ALPHA); + intersection.featurePair.inI = 0; + intersection.featurePair.outI = in[v2Index].featurePair.inI; + intersection.featurePair.inR = planeIdx; + intersection.featurePair.outR = 0; + + out.emplace_back(intersection); + out.emplace_back(in[v2Index]); + } + + // both in front, keep v2 + if (v1Distance >= 0.0f && v2Distance >= 0.0f) + { + out.emplace_back(in[v2Index]); + } + + // v2 is the next v1 + v1Index = v2Index; + v1Distance = v2Distance; + } + + return out; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index b5d7c2cc..926e1fed 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -187,7 +187,7 @@ namespace SHADE * restituion bias = restitution * (relative velocity /dot normal) */ - const float ERROR_BIAS = SHPHYSICS_BAUMGARTE * INV_DT * std::min(0.0f, -contact.penetration + SHPHYSICS_LINEAR_SLOP); + const float ERROR_BIAS = -SHPHYSICS_BAUMGARTE * INV_DT * std::max(0.0f, contact.penetration - SHPHYSICS_LINEAR_SLOP); // Warm starting // Compute impulses @@ -244,6 +244,31 @@ namespace SHADE SHVec3 velocityB = vB + SHVec3::Cross(wB, contact.rB); SHVec3 relativeVelocity = velocityB - velocityA; + // Get scalar of relative velocity along the normal + const float VN = SHVec3::Dot(relativeVelocity, constraint.normal); + + // Compute true normal impulse + const float OLD_NORMAL_IMPULSE = contact.normalImpulse; + + float newNormalImpulse = -(VN + contact.bias) * contact.normalMass; + contact.normalImpulse = std::max(OLD_NORMAL_IMPULSE + newNormalImpulse, 0.0f); + newNormalImpulse = contact.normalImpulse - OLD_NORMAL_IMPULSE; + + const SHVec3 NORMAL_IMPULSE = newNormalImpulse * constraint.normal; + + // Apply impulses + vA -= NORMAL_IMPULSE * constraint.invMassA * LINEAR_LOCK_A; + wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE) * ANGULAR_LOCK_A; + + vB += NORMAL_IMPULSE * constraint.invMassB * LINEAR_LOCK_B; + wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE) * ANGULAR_LOCK_B; + + // Solve normal impulse + // Re-compute relative velocity + velocityA = vA + SHVec3::Cross(wA, contact.rA); + velocityB = vB + SHVec3::Cross(wB, contact.rB); + relativeVelocity = velocityB - velocityA; + // Solve tangent impulse for (int j = 0; j < SHContact::NUM_TANGENTS; ++j) { @@ -269,31 +294,6 @@ namespace SHADE vB += TANGENT_IMPULSE * constraint.invMassB * LINEAR_LOCK_B; wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE) * ANGULAR_LOCK_B; } - - // Solve normal impulse - // Re-compute relative velocity - velocityA = vA + SHVec3::Cross(wA, contact.rA); - velocityB = vB + SHVec3::Cross(wB, contact.rB); - relativeVelocity = velocityB - velocityA; - - // Get scalar of relative velocity along the normal - const float VN = SHVec3::Dot(relativeVelocity, constraint.normal); - - // Compute true normal impulse - const float OLD_NORMAL_IMPULSE = contact.normalImpulse; - - float newNormalImpulse = -(VN + contact.bias) * contact.normalMass; - contact.normalImpulse = std::max(OLD_NORMAL_IMPULSE + newNormalImpulse, 0.0f); - newNormalImpulse = contact.normalImpulse - OLD_NORMAL_IMPULSE; - - const SHVec3 NORMAL_IMPULSE = newNormalImpulse * constraint.normal; - - // Apply impulses - vA -= NORMAL_IMPULSE * constraint.invMassA * LINEAR_LOCK_A; - wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE) * ANGULAR_LOCK_A; - - vB += NORMAL_IMPULSE * constraint.invMassB * LINEAR_LOCK_B; - wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE) * ANGULAR_LOCK_B; } velocityStateA.LinearVelocity = vA; diff --git a/SHADE_Engine/src/Physics/SHPhysicsConstants.h b/SHADE_Engine/src/Physics/SHPhysicsConstants.h index a6cbd608..f252fce5 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsConstants.h +++ b/SHADE_Engine/src/Physics/SHPhysicsConstants.h @@ -26,7 +26,7 @@ namespace SHADE * @brief * Linear Collision & Constraint tolerance. */ - static constexpr float SHPHYSICS_LINEAR_SLOP = 0.05f * SHPHYSICS_LENGTHS_PER_UNIT_METER; + static constexpr float SHPHYSICS_LINEAR_SLOP = 0.01f * SHPHYSICS_LENGTHS_PER_UNIT_METER; /** * @brief -- 2.40.1 From 85f0902c2d7282baae7e7e6935223c6cd626ea46 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 03:48:08 +0800 Subject: [PATCH 77/84] Removed unused collision table and fixed bug with kinematic bodies exploding --- .../Narrowphase/SHCollisionDispatch.cpp | 21 ------------- .../Narrowphase/SHCollisionDispatch.h | 31 ------------------- .../src/Physics/Dynamics/SHRigidBody.cpp | 2 +- 3 files changed, 1 insertion(+), 53 deletions(-) diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp index e11902e0..075e113f 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp @@ -42,31 +42,10 @@ namespace SHADE , { SHCollision::CapsuleVsSphere, SHCollision::CapsuleVsConvex, SHCollision::CapsuleVsCapsule } // Capsule }; - const bool SHCollisionDispatcher::collisionTable[NUM_TYPES][NUM_TYPES] - { - /* S ST K KT D DT */ - /* S */ { false, false, false, true, true, true } - , /* ST */ { false, false, true, true, true, true } - , /* K */ { false, true, false, true, true, true } - , /* KT */ { true, true, true, true, true, true } - , /* D */ { true, true, true, true, true, true } - , /* DT */ { true, true, true, true, true, true } - }; - /*-----------------------------------------------------------------------------------*/ /* Public Member Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHCollisionDispatcher::ShouldCollide(const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - // Filter through collision table - const int TYPE_A = SHUtilities::ConvertEnum(A.GetType()) + A.IsTrigger() ? TYPE_OFFSET : 0; - const int TYPE_B = SHUtilities::ConvertEnum(B.GetType()) + B.IsTrigger() ? TYPE_OFFSET : 0; - - if (!collisionTable[TYPE_A][TYPE_B]) - return false; - } - bool SHCollisionDispatcher::Collide(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { const int TYPE_A = SHUtilities::ConvertEnum(A.GetType()); diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h index 2dea7f1d..1df84da0 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h @@ -31,18 +31,6 @@ namespace SHADE /* Member Functions */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Filters the collision through the collision table and layer matching. - * @param A - * A Collision Shape. - * @param B - * A Collision Shape. - * @return - * True if both shapes should be tested for collision. - */ - static bool ShouldCollide (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; - static bool Collide (SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept; static bool Collide (const SHCollisionShape& A, const SHCollisionShape& B) noexcept; @@ -54,33 +42,14 @@ namespace SHADE using ManifoldCollide = bool(*)(SHManifold&, const SHCollisionShape& A, const SHCollisionShape& B); using TriggerCollide = bool(*)(const SHCollisionShape& A, const SHCollisionShape& B); - enum class Types - { - STATIC - , KINEMATIC - , DYNAMIC - , STATIC_TRIGGER - , KINEMATIC_TRIGGER - , DYNAMIC_TRIGGER - - , COUNT - }; - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - // Read the Types enum class, then see where it's used and it'll make sense - static constexpr int TYPE_OFFSET = 3; - static constexpr int NUM_SHAPES = static_cast(SHCollisionShape::Type::COUNT); - static constexpr int NUM_TYPES = static_cast(Types::COUNT); static const ManifoldCollide manifoldCollide [NUM_SHAPES][NUM_SHAPES]; static const TriggerCollide triggerCollide [NUM_SHAPES][NUM_SHAPES]; - - static const bool collisionTable [NUM_TYPES][NUM_TYPES]; - }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp index 1de9e543..bdaaf230 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp @@ -643,7 +643,7 @@ namespace SHADE // Compute world centroid worldCentroid = (R * localCentroid) + motionState.position; - if (bodyType == Type::STATIC) + if (bodyType != Type::DYNAMIC) return; // Compute world inertia -- 2.40.1 From c077575a738eeab8b4a5b2e2ab7f845af81e8adf Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 15:01:14 +0800 Subject: [PATCH 78/84] Fixed convex-convex face detection Minor bugs with contact point detection. Will test more before pushing into main --- Assets/Scenes/PhysicsSandbox.shade | 6 +- .../Collision/Narrowphase/SHCollision.h | 2 +- .../Narrowphase/SHConvexVsConvex.cpp | 208 +++++++++++++++++- SHADE_Engine/src/Physics/SHPhysicsConstants.h | 12 +- 4 files changed, 220 insertions(+), 8 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index c9104ab3..0d2e4abe 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -267,9 +267,9 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 1, y: 2, z: 3} - Rotate: {x: 0, y: 0.785398185, z: 0.785397708} - Scale: {x: 0.999990404, y: 0.999994516, z: 0.999985456} + Translate: {x: 1.81218028, y: 2, z: 3} + Rotate: {x: 0.785398006, y: 0.785398483, z: 0.785398304} + Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true RigidBody Component: Type: Dynamic diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 8012392b..1ef75974 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -124,7 +124,7 @@ namespace SHADE static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; static std::vector clipPolygonWithPlane (const std::vector& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept; - static std::vector reduceContacts (const std::vector& in) noexcept; + static std::vector reduceContacts (const std::vector& in, const SHVec3& faceNormal) noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 52cc2c81..a59e8f28 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -189,8 +189,78 @@ namespace SHADE } // From the final set of clipped points, only keep the points that are below the reference plane. + const SHPlane REFERENCE_PLANE{ referencePoly->GetVertex(REFERENCE_FACE.vertexIndices.front().index), REFERENCE_NORMAL }; - return false; + std::vector contacts; + for (int32_t i = 0; i < numClipIn; ++i) + { + const SHVec3 POS = clipIn[i].position; + const float DIST = REFERENCE_PLANE.SignedDistance(POS); + if (DIST <= 0.0f) + { + SHContact contact; + contact.position = POS; + contact.penetration = -DIST; + + if (flipNormal) + { + contact.featurePair.inI = clipIn[i].featurePair.inR; + contact.featurePair.inR = clipIn[i].featurePair.inI; + contact.featurePair.outI = clipIn[i].featurePair.outR; + contact.featurePair.outR = clipIn[i].featurePair.outI; + } + else + { + contact.featurePair.key = clipIn[i].featurePair.key; + } + + contacts.emplace_back(contact); + ++numContacts; + } + } + + // Reduce contact manifold if more than 4 points + if (numContacts > 4) + { + const auto INDICES_TO_KEEP = reduceContacts(contacts, REFERENCE_NORMAL); + std::vector reducedContacts; + + const int32_t NUM_REDUCED = static_cast(INDICES_TO_KEEP.size()); + for (int32_t i = 0; i < NUM_REDUCED; ++i) + reducedContacts.emplace_back(contacts[INDICES_TO_KEEP[i]]); + + contacts.clear(); + // Copy contacts to main container + for (auto& contact : reducedContacts) + contacts.emplace_back(contact); + } + + // Remove potential duplicate contact points + // No way about this being an n^2 loop + static constexpr float THRESHOLD = SHPHYSICS_SAME_CONTACT_DISTANCE * SHPHYSICS_SAME_CONTACT_DISTANCE; + for (auto i = contacts.begin(); i != contacts.end(); ++i) + { + for (auto j = i + 1; j != contacts.end();) + { + const float D2 = SHVec3::DistanceSquared(i->position, j->position); + if (D2 < THRESHOLD) + j = contacts.erase(j); + else + ++j; + } + } + + // Copy final contacts into the manifold + numContacts = static_cast(contacts.size()); + for (int32_t i = 0; i < numContacts; ++i) + manifold.contacts[i] = contacts[i]; + + manifold.numContacts = numContacts; + manifold.normal = REFERENCE_NORMAL; + if (flipNormal) + manifold.normal = -manifold.normal; + + return true; } /*-----------------------------------------------------------------------------------*/ @@ -472,5 +542,141 @@ namespace SHADE return out; } + std::vector SHCollision::reduceContacts(const std::vector& in, const SHVec3& faceNormal) noexcept + { + std::vector indicesToKeep; + + // Use a map to temporarily store and track the contacts we want + std::unordered_map contactMap; + const int32_t NUM_CONTACTS = static_cast(in.size()); + for (int32_t i = 0; i < NUM_CONTACTS; ++i) + contactMap.emplace(i, &in[i]); + + // Find the furthest point in a given direction + int32_t indexToKeep = -1; + float bestDistance = std::numeric_limits::lowest(); + + for (const auto& [index, contact] : contactMap) + { + const float DIST = SHVec3::Dot(contact->position, SHVec3::One); + if (DIST > bestDistance) + { + bestDistance = DIST; + indexToKeep = index; + } + } + + indicesToKeep.emplace_back(indexToKeep); + contactMap.erase(indexToKeep); + + + indexToKeep = -1; + bestDistance = std::numeric_limits::lowest(); + + // Find point furthest away from the first index + const SHVec3& FIRST_POS = in[indicesToKeep.back()].position; + for (const auto& [index, contact] : contactMap) + { + const float DIST_SQUARED = SHVec3::DistanceSquared(FIRST_POS, contact->position); + if (DIST_SQUARED > bestDistance) + { + bestDistance = DIST_SQUARED; + indexToKeep = index; + } + } + + indicesToKeep.emplace_back(indexToKeep); + contactMap.erase(indexToKeep); + + indexToKeep = -1; + + // We compute the triangle with the largest area. + // The area can be positive or negative depending on the winding order. + + float maxArea = std::numeric_limits::lowest(); + float minArea = std::numeric_limits::max(); + + int32_t maxAreaIndex = -1; + int32_t minAreaIndex = -1; + + const SHVec3& SECOND_POS = in[indicesToKeep.back()].position; + for (const auto& [index, contact] : contactMap) + { + const SHVec3& POS = contact->position; + const SHVec3 TO_P1 = FIRST_POS - POS; + const SHVec3 TO_P2 = SECOND_POS - POS; + + const float AREA = SHVec3::Dot(SHVec3::Cross(TO_P1, TO_P2), faceNormal) * 0.5f; + + if (AREA > maxArea) + { + maxArea = AREA; + maxAreaIndex = index; + } + + if (AREA < minArea) + { + minArea = AREA; + minAreaIndex = index; + } + } + + // Compare which triangle creates the largest area + bool isAreaPositive = false; + if (maxArea > (-minArea)) + { + isAreaPositive = true; + indexToKeep = maxAreaIndex; + } + else + { + isAreaPositive = false; + indexToKeep = minAreaIndex; + } + + indicesToKeep.emplace_back(indexToKeep); + contactMap.erase(indexToKeep); + + indexToKeep = -1; + + // For the last point, we want the point which forms the largest area that is winded opposite to the first triangle + // The areas should be inverted: If area was -ve, we want a +ve. Otherwise, vice versa. + float bestArea = 0.0f; + + const SHVec3& THIRD_POS = in[indicesToKeep.back()].position; + const SHVec3 ABC[3] = { FIRST_POS, SECOND_POS, THIRD_POS }; + + for (const auto& [index, contact] : contactMap) + { + const SHVec3& Q = contact->position; + + for (int i = 0; i < 3; ++i) + { + const int P1 = i; + const int P2 = (i + 1) % 3; + + const SHVec3 TO_P1 = ABC[P1] - Q; + const SHVec3 TO_P2 = ABC[P2] - Q; + + const float AREA = SHVec3::Dot(SHVec3::Cross(TO_P1, TO_P2), faceNormal) * 0.5f; + + if (isAreaPositive && AREA < bestArea) + { + bestArea = AREA; + indexToKeep = index; + } + + if (!isAreaPositive && AREA > bestArea) + { + bestArea = AREA; + indexToKeep = index; + } + } + } + + indicesToKeep.emplace_back(indexToKeep); + return indicesToKeep; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsConstants.h b/SHADE_Engine/src/Physics/SHPhysicsConstants.h index f252fce5..b680515e 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsConstants.h +++ b/SHADE_Engine/src/Physics/SHPhysicsConstants.h @@ -34,11 +34,17 @@ namespace SHADE */ static constexpr float SHPHYSICS_RESTITUTION_THRESHOLD = 1.0f; - /** + /** * @brief * Scaling factor to control how fast overlaps are resolved.
* 1 is ideal for instant correction, but values close to 1 can lead to overshoot. - */ - static constexpr float SHPHYSICS_BAUMGARTE = 0.2f; + */ + static constexpr float SHPHYSICS_BAUMGARTE = 0.2f; + + /** + * @brief + * Distance threshold to consider two contacts as the same. + */ + static constexpr float SHPHYSICS_SAME_CONTACT_DISTANCE = 0.01; } -- 2.40.1 From 36e01260ec16474ac956091eeb48704a508a2248 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 16:23:48 +0800 Subject: [PATCH 79/84] Merge changes from main missing from previous commit --- Assets/Editor/Editor.SHConfig | 2 +- Assets/Scenes/PhysicsSandbox.shade | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Assets/Editor/Editor.SHConfig b/Assets/Editor/Editor.SHConfig index 51425027..b492a983 100644 --- a/Assets/Editor/Editor.SHConfig +++ b/Assets/Editor/Editor.SHConfig @@ -1,4 +1,4 @@ Start Maximized: true -Working Scene ID: 97161771 +Working Scene ID: 97402985 Window Size: {x: 1920, y: 1080} Style: 0 \ No newline at end of file diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 0d2e4abe..3144e959 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -62,7 +62,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1.5, y: 7.5, z: 0} + Translate: {x: 3, y: 7.5, z: 0} Rotate: {x: -0, y: 0, z: 0.785398185} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -267,8 +267,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 1.81218028, y: 2, z: 3} - Rotate: {x: 0.785398006, y: 0.785398483, z: 0.785398304} + Translate: {x: -1, y: 7, z: 0} + Rotate: {x: 0.785398185, y: 0.785398185, z: 0.785398185} Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true RigidBody Component: -- 2.40.1 From 1dc16fdcda0ec5becc71822d45ced957460b4fc9 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 22 Jan 2023 17:38:51 +0800 Subject: [PATCH 80/84] Fixed typos --- Assets/Scenes/PhysicsSandbox.shade | 24 +++++++++---------- .../src/Physics/Dynamics/SHPhysicsWorld.h | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 3144e959..ad77de0a 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -62,7 +62,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 3, y: 7.5, z: 0} + Translate: {x: -1, y: 7.5, z: 0} Rotate: {x: -0, y: 0, z: 0.785398185} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -77,11 +77,11 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false + Freeze Rotation X: true + Freeze Rotation Y: true + Freeze Rotation Z: true IsActive: true Collider Component: DrawColliders: false @@ -90,7 +90,7 @@ Collision Tag: 1 Type: Sphere Radius: 1 - Friction: 0.400000006 + Friction: 1 Bounciness: 0 Density: 1 Position Offset: {x: 0, y: 0, z: 0} @@ -131,7 +131,7 @@ Collision Tag: 2 Type: Box Half Extents: {x: 1, y: 1, z: 1} - Friction: 0.400000006 + Friction: 1 Bounciness: 0 Density: 1 Position Offset: {x: 0, y: 0, z: 0} @@ -144,9 +144,9 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: -1.74209237, z: 0} + Translate: {x: 0, y: -3, z: 0} Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 10, y: 0.5, z: 10} + Scale: {x: 10, y: 3, z: 10} IsActive: true RigidBody Component: Type: Static @@ -267,8 +267,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1, y: 7, z: 0} - Rotate: {x: 0.785398185, y: 0.785398185, z: 0.785398185} + Translate: {x: 2, y: 2, z: 3} + Rotate: {x: 0, y: 0, z: 0} Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true RigidBody Component: @@ -278,7 +278,7 @@ Drag: 0.00999999978 Angular Drag: 0 Use Gravity: true - Gravity Scale: 1 + Gravity Scale: 5 Interpolate: true Sleeping Enabled: true Freeze Position X: false diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index f63bac40..b171f206 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -108,7 +108,7 @@ namespace SHADE * Performs a single simulation step.
* Detect Collisions -> Integrate Forces -> Resolve Contacts -> Integrate Velocities * @param dt - * A discrete time step for the simulation. This should be consistent for deteministic + * A discrete time step for the simulation. This should be consistent for deterministic * behaviour. */ void Step (float dt); @@ -118,7 +118,7 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - // EntityIDs are used to map resolved contraints back to bodies + // EntityIDs are used to map resolved constraints back to bodies using RigidBodies = std::unordered_map; /*---------------------------------------------------------------------------------*/ -- 2.40.1 From 0c3106f15b9d770be1a2391655ecf63bcf404e36 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 22 Jan 2023 19:20:03 +0800 Subject: [PATCH 81/84] Abstracted contact derivation as setup for cached SAT --- Assets/Scenes/PhysicsSandbox.shade | 14 +- .../Collision/Narrowphase/SHCollision.h | 105 ++++++- .../Narrowphase/SHConvexVsConvex.cpp | 277 +++++++++--------- .../src/Physics/Dynamics/SHPhysicsWorld.h | 4 - 4 files changed, 243 insertions(+), 157 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index ad77de0a..8f439326 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -79,9 +79,9 @@ Freeze Position X: false Freeze Position Y: false Freeze Position Z: false - Freeze Rotation X: true - Freeze Rotation Y: true - Freeze Rotation Z: true + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false IsActive: true Collider Component: DrawColliders: false @@ -90,7 +90,7 @@ Collision Tag: 1 Type: Sphere Radius: 1 - Friction: 1 + Friction: 0.400000006 Bounciness: 0 Density: 1 Position Offset: {x: 0, y: 0, z: 0} @@ -131,7 +131,7 @@ Collision Tag: 2 Type: Box Half Extents: {x: 1, y: 1, z: 1} - Friction: 1 + Friction: 0.400000006 Bounciness: 0 Density: 1 Position Offset: {x: 0, y: 0, z: 0} @@ -268,7 +268,7 @@ Components: Transform Component: Translate: {x: 2, y: 2, z: 3} - Rotate: {x: 0, y: 0, z: 0} + Rotate: {x: 0.785398185, y: 0.785398185, z: 0.785398185} Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true RigidBody Component: @@ -278,7 +278,7 @@ Drag: 0.00999999978 Angular Drag: 0 Use Gravity: true - Gravity Scale: 5 + Gravity Scale: 1 Interpolate: true Sleeping Enabled: true Freeze Position X: false diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index 1ef75974..e78b33fa 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -99,9 +99,27 @@ namespace SHADE // Sphere VS Convex - static FaceQuery findClosestFace (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron) noexcept; - static int32_t findClosestPoint (const SHSphere& sphere, const SHConvexPolyhedron& polyhedron, int32_t faceIndex) noexcept; - static int32_t findVoronoiRegion (const SHSphere& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept; + static FaceQuery findClosestFace + ( + const SHSphere& sphere + , const SHConvexPolyhedron& polyhedron + ) noexcept; + + static int32_t findClosestPoint + ( + const SHSphere& sphere + , const SHConvexPolyhedron& polyhedron + , int32_t faceIndex + ) noexcept; + + static int32_t findVoronoiRegion + ( + const SHSphere& sphere + , const SHVec3& faceVertex + , const SHVec3& faceNormal + , const SHVec3& tangent1 + , const SHVec3& tangent2 + ) noexcept; // Capsule VS Convex @@ -115,16 +133,79 @@ namespace SHADE * https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp */ - static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; - static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept; + static FaceQuery queryFaceDirections + ( + const SHConvexPolyhedron& A + , const SHConvexPolyhedron& B + ) noexcept; - static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept; - static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept; - static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept; - static std::vector clipPolygonWithPlane (const std::vector& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept; - static std::vector reduceContacts (const std::vector& in, const SHVec3& faceNormal) noexcept; + static EdgeQuery queryEdgeDirections + ( + const SHConvexPolyhedron& A + , const SHConvexPolyhedron& B + ) noexcept; + + static bool buildMinkowskiFace + ( + const SHConvexPolyhedron& A + , const SHConvexPolyhedron& B + , int32_t edgeA + , int32_t edgeB + ) noexcept; + + static bool isMinkowskiFace + ( + const SHVec3& a + , const SHVec3& b + , const SHVec3& c + , const SHVec3& d + ) noexcept; + + static float distanceBetweenEdges + ( + const SHConvexPolyhedron& A + , const SHConvexPolyhedron& B + , int32_t edgeA + , int32_t edgeB + ) noexcept; + + static SHVec3 findClosestPointBetweenEdges + ( + const SHConvexPolyhedron& A + , const SHConvexPolyhedron& B + , int32_t edgeA + , int32_t edgeB + ) noexcept; + + static int32_t findIncidentFace + ( + const SHConvexPolyhedron& poly + , const SHVec3& normal + ) noexcept; + + static bool findFaceContacts + ( + SHManifold& manifold + , const SHConvexPolyhedron& incPoly + , int32_t incFace + , const SHConvexPolyhedron& refPoly + , int32_t refFace + , bool flip + ) noexcept; + + static std::vector clipPolygonWithPlane + ( + const std::vector& in + , int32_t numIn + , const SHPlane& plane + , int32_t planeIdx + ) noexcept; + + static std::vector reduceContacts + ( + const std::vector& in + , const SHVec3& faceNormal + ) noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index a59e8f28..71539949 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -128,139 +128,7 @@ namespace SHADE const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace); const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL); - const SHHalfEdgeStructure::Face& INCIDENT_FACE = incidentPoly->GetFace(INCIDENT_FACE_IDX); - const SHHalfEdgeStructure::Face& REFERENCE_FACE = referencePoly->GetFace(minFaceQuery.closestFace); - - const int32_t NUM_INCIDENT_VERTICES = static_cast(INCIDENT_FACE.vertexIndices.size()); - const int32_t NUM_REFERENCE_VERTICES = static_cast(REFERENCE_FACE.vertexIndices.size()); - - // Build incoming vertices to clip - std::vector clipIn; - clipIn.resize(NUM_INCIDENT_VERTICES * 2, ClipVertex{}); - - int32_t numClipIn = 0; - for (int32_t i = 0; i < NUM_INCIDENT_VERTICES; ++i) - { - const int32_t prevI = i - 1 < 0 ? NUM_INCIDENT_VERTICES - 1 : i - 1; - - const int32_t V_INDEX = INCIDENT_FACE.vertexIndices[i].index; - - // The incoming id is the previous edge - // The outgoing id is the current edge (where this vertex is the tail of) - - ClipVertex v; - v.position = incidentPoly->GetVertex(V_INDEX); - v.featurePair.inI = INCIDENT_FACE.vertexIndices[prevI].edgeIndex; - v.featurePair.outI = INCIDENT_FACE.vertexIndices[i].edgeIndex; - v.featurePair.inR = 0; - v.featurePair.outR = 0; - - clipIn[numClipIn++] = v; - } - - // Clip the vertices against the reference face side planes. - // Number of side planes == number of edges == number of vertices - for (int32_t i = 0; i < NUM_REFERENCE_VERTICES; ++i) - { - // Side plane can be built with the vertex on the edge and the plane's normal - // Plane normal = faceNormal X tangent (v2 - v1) - - const int32_t V1_INDEX = REFERENCE_FACE.vertexIndices[i].index; - const int32_t V2_INDEX = REFERENCE_FACE.vertexIndices[(i + 1) % NUM_REFERENCE_VERTICES].index; - - const SHVec3 V1 = referencePoly->GetVertex(V1_INDEX); - const SHVec3 V2 = referencePoly->GetVertex(V2_INDEX); - - const SHVec3 TANGENT = SHVec3::Normalise(V2 - V1); - const SHPlane CLIP_PLANE { V1, SHVec3::Cross(REFERENCE_NORMAL, TANGENT) }; - - std::vector clipOut = clipPolygonWithPlane(clipIn, numClipIn, CLIP_PLANE, REFERENCE_FACE.vertexIndices[i].edgeIndex); - if (clipOut.empty()) - return false; - - // Replace the clip container's contents with the clipped points for the next clipping pass - const int32_t NUM_CLIPPED = static_cast(clipOut.size()); - for (int32_t clippedIndex = 0; clippedIndex < NUM_CLIPPED; ++clippedIndex) - { - clipIn[clippedIndex].position = clipOut[clippedIndex].position; - clipIn[clippedIndex].featurePair.key = clipOut[clippedIndex].featurePair.key; - } - numClipIn = NUM_CLIPPED; - } - - // From the final set of clipped points, only keep the points that are below the reference plane. - const SHPlane REFERENCE_PLANE{ referencePoly->GetVertex(REFERENCE_FACE.vertexIndices.front().index), REFERENCE_NORMAL }; - - std::vector contacts; - for (int32_t i = 0; i < numClipIn; ++i) - { - const SHVec3 POS = clipIn[i].position; - const float DIST = REFERENCE_PLANE.SignedDistance(POS); - if (DIST <= 0.0f) - { - SHContact contact; - contact.position = POS; - contact.penetration = -DIST; - - if (flipNormal) - { - contact.featurePair.inI = clipIn[i].featurePair.inR; - contact.featurePair.inR = clipIn[i].featurePair.inI; - contact.featurePair.outI = clipIn[i].featurePair.outR; - contact.featurePair.outR = clipIn[i].featurePair.outI; - } - else - { - contact.featurePair.key = clipIn[i].featurePair.key; - } - - contacts.emplace_back(contact); - ++numContacts; - } - } - - // Reduce contact manifold if more than 4 points - if (numContacts > 4) - { - const auto INDICES_TO_KEEP = reduceContacts(contacts, REFERENCE_NORMAL); - std::vector reducedContacts; - - const int32_t NUM_REDUCED = static_cast(INDICES_TO_KEEP.size()); - for (int32_t i = 0; i < NUM_REDUCED; ++i) - reducedContacts.emplace_back(contacts[INDICES_TO_KEEP[i]]); - - contacts.clear(); - // Copy contacts to main container - for (auto& contact : reducedContacts) - contacts.emplace_back(contact); - } - - // Remove potential duplicate contact points - // No way about this being an n^2 loop - static constexpr float THRESHOLD = SHPHYSICS_SAME_CONTACT_DISTANCE * SHPHYSICS_SAME_CONTACT_DISTANCE; - for (auto i = contacts.begin(); i != contacts.end(); ++i) - { - for (auto j = i + 1; j != contacts.end();) - { - const float D2 = SHVec3::DistanceSquared(i->position, j->position); - if (D2 < THRESHOLD) - j = contacts.erase(j); - else - ++j; - } - } - - // Copy final contacts into the manifold - numContacts = static_cast(contacts.size()); - for (int32_t i = 0; i < numContacts; ++i) - manifold.contacts[i] = contacts[i]; - - manifold.numContacts = numContacts; - manifold.normal = REFERENCE_NORMAL; - if (flipNormal) - manifold.normal = -manifold.normal; - - return true; + return findFaceContacts(manifold, *incidentPoly, INCIDENT_FACE_IDX, *referencePoly, minFaceQuery.closestFace, flipNormal); } /*-----------------------------------------------------------------------------------*/ @@ -442,7 +310,7 @@ namespace SHADE const float A2_OVER_A1 = VB_DOT_VA == 0.0f ? 0.0f : VB_DOT_VB / VB_DOT_VA; const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB; const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; - const float R = DENOMINATOR == 0.0f ? NUMERATOR : NUMERATOR / DENOMINATOR; + const float R = std::clamp(NUMERATOR / DENOMINATOR, 0.0f, 1.0f); // Just take a point from A since it's A -> B return TAIL_A + R * VA; @@ -470,6 +338,147 @@ namespace SHADE return bestFace; } + bool SHCollision::findFaceContacts(SHManifold& manifold, const SHConvexPolyhedron& incPoly, int32_t incFace, const SHConvexPolyhedron& refPoly, int32_t refFace, bool flip) noexcept + { + const SHHalfEdgeStructure::Face& INCIDENT_FACE = incPoly.GetFace(incFace); + const SHHalfEdgeStructure::Face& REFERENCE_FACE = refPoly.GetFace(refFace); + + const int32_t NUM_INCIDENT_VERTICES = static_cast(INCIDENT_FACE.vertexIndices.size()); + const int32_t NUM_REFERENCE_VERTICES = static_cast(REFERENCE_FACE.vertexIndices.size()); + + // Build incoming vertices to clip + std::vector clipIn; + clipIn.resize(NUM_INCIDENT_VERTICES * 2, ClipVertex{}); + + int32_t numClipIn = 0; + for (int32_t i = 0; i < NUM_INCIDENT_VERTICES; ++i) + { + const int32_t prevI = i - 1 < 0 ? NUM_INCIDENT_VERTICES - 1 : i - 1; + + const int32_t V_INDEX = INCIDENT_FACE.vertexIndices[i].index; + + // The incoming id is the previous edge + // The outgoing id is the current edge (where this vertex is the tail of) + + ClipVertex v; + v.position = incPoly.GetVertex(V_INDEX); + v.featurePair.inI = INCIDENT_FACE.vertexIndices[prevI].edgeIndex; + v.featurePair.outI = INCIDENT_FACE.vertexIndices[i].edgeIndex; + v.featurePair.inR = 0; + v.featurePair.outR = 0; + + clipIn[numClipIn++] = v; + } + + // Clip the vertices against the reference face side planes. + // Number of side planes == number of edges == number of vertices + const SHVec3 REF_NORMAL = refPoly.GetNormal(refFace); + for (int32_t i = 0; i < NUM_REFERENCE_VERTICES; ++i) + { + // Side plane can be built with the vertex on the edge and the plane's normal + // Plane normal = faceNormal X tangent (v2 - v1) + + const int32_t V1_INDEX = REFERENCE_FACE.vertexIndices[i].index; + const int32_t V2_INDEX = REFERENCE_FACE.vertexIndices[(i + 1) % NUM_REFERENCE_VERTICES].index; + + const SHVec3 V1 = refPoly.GetVertex(V1_INDEX); + const SHVec3 V2 = refPoly.GetVertex(V2_INDEX); + + const SHVec3 TANGENT = SHVec3::Normalise(V2 - V1); + const SHPlane CLIP_PLANE { V1, SHVec3::Cross(REF_NORMAL, TANGENT) }; + + std::vector clipOut = clipPolygonWithPlane(clipIn, numClipIn, CLIP_PLANE, REFERENCE_FACE.vertexIndices[i].edgeIndex); + if (clipOut.empty()) + return false; + + // Replace the clip container's contents with the clipped points for the next clipping pass + const int32_t NUM_CLIPPED = static_cast(clipOut.size()); + for (int32_t clippedIndex = 0; clippedIndex < NUM_CLIPPED; ++clippedIndex) + { + clipIn[clippedIndex].position = clipOut[clippedIndex].position; + clipIn[clippedIndex].featurePair.key = clipOut[clippedIndex].featurePair.key; + } + numClipIn = NUM_CLIPPED; + } + + // From the final set of clipped points, only keep the points that are below the reference plane. + const SHPlane REFERENCE_PLANE{ refPoly.GetVertex(REFERENCE_FACE.vertexIndices.front().index), REF_NORMAL }; + + uint32_t numContacts = 0; + + std::vector contacts; + for (int32_t i = 0; i < numClipIn; ++i) + { + const SHVec3 POS = clipIn[i].position; + const float DIST = REFERENCE_PLANE.SignedDistance(POS); + if (DIST <= 0.0f) + { + SHContact contact; + contact.position = POS; + contact.penetration = -DIST; + + if (flip) + { + contact.featurePair.inI = clipIn[i].featurePair.inR; + contact.featurePair.inR = clipIn[i].featurePair.inI; + contact.featurePair.outI = clipIn[i].featurePair.outR; + contact.featurePair.outR = clipIn[i].featurePair.outI; + } + else + { + contact.featurePair.key = clipIn[i].featurePair.key; + } + + contacts.emplace_back(contact); + ++numContacts; + } + } + + // Reduce contact manifold if more than 4 points + if (numContacts > 4) + { + const auto INDICES_TO_KEEP = reduceContacts(contacts, REF_NORMAL); + std::vector reducedContacts; + + const int32_t NUM_REDUCED = static_cast(INDICES_TO_KEEP.size()); + for (int32_t i = 0; i < NUM_REDUCED; ++i) + reducedContacts.emplace_back(contacts[INDICES_TO_KEEP[i]]); + + contacts.clear(); + // Copy contacts to main container + for (auto& contact : reducedContacts) + contacts.emplace_back(contact); + } + + // Remove potential duplicate contact points + // No way about this being an n^2 loop + static constexpr float THRESHOLD = SHPHYSICS_SAME_CONTACT_DISTANCE * SHPHYSICS_SAME_CONTACT_DISTANCE; + for (auto i = contacts.begin(); i != contacts.end(); ++i) + { + for (auto j = i + 1; j != contacts.end();) + { + const float D2 = SHVec3::DistanceSquared(i->position, j->position); + if (D2 < THRESHOLD) + j = contacts.erase(j); + else + ++j; + } + } + + // Copy final contacts into the manifold + numContacts = static_cast(contacts.size()); + for (int32_t i = 0; i < numContacts; ++i) + manifold.contacts[i] = contacts[i]; + + manifold.numContacts = numContacts; + manifold.normal = REF_NORMAL; + if (flip) + manifold.normal = -manifold.normal; + + return true; + } + + std::vector SHCollision::clipPolygonWithPlane(const std::vector& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept { std::vector out; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index b171f206..9ad525e8 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -139,10 +139,6 @@ namespace SHADE // TODO: Move to island when islands are set up void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept; void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept; - - - - }; -- 2.40.1 From a0f6cd3ae7c6a4aadb5916e8042515e0dd7573f7 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 23 Jan 2023 00:37:22 +0800 Subject: [PATCH 82/84] Cached SAT for improved stability The effects of baumgarte stabilisation can be rather obvious especially when polyhedrons are thrown around at angles. Regardless, the system is relatively stable bar the added energy from the solving method, which may make for a more "bombastic" physics playground --- Assets/Scenes/PhysicsSandbox.shade | 10 +- .../Collision/Contacts/SHCollisionEvents.h | 4 +- .../Physics/Collision/Contacts/SHManifold.h | 3 + .../Physics/Collision/Contacts/SHManifold.hpp | 60 +++---- .../Collision/Narrowphase/SHCollision.h | 11 ++ .../Narrowphase/SHConvexVsConvex.cpp | 149 ++++++++++++++++-- .../Physics/Collision/Narrowphase/SHSATInfo.h | 87 ++++++++++ .../Collision/Narrowphase/SHSATInfo.hpp | 71 +++++++++ 8 files changed, 351 insertions(+), 44 deletions(-) create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.h create mode 100644 SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.hpp diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 8f439326..44e5e03f 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,7 +45,7 @@ NumberOfChildren: 0 Components: Camera Component: - Position: {x: 0, y: 2, z: 7} + Position: {x: 0, y: 2, z: 10} Pitch: 0 Yaw: 0 Roll: 0 @@ -62,7 +62,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -1, y: 7.5, z: 0} + Translate: {x: -2, y: 7.5, z: 0} Rotate: {x: -0, y: 0, z: 0.785398185} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -77,7 +77,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -267,8 +267,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 2, y: 2, z: 3} - Rotate: {x: 0.785398185, y: 0.785398185, z: 0.785398185} + Translate: {x: 0, y: 7, z: 0} + Rotate: {x: 0, y: 0.785398185, z: 0} Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true RigidBody Component: diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h index 3dbb16d0..15142303 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h @@ -38,7 +38,7 @@ namespace SHADE { public: SHCollisionKey info; - SHCollisionState state; + SHCollisionState state = SHCollisionState::INVALID; }; /** @@ -52,7 +52,7 @@ namespace SHADE static constexpr int MAX_NUM_CONTACTS = 4; SHCollisionKey info; - SHCollisionState state; + SHCollisionState state = SHCollisionState::INVALID; SHVec3 normal; SHVec3 contactPoints[MAX_NUM_CONTACTS]; }; diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h index 3b591875..e60e5329 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h @@ -12,6 +12,7 @@ // Primary Header #include "Physics/Dynamics/SHRigidBody.h" +#include "Physics/Collision/Narrowphase/SHSATInfo.h" #include "Physics/Collision/Shapes/SHCollisionShape.h" #include "SHContact.h" #include "SHCollisionEvents.h" @@ -58,6 +59,8 @@ namespace SHADE uint32_t numContacts = 0; SHCollisionState state = SHCollisionState::INVALID; + SHSATInfo cachedSATInfo; + SHVec3 normal; SHVec3 tangents[SHContact::NUM_TANGENTS]; SHContact contacts[MAX_NUM_CONTACTS]; diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp index 23be8c79..f1b93a43 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp +++ b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp @@ -28,13 +28,14 @@ namespace SHADE } inline SHManifold::SHManifold(const SHManifold& rhs) noexcept - : shapeA { rhs.shapeA } - , shapeB { rhs.shapeB } - , bodyA { rhs.bodyA } - , bodyB { rhs.bodyB } - , numContacts { rhs.numContacts } - , state { rhs.state } - , normal { rhs.normal } + : shapeA { rhs.shapeA } + , shapeB { rhs.shapeB } + , bodyA { rhs.bodyA } + , bodyB { rhs.bodyB } + , numContacts { rhs.numContacts } + , state { rhs.state } + , cachedSATInfo { rhs.cachedSATInfo } + , normal { rhs.normal } { static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); @@ -44,13 +45,14 @@ namespace SHADE } inline SHManifold::SHManifold(SHManifold&& rhs) noexcept - : shapeA { rhs.shapeA } - , shapeB { rhs.shapeB } - , bodyA { rhs.bodyA } - , bodyB { rhs.bodyB } - , numContacts { rhs.numContacts } - , state { rhs.state } - , normal { rhs.normal } + : shapeA { rhs.shapeA } + , shapeB { rhs.shapeB } + , bodyA { rhs.bodyA } + , bodyB { rhs.bodyB } + , numContacts { rhs.numContacts } + , state { rhs.state } + , cachedSATInfo { rhs.cachedSATInfo } + , normal { rhs.normal } { static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); @@ -68,13 +70,14 @@ namespace SHADE if (this == &rhs) return *this; - shapeA = rhs.shapeA; - shapeB = rhs.shapeB; - bodyA = rhs.bodyA; - bodyB = rhs.bodyB; - numContacts = rhs.numContacts; - state = rhs.state; - normal = rhs.normal; + shapeA = rhs.shapeA; + shapeB = rhs.shapeB; + bodyA = rhs.bodyA; + bodyB = rhs.bodyB; + numContacts = rhs.numContacts; + state = rhs.state; + cachedSATInfo = rhs.cachedSATInfo; + normal = rhs.normal; static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); @@ -87,13 +90,14 @@ namespace SHADE inline SHManifold& SHManifold::operator=(SHManifold&& rhs) noexcept { - shapeA = rhs.shapeA; - shapeB = rhs.shapeB; - bodyA = rhs.bodyA; - bodyB = rhs.bodyB; - numContacts = rhs.numContacts; - state = rhs.state; - normal = rhs.normal; + shapeA = rhs.shapeA; + shapeB = rhs.shapeB; + bodyA = rhs.bodyA; + bodyB = rhs.bodyB; + numContacts = rhs.numContacts; + state = rhs.state; + cachedSATInfo = rhs.cachedSATInfo; + normal = rhs.normal; static constexpr size_t SIZE_OF_CONTACTS = sizeof(SHContact) * static_cast(MAX_NUM_CONTACTS); memcpy_s(contacts, SIZE_OF_CONTACTS, rhs.contacts, SIZE_OF_CONTACTS); diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h index e78b33fa..060d42cc 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h @@ -139,6 +139,8 @@ namespace SHADE , const SHConvexPolyhedron& B ) noexcept; + + static EdgeQuery queryEdgeDirections ( const SHConvexPolyhedron& A @@ -207,5 +209,14 @@ namespace SHADE , const SHVec3& faceNormal ) noexcept; + // Cached Convex VS Convex + + static bool cachedConvexVSConvex + ( + SHManifold& manifold + , const SHSATInfo& cachedInfo + , const SHConvexPolyhedron& A + , const SHConvexPolyhedron& B + ) noexcept; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index 71539949..f2d6fcb3 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -48,25 +48,56 @@ namespace SHADE bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept { - static constexpr float ABSOLUTE_TOLERANCE = 0.01f; - static constexpr float RELATIVE_TOLERANCE = 0.95f; + static constexpr float ABSOLUTE_TOLERANCE = 0.01f; // 0.0005 + static constexpr float RELATIVE_TOLERANCE = 0.95f; // 1.0002 const SHConvexPolyhedron& POLY_A = dynamic_cast(A); const SHConvexPolyhedron& POLY_B = dynamic_cast(B); - // TODO: Check against cached separating axis. + if (manifold.cachedSATInfo.type != SHSATInfo::Type::INVALID) + return cachedConvexVSConvex(manifold, manifold.cachedSATInfo, POLY_A, POLY_B); + + SHSATInfo cachedInfo; const FaceQuery FACE_QUERY_A = queryFaceDirections(POLY_A, POLY_B); if (FACE_QUERY_A.bestDistance > 0.0f) + { + // cache the info + cachedInfo.type = SHSATInfo::Type::FACE; + cachedInfo.info.refPoly = SHSATInfo::ShapeID::A; + cachedInfo.info.refFace = FACE_QUERY_A.closestFace; + + manifold.cachedSATInfo = cachedInfo; + return false; + } + const FaceQuery FACE_QUERY_B = queryFaceDirections(POLY_B, POLY_A); if (FACE_QUERY_B.bestDistance > 0.0f) + { + // cache the info + cachedInfo.type = SHSATInfo::Type::FACE; + cachedInfo.info.refPoly = SHSATInfo::ShapeID::B; + cachedInfo.info.refFace = FACE_QUERY_B.closestFace; + + manifold.cachedSATInfo = cachedInfo; + return false; + } const EdgeQuery EDGE_QUERY = queryEdgeDirections(POLY_A, POLY_B); if (EDGE_QUERY.bestDistance > 0.0f) + { + // cache the info + cachedInfo.type = SHSATInfo::Type::EDGE; + cachedInfo.info.edgeA = EDGE_QUERY.halfEdgeA; + cachedInfo.info.edgeB = EDGE_QUERY.halfEdgeB; + + manifold.cachedSATInfo = cachedInfo; + return false; + } // Apply weight to improve frame coherence of normal directions. // We want a normal in the direction from A -> B, so we flip the normal if needed. @@ -81,6 +112,10 @@ namespace SHADE referencePoly = &POLY_A; incidentPoly = &POLY_B; flipNormal = false; + + cachedInfo.type = SHSATInfo::Type::FACE; + cachedInfo.info.refPoly = SHSATInfo::ShapeID::A; + cachedInfo.info.refFace = minFaceQuery.closestFace; } else { @@ -88,9 +123,13 @@ namespace SHADE referencePoly = &POLY_B; incidentPoly = &POLY_A; flipNormal = true; + + cachedInfo.type = SHSATInfo::Type::FACE; + cachedInfo.info.refPoly = SHSATInfo::ShapeID::B; + cachedInfo.info.refFace = minFaceQuery.closestFace; } - uint32_t numContacts = 0; + // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on @@ -114,6 +153,8 @@ namespace SHADE manifold.normal = -manifold.normal; // In this scenario, we only have one contact + uint32_t numContacts = 0; + SHContact contact; contact.featurePair.key = EDGE_QUERY.axis; contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB); @@ -122,12 +163,20 @@ namespace SHADE manifold.contacts[numContacts++] = contact; manifold.numContacts = numContacts; + // Cache the info + cachedInfo.type = SHSATInfo::Type::EDGE; + cachedInfo.info.edgeA = EDGE_QUERY.halfEdgeA; + cachedInfo.info.edgeB = EDGE_QUERY.halfEdgeB; + + manifold.cachedSATInfo = cachedInfo; + return true; } const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace); const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL); + manifold.cachedSATInfo = cachedInfo; return findFaceContacts(manifold, *incidentPoly, INCIDENT_FACE_IDX, *referencePoly, minFaceQuery.closestFace, flipNormal); } @@ -268,6 +317,7 @@ namespace SHADE * (LB(s) - LA(r)) /dot VB = 0 * * Where LB(s) - LA(r) is the same vector as VB X VA. + * */ const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(edgeA); @@ -291,15 +341,17 @@ namespace SHADE * c = C' /dot U * * U is either VA or VB + * + * TODO: Check if segments degenerate into a point */ const SHVec3 C = TAIL_B - TAIL_A; - const float VB_DOT_VA = SHVec3::Dot(VB, VA); // a1 - const float VB_DOT_VB = SHVec3::Dot(VB, VB); // a2 - const float AV_DOT_VA = SHVec3::Dot(-VA, VA); // b1 - const float AV_DOT_VB = SHVec3::Dot(-VA, VB); // b2 - const float C_DOT_VA = SHVec3::Dot(C, VA); // c1 + const float VB_DOT_VA = SHVec3::Dot(VB, VA); // a1 + const float VB_DOT_VB = SHVec3::Dot(VB, VB); // a2 + const float AV_DOT_VA = SHVec3::Dot(-VA, VA); // b1 + const float AV_DOT_VB = SHVec3::Dot(-VA, VB); // b2 + const float C_DOT_VA = SHVec3::Dot(C, VA); // c1 const float C_DOT_VB = SHVec3::Dot(C, VB); // c2 /* @@ -310,6 +362,8 @@ namespace SHADE const float A2_OVER_A1 = VB_DOT_VA == 0.0f ? 0.0f : VB_DOT_VB / VB_DOT_VA; const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB; const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; + + // We clamp it because the factor cannot be beyond [0,1] as it would be beyond the segment if it was so. const float R = std::clamp(NUMERATOR / DENOMINATOR, 0.0f, 1.0f); // Just take a point from A since it's A -> B @@ -687,5 +741,82 @@ namespace SHADE return indicesToKeep; } + bool SHCollision::cachedConvexVSConvex(SHManifold& manifold, const SHSATInfo& cachedInfo, const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept + { + if (cachedInfo.type == SHSATInfo::Type::FACE) + { + SHASSERT(cachedInfo.info.refPoly != SHSATInfo::ShapeID::INVALID, "Attempted to perform cached SAT with an invalid cached collision!") + + // Assume the reference poly was A + const SHConvexPolyhedron* incPoly = &B; + const SHConvexPolyhedron* refPoly = &A; + bool flip = false; + + // Swap if it was B + if (cachedInfo.info.refPoly == SHSATInfo::ShapeID::B) + { + refPoly = &B; + incPoly = &A; + flip = true; + } + + const SHHalfEdgeStructure::Face& REF_FACE = refPoly->GetFace(cachedInfo.info.refFace); + const SHVec3 REF_NORMAL = refPoly->GetNormal(cachedInfo.info.refFace); + + const SHVec3 SUPPORT_POINT = incPoly->FindSupportPoint(-REF_NORMAL); + + const SHPlane REF_FACE_PLANE { refPoly->GetVertex(REF_FACE.vertexIndices[0].index), REF_NORMAL }; + const float DISTANCE = REF_FACE_PLANE.SignedDistance(SUPPORT_POINT); + + if (DISTANCE > 0.0f) + return false; + + // Find the incident face + const int32_t INCIDENT_FACE_INDEX = findIncidentFace(*incPoly, REF_NORMAL); + + return findFaceContacts(manifold, *incPoly, INCIDENT_FACE_INDEX, *refPoly, cachedInfo.info.refFace, flip); + } + + if (cachedInfo.type == SHSATInfo::Type::EDGE) + { + const float DISTANCE = distanceBetweenEdges(A, B, cachedInfo.info.edgeA, cachedInfo.info.edgeB); + if (DISTANCE > 0.0f) + return false; + + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = A.GetHalfEdge(cachedInfo.info.edgeA); + const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = B.GetHalfEdge(cachedInfo.info.edgeB); + + const SHVec3 HEAD_A = A.GetVertex(HALF_EDGE_A.headVertexIndex); + const SHVec3 TAIL_A = A.GetVertex(HALF_EDGE_A.tailVertexIndex); + const SHVec3 HEAD_B = B.GetVertex(HALF_EDGE_B.headVertexIndex); + const SHVec3 TAIL_B = B.GetVertex(HALF_EDGE_B.tailVertexIndex); + + const SHVec3 VA = SHVec3::Normalise(HEAD_A - TAIL_A); + const SHVec3 VB = SHVec3::Normalise(HEAD_B - TAIL_B); + + manifold.normal = SHVec3::Cross(VB, VA); + // Flip normal if need to ( A -> B) + if (SHVec3::Dot(manifold.normal, HEAD_A - A.GetWorldCentroid()) < 0.0f) + manifold.normal = -manifold.normal; + + // In this scenario, we only have one contact + uint32_t numContacts = 0; + + SHContact contact; + // Take feature pair key from previous manifold + contact.featurePair.key = manifold.contacts[0].featurePair.key; + contact.position = findClosestPointBetweenEdges(A, B, cachedInfo.info.edgeA, cachedInfo.info.edgeB); + contact.penetration = -DISTANCE; + + manifold.contacts[numContacts++] = contact; + manifold.numContacts = numContacts; + + return true; + } + + // Should never reach this. + return false; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.h b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.h new file mode 100644 index 00000000..25606084 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.h @@ -0,0 +1,87 @@ +/**************************************************************************************** + * \file SHSATInfo.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for storing information of collision detection between two + * convex shapes using SAT. + * + * \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 // int32_t + +namespace SHADE +{ + /** + * @brief + * Primarily used to cached collision information between two convex polyhedrons for + * temporal coherence. + */ + struct SHSATInfo + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class ShapeID : int32_t + { + A = 0 + , B = 1 + + , INVALID = -1 + }; + + enum class Type + { + EDGE + , FACE + + , INVALID = -1 + }; + + union ContactInfo + { + struct // FaceContact + { + ShapeID refPoly; + int32_t refFace; + }; + + struct // Edge Contact + { + int32_t edgeA; + int32_t edgeB; + }; + }; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Type type; + ContactInfo info; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHSATInfo () noexcept; + SHSATInfo (const SHSATInfo& rhs) noexcept; + SHSATInfo (SHSATInfo&& rhs) noexcept; + ~SHSATInfo () noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHSATInfo& operator= (const SHSATInfo& rhs) noexcept; + SHSATInfo& operator= (SHSATInfo&& rhs) noexcept; + }; + +} // namespace SHADE + +#include "SHSATInfo.hpp" diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.hpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.hpp new file mode 100644 index 00000000..8e51d54b --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.hpp @@ -0,0 +1,71 @@ +/**************************************************************************************** + * \file SHSATInfo.hpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation of inlined methods for cached SAT Info. + * + * \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 "SHSATInfo.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-----------------------------------------------------------------------------------*/ + + inline SHSATInfo::SHSATInfo() noexcept + : type { Type::INVALID } + , info {} + { + info.refPoly = ShapeID::INVALID; + info.refFace = -1; + } + + inline SHSATInfo::SHSATInfo(const SHSATInfo& rhs) noexcept + : type { rhs.type } + , info {} + { + info.refPoly = rhs.info.refPoly; + info.refFace = rhs.info.refFace; + + } + + inline SHSATInfo::SHSATInfo(SHSATInfo&& rhs) noexcept + : type { rhs.type } + , info {} + { + info.refPoly = rhs.info.refPoly; + info.refFace = rhs.info.refFace; + } + + /*---------------------------------------------------------------------------------- */ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------- */ + + inline SHSATInfo& SHSATInfo::operator=(const SHSATInfo& rhs) noexcept + { + if (this == &rhs) + return *this; + + type = rhs.type; + info.refPoly = rhs.info.refPoly; + info.refFace = rhs.info.refFace; + + return *this; + } + + inline SHSATInfo& SHSATInfo::operator=(SHSATInfo&& rhs) noexcept + { + type = rhs.type; + info.refPoly = rhs.info.refPoly; + info.refFace = rhs.info.refFace; + + return *this; + } +} -- 2.40.1 From 5730381302bcc23fd0a7fffc6139ced1ce7bef7e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 23 Jan 2023 00:56:46 +0800 Subject: [PATCH 83/84] Physics objects can be implicity static if only a collider was added. Removed the need to create an extra body. Math is great. --- Assets/Scenes/PhysicsSandbox.shade | 108 +----------------- .../Dynamics/Constraints/SHVelocityState.h | 35 +++--- .../src/Physics/Dynamics/SHContactManager.cpp | 14 ++- .../src/Physics/Dynamics/SHContactSolver.cpp | 37 +++++- 4 files changed, 65 insertions(+), 129 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 44e5e03f..3b940bc1 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -8,23 +8,6 @@ Rotate: {x: 0, y: 0, z: 0.436332315} Scale: {x: 4.61070776, y: 0.99999392, z: 0.999996722} IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: true - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: true - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true Collider Component: DrawColliders: false Colliders: @@ -62,7 +45,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -2, y: 7.5, z: 0} + Translate: {x: 0, y: 7.5, z: 0} Rotate: {x: -0, y: 0, z: 0.785398185} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -77,7 +60,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: true + Freeze Position Y: false Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -107,23 +90,6 @@ Rotate: {x: -0, y: 0, z: -0.436332315} Scale: {x: 4.61071014, y: 0.999995887, z: 1} IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: true - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: true - Freeze Position Y: true - Freeze Position Z: true - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true Collider Component: DrawColliders: false Colliders: @@ -148,23 +114,6 @@ Rotate: {x: -0, y: 0, z: -0} Scale: {x: 10, y: 3, z: 10} IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: true - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: true - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true Collider Component: DrawColliders: false Colliders: @@ -189,23 +138,6 @@ Rotate: {x: -0, y: 0, z: 1.57079601} Scale: {x: 9.99975109, y: 0.499992192, z: 10} IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: true - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: true - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true Collider Component: DrawColliders: false Colliders: @@ -230,23 +162,6 @@ Rotate: {x: -0, y: 0, z: 1.57079601} Scale: {x: 9.99975109, y: 0.499992192, z: 10} IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: true - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: true - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true Collider Component: DrawColliders: false Colliders: @@ -267,7 +182,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 7, z: 0} + Translate: {x: 0, y: 2, z: 3} Rotate: {x: 0, y: 0.785398185, z: 0} Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true @@ -316,23 +231,6 @@ Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true - RigidBody Component: - Type: Static - Auto Mass: false - Mass: .inf - Drag: 0.00999999978 - Angular Drag: 0.00999999978 - Use Gravity: true - Gravity Scale: 1 - Interpolate: true - Sleeping Enabled: true - Freeze Position X: false - Freeze Position Y: true - Freeze Position Z: false - Freeze Rotation X: false - Freeze Rotation Y: false - Freeze Rotation Z: false - IsActive: true Collider Component: DrawColliders: false Colliders: diff --git a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h index 6cbb6efb..7c9b6a10 100644 --- a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h +++ b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h @@ -33,23 +33,30 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ SHVelocityState (const SHRigidBody* rigidBody) noexcept + : LinearVelocity { SHVec3::Zero } + , AngularVelocity { SHVec3::Zero } + , LinearLockFactor { SHVec3::Zero } + , AngularLockFactor { SHVec3::Zero } { - LinearVelocity = rigidBody->GetLinearVelocity(); - AngularVelocity = rigidBody->GetAngularVelocity(); - - LinearLockFactor = SHVec3 + if (rigidBody) { - rigidBody->GetFreezePositionX() ? 0.0f : 1.0f - , rigidBody->GetFreezePositionY() ? 0.0f : 1.0f - , rigidBody->GetFreezePositionZ() ? 0.0f : 1.0f - }; + LinearVelocity = rigidBody->GetLinearVelocity(); + AngularVelocity = rigidBody->GetAngularVelocity(); - AngularLockFactor = SHVec3 - { - rigidBody->GetFreezeRotationX() ? 0.0f : 1.0f - , rigidBody->GetFreezeRotationY() ? 0.0f : 1.0f - , rigidBody->GetFreezeRotationZ() ? 0.0f : 1.0f - }; + LinearLockFactor = SHVec3 + { + rigidBody->GetFreezePositionX() ? 0.0f : 1.0f + , rigidBody->GetFreezePositionY() ? 0.0f : 1.0f + , rigidBody->GetFreezePositionZ() ? 0.0f : 1.0f + }; + + AngularLockFactor = SHVec3 + { + rigidBody->GetFreezeRotationX() ? 0.0f : 1.0f + , rigidBody->GetFreezeRotationY() ? 0.0f : 1.0f + , rigidBody->GetFreezeRotationZ() ? 0.0f : 1.0f + }; + } } }; diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp index ade7b482..7434953e 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -200,11 +200,17 @@ namespace SHADE const auto& STATE_A = VELOCITY_STATES.find(key.GetEntityA())->second; const auto& STATE_B = VELOCITY_STATES.find(key.GetEntityB())->second; - bodyA->SetLinearVelocity(STATE_A.LinearVelocity); - bodyB->SetLinearVelocity(STATE_B.LinearVelocity); + if (bodyA) + { + bodyA->SetLinearVelocity(STATE_A.LinearVelocity); + bodyA->SetAngularVelocity(STATE_A.AngularVelocity); + } - bodyA->SetAngularVelocity(STATE_A.AngularVelocity); - bodyB->SetAngularVelocity(STATE_B.AngularVelocity); + if (bodyB) + { + bodyB->SetLinearVelocity(STATE_B.LinearVelocity); + bodyB->SetAngularVelocity(STATE_B.AngularVelocity); + } } contactSolver.Reset(); diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp index 926e1fed..f16d7f1e 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp @@ -63,13 +63,38 @@ namespace SHADE // Mass data - newConstraint.invMassA = BODY_A->invMass; - newConstraint.invInertiaA = BODY_A->worldInvInertia; - newConstraint.centerOfMassA = BODY_A->worldCentroid; + // Account for implicity-static bodies + if (BODY_A) + { + newConstraint.invMassA = BODY_A->invMass; + newConstraint.centerOfMassA = BODY_A->worldCentroid; + newConstraint.invInertiaA = BODY_A->worldInvInertia; + } + else + { + newConstraint.invMassA = 0.0f; + newConstraint.centerOfMassA = SHVec3::Zero; - newConstraint.invMassB = BODY_B->invMass; - newConstraint.invInertiaB = BODY_B->worldInvInertia; - newConstraint.centerOfMassB = BODY_B->worldCentroid; + // Matrix needs to maintain its homogenous structure + newConstraint.invInertiaA = SHMatrix::Zero; + newConstraint.invInertiaA.m[3][3] = 1.0f; + } + + if (BODY_B) + { + newConstraint.invMassB = BODY_B->invMass; + newConstraint.centerOfMassB = BODY_B->worldCentroid; + newConstraint.invInertiaB = BODY_B->worldInvInertia; + } + else + { + newConstraint.invMassB = 0.0f; + newConstraint.centerOfMassB = SHVec3::Zero; + + // Matrix needs to maintain its homogenous structure + newConstraint.invInertiaB = SHMatrix::Zero; + newConstraint.invInertiaB.m[3][3] = 1.0f; + } // Collision data -- 2.40.1 From 4ed7aa3aed2ccfcf0eb6742bd5dc5b041765aced Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 23 Jan 2023 03:03:40 +0800 Subject: [PATCH 84/84] Reverted an attempt to stabilise edge detection between polyhedrons --- Assets/Scenes/PhysicsSandbox.shade | 8 ++++---- .../Physics/Collision/Narrowphase/SHConvexVsConvex.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Assets/Scenes/PhysicsSandbox.shade b/Assets/Scenes/PhysicsSandbox.shade index 3b940bc1..56f272e0 100644 --- a/Assets/Scenes/PhysicsSandbox.shade +++ b/Assets/Scenes/PhysicsSandbox.shade @@ -45,7 +45,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 7.5, z: 0} + Translate: {x: 2, y: 7.5, z: 0} Rotate: {x: -0, y: 0, z: 0.785398185} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -60,7 +60,7 @@ Interpolate: true Sleeping Enabled: true Freeze Position X: false - Freeze Position Y: false + Freeze Position Y: true Freeze Position Z: false Freeze Rotation X: false Freeze Rotation Y: false @@ -182,8 +182,8 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 2, z: 3} - Rotate: {x: 0, y: 0.785398185, z: 0} + Translate: {x: 0, y: 7, z: 0} + Rotate: {x: 0, y: 0, z: 0.785398185} Scale: {x: 0.999990404, y: 0.999994457, z: 0.999985337} IsActive: true RigidBody Component: diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp index f2d6fcb3..e38a66a7 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp @@ -364,7 +364,7 @@ namespace SHADE const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; // We clamp it because the factor cannot be beyond [0,1] as it would be beyond the segment if it was so. - const float R = std::clamp(NUMERATOR / DENOMINATOR, 0.0f, 1.0f); + const float R = DENOMINATOR == 0.0f ? NUMERATOR : NUMERATOR / DENOMINATOR; // Just take a point from A since it's A -> B return TAIL_A + R * VA; -- 2.40.1