From 52dc993941676f93f0af4985c197b63e38072016 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 2 Dec 2022 17:44:44 +0800 Subject: [PATCH 001/134] 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 */ /*-----------------------------------------------------------------------------*/ From 6cd203179a6bb7d6951ce4b06993a6b0489e7fd6 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 2 Dec 2022 19:01:08 +0800 Subject: [PATCH 002/134] 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 From ca45a12186f97621bfa4c91e1e76313bd7eda6ae Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 4 Dec 2022 17:31:22 +0800 Subject: [PATCH 003/134] 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" From 36ceec5855faa477d292e9e105ca37a5a93e9ed2 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 5 Dec 2022 00:19:48 +0800 Subject: [PATCH 004/134] 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: /*---------------------------------------------------------------------------------*/ From 38b1c46d1f96a77023fe2f47cd2631f0645e0c21 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 5 Dec 2022 00:20:29 +0800 Subject: [PATCH 005/134] 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; }; } From 74e50e10bdc5c7c203b96238c31617e6fdeb87aa Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 9 Dec 2022 01:15:43 +0800 Subject: [PATCH 006/134] 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" From c1d77029142e5631a0293b7e9bd2f1018de89525 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 11 Dec 2022 20:12:26 +0800 Subject: [PATCH 007/134] 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; /*---------------------------------------------------------------------------------*/ From bf8a410fa2a933656b68d5df749010c18c5182ee Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 11 Dec 2022 20:33:30 +0800 Subject: [PATCH 008/134] 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:; } From 0cebedeee09f32c092966a9aba30e4da1a51616a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 11 Dec 2022 20:44:40 +0800 Subject: [PATCH 009/134] 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; From af3a5e7dc9313c5cbbc14123b3b8e533af715812 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 13 Dec 2022 03:54:37 +0800 Subject: [PATCH 010/134] 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{}; From 53edffebac0e69feaf190ab2594ed16be07b04fc Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 15 Dec 2022 02:08:25 +0800 Subject: [PATCH 011/134] 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 From 27c7a1739776e2de7a135e145220f42bd11b1a35 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 15 Dec 2022 22:59:55 +0800 Subject: [PATCH 012/134] 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; From 27760a95c98fa3a0a4e0574377f61af0f9483ca5 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 15 Dec 2022 23:00:15 +0800 Subject: [PATCH 013/134] 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 From 6b8232ae9150bdd25cff47165c8531f5498e3728 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 02:02:20 +0800 Subject: [PATCH 014/134] 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(); + } } /*-----------------------------------------------------------------------------------*/ From ddf2d8bde9b424d0f140b1c1fbf3eb4815a930fc Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 14:38:01 +0800 Subject: [PATCH 015/134] 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; } } From 1b91f60c4ae3619feb75833d3e047eb09e5fedca Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 14:38:22 +0800 Subject: [PATCH 016/134] 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: /*---------------------------------------------------------------------------------*/ From 2bd90e7c143ddd7a665c4e5d5f58f07d16203c11 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 14:38:46 +0800 Subject: [PATCH 017/134] 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; From a6e1064e64dcc8515a76c445e95f9349d6e9f706 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 15:03:55 +0800 Subject: [PATCH 018/134] 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(); } } } From 6a20e93704b2eda4d680f913cb6d430d87081e1b Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 18:34:29 +0800 Subject: [PATCH 019/134] 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; } From 24b13ed6e42815573900870a65906a61afa975d3 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 16 Dec 2022 18:34:29 +0800 Subject: [PATCH 020/134] 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; } From cf9d4ef04bf518a3a370ad6312dbbdbe352a5f42 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 19 Dec 2022 16:56:34 +0800 Subject: [PATCH 021/134] 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); }; From 751a16dcc3a64a9f22eae66f11a66d858c766c1a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 20 Dec 2022 02:13:06 +0800 Subject: [PATCH 022/134] 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]; From 5def5392a1986250fbb0ddc6d90aa92646fbfad0 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 20 Dec 2022 02:26:31 +0800 Subject: [PATCH 023/134] 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 From b58b475c04cb0496515e576be9d7f1e057554eb8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 20 Dec 2022 23:10:23 +0800 Subject: [PATCH 024/134] 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; } From 265a5bece8aa8ab0804a692550faa2c2697bd730 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 00:40:01 +0800 Subject: [PATCH 025/134] 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 */ From 33ef5e0d3d1ffbe433993944d1644b3eec6c897b Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 01:10:28 +0800 Subject: [PATCH 026/134] 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 From d109d06764fc653dfe7ca34e1ec1ed96a025285e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 18:57:10 +0800 Subject: [PATCH 027/134] 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: /*-----------------------------------------------------------------------------------*/ From 92ed8a29ffaa97895631f3b787df635b357073b3 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 21 Dec 2022 19:04:10 +0800 Subject: [PATCH 028/134] 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 } {} From f4f6cb7eae178a333730ab6fed7f461b94c57829 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 22 Dec 2022 01:10:25 +0800 Subject: [PATCH 029/134] 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 From b667e4df872316bebb69afb1a117f43e8f5db47b Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 22 Dec 2022 03:11:14 +0800 Subject: [PATCH 030/134] 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; }; From 22c0a14081e2109de18a977382dd4412cbc38b4e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 23 Dec 2022 00:55:36 +0800 Subject: [PATCH 031/134] 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; } From 89f1f600640c9d7420a674b4192ae8ad950f8c58 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 24 Dec 2022 02:19:53 +0800 Subject: [PATCH 032/134] 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 */ /*---------------------------------------------------------------------------------*/ From 0df6e09ed6334de0ca070b1bc24d20456e6d4ee6 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 24 Dec 2022 13:32:50 +0800 Subject: [PATCH 033/134] 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() { From b14ddac1e692cb5a1edf4ee80003e5794b54a3c5 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:42:10 +0800 Subject: [PATCH 034/134] 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:; } From 8ead885d0df7d661643e186289a7bf461fad6810 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:44:08 +0800 Subject: [PATCH 035/134] 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 */ From ea1dd57996bf684e8d954feebb3161079a03efd2 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:45:01 +0800 Subject: [PATCH 036/134] 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 From 400cbb35d9b43685f02a79c651b89e4be4583f11 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 00:45:37 +0800 Subject: [PATCH 037/134] 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 From fba338eaef197eb2e0abeae46de86a52cb9ed62f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 01:14:40 +0800 Subject: [PATCH 038/134] 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); From 6bab419428fa6ef5d16c890882210156a153c21e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 01:23:14 +0800 Subject: [PATCH 039/134] 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 { From 7b1b4873ec52a986ac47440810ea169d4afb71fd Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 01:27:31 +0800 Subject: [PATCH 040/134] 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); From 50e3ddf0dd5d77681141a582b1a4fcf5b2549a0d Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 17:59:59 +0800 Subject: [PATCH 041/134] 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; From a36d03b03bb2b1164faaa4e58efb5c60a1361d78 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 21:42:44 +0800 Subject: [PATCH 042/134] 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; }; From d98d6a9e06a978150b35e20066f9075b417085b3 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 21:43:06 +0800 Subject: [PATCH 043/134] 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: From 3586c7ffdc675f7d5a244fc6716948fc729929ad Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 21:43:22 +0800 Subject: [PATCH 044/134] 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(); From 82d46fce9962d6e2e0b5610014376f296c6c3a4a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 30 Dec 2022 23:53:45 +0800 Subject: [PATCH 045/134] 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); } } From 896b47c1a01e28fb98ebc4fe6a9ecbcb577f7e9f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:11:03 +0800 Subject: [PATCH 046/134] 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) From 987a1fa515fbad167de0f7c5a27a2c6926547f98 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:18:35 +0800 Subject: [PATCH 047/134] 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 */ From 6451ca5e954bcb53e6a6ef161b317d73dd6888d8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:40:28 +0800 Subject: [PATCH 048/134] 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; From 136b7e7bfcb07f90b251d8d5f915d09845a6701a Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 01:47:42 +0800 Subject: [PATCH 049/134] 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()); From 3a7336fe15d918ec281252f833da001040811bd4 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 31 Dec 2022 18:43:46 +0800 Subject: [PATCH 050/134] 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: From 00f8726e465303d1d12e7a139ae443206803fa06 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 02:42:44 +0800 Subject: [PATCH 051/134] 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; From 67907b1ca98a4355a8f9708b994be9ed7ca38ab1 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 02:48:02 +0800 Subject: [PATCH 052/134] 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) From f3c0bdbcfd45872ebbc4aa5666017db2be18ce10 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 03:24:34 +0800 Subject: [PATCH 053/134] 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 From 38764e79b31cdcef31f5df8ae4eb2271f264387f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 03:32:59 +0800 Subject: [PATCH 054/134] 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 /* From 03becd8e471aec37ffcbb1d166dd852197d052f8 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sun, 1 Jan 2023 13:59:10 +0800 Subject: [PATCH 055/134] Removing resources now remove subpasses and computes involved - Added an empty node in the render graph for shadow mapping --- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 5 +- .../Graphics/RenderGraph/SHRenderGraph.cpp | 109 +++++----- .../src/Graphics/RenderGraph/SHRenderGraph.h | 1 - .../RenderGraph/SHRenderGraphNode.cpp | 198 ++++++++++-------- .../RenderGraph/SHRenderGraphNodeCompute.cpp | 78 ++++--- .../RenderGraph/SHRenderGraphNodeCompute.h | 12 ++ .../src/Graphics/RenderGraph/SHSubpass.cpp | 26 +-- .../src/Graphics/RenderGraph/SHSubpass.h | 7 +- 8 files changed, 241 insertions(+), 195 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index b1256921..18d79579 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -259,9 +259,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. // It will initially also not have any subpasses since they will be added for each light that casts shadows. - //auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {}); - - + auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ @@ -450,6 +448,7 @@ namespace SHADE InitMiddleEnd(); InitSubsystems(); InitBuiltInResources(); + InitEvents(); } void SHGraphicsSystem::Exit(void) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 74371a64..e9a0e0bd 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -106,6 +106,9 @@ namespace SHADE for (auto& affectedNode : affectedNodes) nodes[affectedNode]->CreateFramebuffer(); + + renderGraphStorage->graphResources->at(resourceName).Free(); + renderGraphStorage->graphResources->erase (resourceName); /* * IMPORTANT NOTES * @@ -168,65 +171,62 @@ namespace SHADE { // key is handle ID, value is final layout. std::unordered_map resourceAttFinalLayouts; - if (node->subpasses.empty()) + if (!node->subpasses.empty()) { - SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); - return; - } - - // We first want to take all resources track their layout as undefined at the start of the node/renderpass - auto const resources = node->GetResources(); - for (auto& resource : resources) - { - resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); - } - - // attempt to get all final layouts for all resources - for (auto& subpass : node->subpasses) - { - for (auto& color : subpass->colorReferences) + // We first want to take all resources track their layout as undefined at the start of the node/renderpass + auto const resources = node->GetResources(); + for (auto& resource : resources) { - // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass - if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) - resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; - else - resourceAttFinalLayouts[color.attachment] = color.layout; - - node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); + resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); } - for (auto& depth : subpass->depthReferences) + // attempt to get all final layouts for all resources + for (auto& subpass : node->subpasses) { - resourceAttFinalLayouts[depth.attachment] = depth.layout; - node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); + for (auto& color : subpass->colorReferences) + { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass + if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + else + resourceAttFinalLayouts[color.attachment] = color.layout; + + node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); + } + + for (auto& depth : subpass->depthReferences) + { + resourceAttFinalLayouts[depth.attachment] = depth.layout; + node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); + } + + for (auto& input : subpass->inputReferences) + { + resourceAttFinalLayouts[input.attachment] = input.layout; + node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); + } } - for (auto& input : subpass->inputReferences) + for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) { - resourceAttFinalLayouts[input.attachment] = input.layout; - node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); - } - } + auto& att = node->attachmentDescriptions[j]; + auto& resource = node->attResources[j]; - for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) - { - auto& att = node->attachmentDescriptions[j]; - auto& resource = node->attResources[j]; - - // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. - // We also want to load the attachment, not "don't care". - if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && + // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. + // We also want to load the attachment, not "don't care". + if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) - { - att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at (resource.GetId().Raw); - att.loadOp = vk::AttachmentLoadOp::eLoad; - att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; - } - else - att.initialLayout = vk::ImageLayout::eUndefined; + { + att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw); + att.loadOp = vk::AttachmentLoadOp::eLoad; + att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; + } + else + att.initialLayout = vk::ImageLayout::eUndefined; - att.finalLayout = resourceAttFinalLayouts[j]; - resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); + att.finalLayout = resourceAttFinalLayouts[j]; + resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); + } } ++i; } @@ -532,10 +532,6 @@ namespace SHADE ConfigureSubSystems(); } - void SHRenderGraph::Regenerate(void) noexcept - { - - } /***************************************************************************/ /*! @@ -572,10 +568,13 @@ namespace SHADE for (auto& node : nodes) { - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + if (node->renderpass) + { + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - node->Execute(cmdBuffer, descPool, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); + } } cmdBuffer->EndLabeledSegment(); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index c7fe221b..7dc19a80 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -134,7 +134,6 @@ namespace SHADE ) noexcept; void Generate (void) noexcept; - void Regenerate (void) noexcept; void CheckForNodeComputes (void) noexcept; void Execute (uint32_t frameIndex, Handle descPool) noexcept; void Begin (uint32_t frameIndex) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 3c412645..56d8734a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -32,8 +32,11 @@ namespace SHADE renderpass.Free(); } - renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + if (!spDescs.empty()) + { + renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + } } /***************************************************************************/ @@ -46,77 +49,86 @@ namespace SHADE /***************************************************************************/ void SHRenderGraphNode::CreateFramebuffer(void) noexcept { - if (!framebuffers.empty()) + if (renderpass) { - for (auto fbo : framebuffers) + if (!framebuffers.empty()) { - if (fbo) - fbo.Free(); - } - } - - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (auto fbo : framebuffers) + { + if (fbo) + fbo.Free(); + } } + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + } } } void SHRenderGraphNode::HandleResize(void) noexcept { - renderpass->HandleResize(); - - for (uint32_t i = 0; i < framebuffers.size(); ++i) + if (renderpass) { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); + renderpass->HandleResize(); - for (uint32_t j = 0; j < attResources.size(); ++j) + for (uint32_t i = 0; i < framebuffers.size(); ++i) { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } - framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); - } + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } - for (auto& subpass : subpasses) - { - subpass->HandleResize(); - } - - for (auto& nodeCompute : nodeComputes) - { - nodeCompute->HandleResize(); + for (auto& nodeCompute : nodeComputes) + { + nodeCompute->HandleResize(); + } } } void SHRenderGraphNode::ConfigureSubpasses(void) noexcept { + if (subpasses.empty()) + return; + // Create subpass description and dependencies based on number of subpasses spDescs.resize(subpasses.size()); spDeps.resize(subpasses.size()); @@ -512,11 +524,8 @@ namespace SHADE // Remove footprint of attachment from all subpasses as well for (auto it = subpasses.begin(); it != subpasses.end(); ++it) { - // attempt to detach resource from subpass - (*it)->DetachResource(resourceName, index); - - // If the subpass ends up having no attachments after, erase it from the node - if ((*it)->HasNoAttachments()) + // If the subpass uses the resource, just remove the subpass since the subpass will be invalid + if ((*it)->UsesResource(index)) { // erase from indexing subpassIndexing.erase((*it)->GetName()); @@ -530,6 +539,24 @@ namespace SHADE for (uint32_t i = 0; i < subpasses.size(); ++i) subpasses[i]->SetIndex(i); + // remove node computes using the resource + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if ((*it)->UsesResource(resourceHandleID)) + { + it = nodeComputes.erase(it); + } + } + + // recompute the barriers for the other computes + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if (it == nodeComputes.begin()) + (*it)->SetFollowingEndRenderpass(true); + + (*it)->InitializeBarriers(); + } + return true; } return false; @@ -537,37 +564,40 @@ namespace SHADE void SHRenderGraphNode::Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { - uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) + if (renderpass) { - subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - // Go to next subpass if not last subpass - if (i != static_cast(subpasses.size()) - 1u) - commandBuffer->NextSubpass(); + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + + // Go to next subpass if not last subpass + if (i != static_cast(subpasses.size()) - 1u) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); + + // We bind these 2 descriptor sets here because they apply to all node computes + if (!nodeComputes.empty()) + { + commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); + + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + + // bind lighting data + SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); + } + + // Execute all subpass computes + for (auto& sbCompute : nodeComputes) + sbCompute->Execute(commandBuffer, frameIndex); } - - commandBuffer->EndRenderpass(); - - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); - - // We bind these 2 descriptor sets here because they apply to all node computes - if (!nodeComputes.empty()) - { - commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); - - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - - // bind lighting data - SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); - } - - // Execute all subpass computes - for (auto& sbCompute : nodeComputes) - sbCompute->Execute(commandBuffer, frameIndex); } Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index cfc8443c..e1bc3842 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -14,6 +14,54 @@ namespace SHADE { + + bool SHRenderGraphNodeCompute::UsesResource(uint64_t resourceHandleID) const noexcept + { + for (auto& resource : resources) + { + if (resource.GetId().Raw == resourceHandleID) + return true; + } + return false; + } + + void SHRenderGraphNodeCompute::InitializeBarriers(void) noexcept + { + for (uint32_t i = 0; auto & barriers : memoryBarriers) + { + barriers.clear(); + + for (auto& resource : resources) + { + vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); + barriers.push_back(vk::ImageMemoryBarrier + { + .srcAccessMask = srcAccessMask, + .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, + .oldLayout = vk::ImageLayout::eGeneral, + .newLayout = vk::ImageLayout::eGeneral, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = resource->imageAspectFlags, + .baseMipLevel = 0, + .levelCount = resource->mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + } + ++i; + } + } + + void SHRenderGraphNodeCompute::SetFollowingEndRenderpass(uint32_t flag) noexcept + { + followingEndRenderpass = flag; + } + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} @@ -157,35 +205,7 @@ namespace SHADE groupSizeX = maxWidth / workGroupSizeX; groupSizeY = maxHeight / workGroupSizeY; - for (uint32_t i = 0; auto& barriers : memoryBarriers) - { - barriers.clear(); - - for (auto& resource : resources) - { - vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); - barriers.push_back(vk::ImageMemoryBarrier - { - .srcAccessMask = srcAccessMask, - .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, - .oldLayout = vk::ImageLayout::eGeneral, - .newLayout = vk::ImageLayout::eGeneral, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), - .subresourceRange = vk::ImageSubresourceRange - { - .aspectMask = resource->imageAspectFlags, - .baseMipLevel = 0, - .levelCount = resource->mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - } - }); - } - - ++i; - } + InitializeBarriers(); } void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span perFrameSizes) noexcept diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index dc3ca886..476099c7 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -73,6 +73,18 @@ namespace SHADE //! Name of this node std::string name; + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource (uint64_t resourceHandleID) const noexcept; + void InitializeBarriers (void) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetFollowingEndRenderpass (uint32_t flag) noexcept; + public: SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 3d2b1699..1f03bbc4 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -265,42 +265,24 @@ namespace SHADE */ /***************************************************************************/ - void SHSubpass::DetachResource(std::string const& resourceName, uint32_t attachmentIndex) noexcept + bool SHSubpass::UsesResource(uint32_t attachmentIndex) noexcept { for (uint32_t i = 0; i < colorReferences.size(); ++i) { if (colorReferences[i].attachment == attachmentIndex) - { - colorReferences.erase (colorReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < depthReferences.size(); ++i) { if (depthReferences[i].attachment == attachmentIndex) - { - depthReferences.erase(depthReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < inputReferences.size(); ++i) { if (inputReferences[i].attachment == attachmentIndex) - { - inputReferences.erase(inputReferences.begin() + i); - break; - } - } - - for (uint32_t i = 0; i < inputNames.size(); ++i) - { - if (inputNames[i] == resourceName) - { - inputNames.erase(inputNames.begin() + i); - break; - } + return true; } } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 6c582aa6..7f1bd3da 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -95,6 +95,12 @@ namespace SHADE std::string name; + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource(uint32_t attachmentIndex) noexcept; + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ @@ -119,7 +125,6 @@ namespace SHADE void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; void BindInputDescriptorSets (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; - void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept; bool HasNoAttachments (void) const noexcept; void Init(SHResourceHub& resourceManager) noexcept; From 6f55f202b9a65608c6fe3cb82b8113619483e0ad Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 16:53:13 +0800 Subject: [PATCH 056/134] 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. From 50de3a8ef07a6acd515ab0292257eb64532a53d6 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 17:15:49 +0800 Subject: [PATCH 057/134] 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 From 7a92c2c86f09ed57abd980f1218962f070c7afb7 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 17:23:06 +0800 Subject: [PATCH 058/134] 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: From ddfbc71400d176e14fd6d57d4222620ae04e8a82 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 1 Jan 2023 19:39:16 +0800 Subject: [PATCH 059/134] 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; }; From 7f8dc2b6478296a7cf71053de1916acac9a4ffb8 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 2 Jan 2023 18:24:29 +0800 Subject: [PATCH 060/134] Added constants for render graph node names - Fleshed out event function to add resource and subpass to shadow map render graph node when shadow is turned on - Added support for linking resources and subpasses to render graph at runtime --- SHADE_Engine/src/Editor/SHEditor.cpp | 4 +- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 4 +- .../MiddleEnd/Interface/SHGraphicsConstants.h | 133 +++++++++-------- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 48 ++++--- .../MiddleEnd/Interface/SHGraphicsSystem.h | 6 +- .../Graphics/RenderGraph/SHRenderGraph.cpp | 60 +------- .../src/Graphics/RenderGraph/SHRenderGraph.h | 9 +- .../RenderGraph/SHRenderGraphNode.cpp | 136 ++++++++++++++++++ .../Graphics/RenderGraph/SHRenderGraphNode.h | 19 ++- 9 files changed, 266 insertions(+), 153 deletions(-) diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 93b42418..f3fe6b72 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -502,7 +502,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass(); + auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) { @@ -521,7 +521,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index b57249de..fc701da3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,7 +101,7 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); + auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); @@ -125,7 +125,7 @@ namespace SHADE } cmdBuffer->EndLabeledSegment(); }); - auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); + auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index c889a321..f331ce02 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,68 +31,79 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - //struct DescriptorSetIndex - //{ - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for static global values like generic data, and - // texture samplers - // */ - // /***************************************************************************/ - // static constexpr uint32_t STATIC_GLOBALS = 0; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for dynamic global values like lights. - // */ - // /***************************************************************************/ - // static constexpr uint32_t DYNAMIC_GLOBALS = 1; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for high frequency changing global values like - // camera matrices. - // */ - // /***************************************************************************/ - // static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for per-instance/material changing values. - // */ - // /***************************************************************************/ - // static constexpr uint32_t PER_INSTANCE = 3; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph resources. Unlike the sets from - // 1 to 3 and 6, this set index does not have hard coded bindings and is - // NOT part of the layouts included in the global data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph node compute resources. For data - // that we wish to pass to compute shaders in the render graph, this is - // the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have - // hard coded bindings and is NOT part of the layouts included in the global - // data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5; + struct RenderGraphNodeNames + { + /***************************************************************************/ + /*! + + \brief + Name of G-Buffer render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view GBUFFER_PASS = "G-Buffer"; - // /***************************************************************************/ - // /*! - // \brief - // To store font data. - // - // */ - // /***************************************************************************/ - // static constexpr uint32_t FONT_DATA = 4; - //}; + /***************************************************************************/ + /*! + + \brief + Name of shadow map render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw with Depth render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of screen space pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of ImGui pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view IMGUI_PASS = "ImGui Pass"; + + }; struct DescriptorSetBindings { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 18d79579..2ad41151 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -44,6 +44,8 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" +#include "Events/SHEvent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" namespace SHADE { @@ -198,7 +200,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* MAIN NODE */ /*-----------------------------------------------------------------------*/ - auto gBufferNode = renderGraph->AddNode("G-Buffer", + auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), + //auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data() { "Position", "Entity ID", @@ -259,13 +262,13 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. // It will initially also not have any subpasses since they will be added for each light that casts shadows. - auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {}); + auto shadowMapPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ /*-----------------------------------------------------------------------*/ // This pass will facilitate both lighting and shadows in 1 single pass. - auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass", + auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), { "Position", "Light Layer Indices", @@ -274,7 +277,7 @@ namespace SHADE "Scene", "SSAO Blur" }, - {"G-Buffer"}); + { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ @@ -286,19 +289,19 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - Depth Tested - auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"}); + auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data()}); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - No Depth Test - auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" }); + auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data()}); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* SCREEN SPACE PASS */ /*-----------------------------------------------------------------------*/ - auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" }); + auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data()}); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -313,16 +316,16 @@ namespace SHADE #ifdef SHEDITOR { // Dummy Node to transition scene render graph resource - auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" }); + auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); dummySubpass->AddInput("Scene"); - auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {}); + auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data(), {"Present"}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -396,7 +399,7 @@ namespace SHADE textRenderingSubSystem = resourceManager.Create(); // initialize the text renderer - auto uiNode = renderGraph->GetNode("Screen Space Pass"); + auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data()); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -423,7 +426,7 @@ namespace SHADE defaultMaterial = AddMaterial ( defaultVertShader, defaultFragShader, - renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write") + renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") ); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); } @@ -724,16 +727,29 @@ namespace SHADE renderers.erase(iter); } - SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept + SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept { + // we need to wait for the device to finish using the graph first + device->WaitIdle(); + + auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; + auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); + std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + // Add the shadow map resource to the graph + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. + auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + shadowMapNode->RuntimeLinkResource(resourceName); // Add a subpass to render to that shadow map + shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, worldRenderer); + + // regenerate the node + //shadowMapNode->RuntimeStandaloneRegenerate(); - //renderGraph->GetNode (); - return event->handle; + return eventPtr->handle; } Handle SHGraphicsSystem::AddMaterial(Handle vertShader, Handle fragShader, Handle subpass) @@ -1076,7 +1092,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 40148e05..88d66ded 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -177,7 +177,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* Light functions */ /*-----------------------------------------------------------------------*/ - SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; + SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept; /*-----------------------------------------------------------------------------*/ /* Material Functions */ @@ -405,10 +405,6 @@ namespace SHADE SHWindow* GetWindow() noexcept { return window; } private: - /*-----------------------------------------------------------------------------*/ - /* Constants */ - /*-----------------------------------------------------------------------------*/ - static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer"; /*-----------------------------------------------------------------------------*/ /* Data Members */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index e9a0e0bd..e6b9ae33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -169,65 +169,7 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is final layout. - std::unordered_map resourceAttFinalLayouts; - if (!node->subpasses.empty()) - { - // We first want to take all resources track their layout as undefined at the start of the node/renderpass - auto const resources = node->GetResources(); - for (auto& resource : resources) - { - resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); - } - - // attempt to get all final layouts for all resources - for (auto& subpass : node->subpasses) - { - for (auto& color : subpass->colorReferences) - { - // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass - if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) - resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; - else - resourceAttFinalLayouts[color.attachment] = color.layout; - - node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); - } - - for (auto& depth : subpass->depthReferences) - { - resourceAttFinalLayouts[depth.attachment] = depth.layout; - node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); - } - - for (auto& input : subpass->inputReferences) - { - resourceAttFinalLayouts[input.attachment] = input.layout; - node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); - } - } - - for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) - { - auto& att = node->attachmentDescriptions[j]; - auto& resource = node->attResources[j]; - - // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. - // We also want to load the attachment, not "don't care". - if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && - renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) - { - att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw); - att.loadOp = vk::AttachmentLoadOp::eLoad; - att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; - } - else - att.initialLayout = vk::ImageLayout::eUndefined; - - att.finalLayout = resourceAttFinalLayouts[j]; - resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); - } - } + node->StandaloneConfigureAttDesc(i == nodes.size() - 1); ++i; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 7dc19a80..6dbc4308 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -164,7 +164,14 @@ namespace SHADE * that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph, * but different matrices (SHRenderer) can be used in different nodes. * - There are also way too many hash maps created for ease of access. This definitely can be cut down. - * - + * - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted + * for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses + * while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other + * than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as + * whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later + * be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as + * if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any + * other node. * */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 56d8734a..cc9d61a9 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -495,6 +495,68 @@ namespace SHADE } } + void SHRenderGraphNode::StandaloneConfigureAttDesc(bool isLastNode) noexcept + { + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; + if (!subpasses.empty()) + { + // We first want to take all resources track their layout as undefined at the start of the node/renderpass + for (auto& resource : attResources) + { + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, vk::ImageLayout::eUndefined); + } + + // attempt to get all final layouts for all resources + for (auto& subpass : subpasses) + { + for (auto& color : subpass->colorReferences) + { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass + if (isLastNode && (attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + else + resourceAttFinalLayouts[color.attachment] = color.layout; + + attResources[color.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, color.layout); + } + + for (auto& depth : subpass->depthReferences) + { + resourceAttFinalLayouts[depth.attachment] = depth.layout; + attResources[depth.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, depth.layout); + } + + for (auto& input : subpass->inputReferences) + { + resourceAttFinalLayouts[input.attachment] = input.layout; + attResources[input.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, input.layout); + } + } + + for (uint32_t j = 0; j < attachmentDescriptions.size(); ++j) + { + auto& att = attachmentDescriptions[j]; + auto& resource = attResources[j]; + + // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. + // We also want to load the attachment, not "don't care". + if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && + graphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) + { + att.initialLayout = graphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw); + att.loadOp = vk::AttachmentLoadOp::eLoad; + att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; + } + else + att.initialLayout = vk::ImageLayout::eUndefined; + + att.finalLayout = resourceAttFinalLayouts[j]; + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, att.finalLayout); + } + } + } + /***************************************************************************/ /*! @@ -521,6 +583,9 @@ namespace SHADE // remove attachment reference attachmentDescriptions.erase (attachmentDescriptions.begin() + index); + // erase from mapping as well + resourceAttachmentMapping->erase(resourceHandleID); + // Remove footprint of attachment from all subpasses as well for (auto it = subpasses.begin(); it != subpasses.end(); ++it) { @@ -629,6 +694,77 @@ namespace SHADE batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); } + /***************************************************************************/ + /*! + + \brief + This function simply appends to the container of VkAttachmentDescription + and attResources. It will assume the resource is used standalone in the + node and will not account for its usage in other nodes. As such its + initialLayout will always be UNDEFINED and its finalLayout will be + whatever is calculated if the node is regenerated using + StandaloneRegnerate. This function also does not affect the render graph + while its running since the 2 containers above have already been copied + to the GPU. + + \param resourceName + The name of the resource for getting the resource. + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeLinkResource(std::string resourceName) noexcept + { + // Get new resource + Handle newResource = graphStorage->graphResources->at(resourceName); + + // append new resource to container + attResources.push_back(newResource); + + attachmentDescriptions.push_back(vk::AttachmentDescription + { + .format = newResource->GetResourceFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eClear, + .stencilStoreOp = vk::AttachmentStoreOp::eStore, + }); + + resourceAttachmentMapping->try_emplace(newResource.GetId().Raw, attachmentDescriptions.size() - 1); + } + + void SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept + { + AddSubpass(std::move (subpassName), viewport, renderer); + } + + /***************************************************************************/ + /*! + + \brief + USE WITH CAUTION because the function does not reevaluate resource + layouts in attachment descriptions. All resources here will start at + UNDEFINED and end at whatever the last subpass using the attachment + specifies. It will also not support render graph node computes given its + complexity if it has to be accounted for. + + IN SHORT, IT GENERATES A RENDERPASS AS IF ITS THE ONLY NODE + IN THE RENDER GRAPH. SEE NOTES IN SHRenderGraph.h + + This function is mainly meant for nodes that are dynamic (in hindsight, + there really should have been a distinction between static and dynamic + nodes). + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeStandaloneRegenerate(void) noexcept + { + StandaloneConfigureAttDesc(false); + ConfigureSubpasses(); + CreateRenderpass(); + CreateFramebuffer(); + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index a581d21c..d8e4caa4 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -93,6 +93,9 @@ namespace SHADE void CreateFramebuffer(void) noexcept; void HandleResize (void) noexcept; void ConfigureSubpasses (void) noexcept; + bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept; + void AddDummySubpassIfNeeded(void) noexcept; + void StandaloneConfigureAttDesc (bool isLastNode) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -105,15 +108,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; - void AddDummySubpassIfNeeded (void) noexcept; - bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept; + + void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); - // TODO: RemoveSubpass() - void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex, Handle descPool); + // Runtime functions that don't affect the renderpass + void RuntimeLinkResource(std::string resourceName) noexcept; + void RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + void RuntimeStandaloneRegenerate (void) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ From ef8867a7a55f9773e34f76362888f92ae9803efd Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 2 Jan 2023 22:16:35 +0800 Subject: [PATCH 061/134] Shadows WIP --- .../Descriptors/SHVkDescriptorSetGroup.cpp | 15 ++++ .../Descriptors/SHVkDescriptorSetGroup.h | 1 + .../GlobalData/SHGraphicsPredefinedData.cpp | 14 ++++ .../GlobalData/SHGraphicsPredefinedData.h | 1 + .../MiddleEnd/Interface/SHGraphicsConstants.h | 9 +++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 6 +- .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 55 +++++++++++++- .../MiddleEnd/Lights/SHLightingSubSystem.h | 76 +++++++++++++------ 8 files changed, 153 insertions(+), 24 deletions(-) diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index e77234ca..7c5c0e48 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -177,6 +177,21 @@ namespace SHADE } } + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept + { + // Find the target writeDescSet + BindingAndSetHash writeHash = binding; + writeHash |= static_cast(set) << 32; + auto& writeInfo = updater.writeInfos[updater.writeHashMap.at(writeHash)]; + + // write sampler and image view + auto& [view, sampler, layout] = imageViewAndSampler; + writeInfo.descImageInfos[descIndex].imageView = view->GetImageView(); + writeInfo.descImageInfos[descIndex].sampler = sampler ? sampler->GetVkSampler() : nullptr; + writeInfo.descImageInfos[descIndex].imageLayout = layout; + + } + void SHVkDescriptorSetGroup::ModifyWriteDescBuffer(uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept { // Find the target writeDescSet diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index a228bc66..4538b271 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -67,6 +67,7 @@ namespace SHADE void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index ffe29b36..d09ec5b4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -150,12 +150,26 @@ namespace SHADE Handle fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding }); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data"); + // descriptor binding for storing shadow maps + SHVkDescriptorSetLayout::Binding shadowMapBinding + { + .Type = vk::DescriptorType::eCombinedImageSampler, + .Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + .DescriptorCount = 200, // we can have up to 2000 textures for now + .flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount, + }; + + // For global data (generic data and textures) + Handle shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding }); + SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps"); predefinedLayouts.push_back(staticGlobalLayout); predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(cameraDataGlobalLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(fontDataDescSetLayout); + predefinedLayouts.push_back(shadowMapDescLayout); perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts ( diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h index 11bfc469..b4004d5a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h @@ -28,6 +28,7 @@ namespace SHADE CAMERA = 0x04, MATERIALS = 0x08, FONT = 0x10, + SHADOW = 0x20, }; enum class SystemType diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index f331ce02..b061dde3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -169,6 +169,15 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t FONT_MATRIX_DATA = 1; + /***************************************************************************/ + /*! + \brief + Descriptor set binding for shadow map images. + + */ + /***************************************************************************/ + static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 2ad41151..6647ea74 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -394,7 +394,11 @@ namespace SHADE postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); lightingSubSystem = resourceManager.Create(); - lightingSubSystem->Init(device, descPool); + lightingSubSystem->Init(device, descPool, samplerCache.GetSampler (device, SHVkSamplerParams + { + // nothing for now + }) + ); textRenderingSubSystem = resourceManager.Create(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index ddacf3a7..7a4a3203 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -10,6 +10,9 @@ #include "SHLightComponent.h" #include "Math/Vector/SHVec4.h" #include "Math/SHMatrix.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h" +#include "Graphics/Images/SHVkSampler.h" namespace SHADE { @@ -365,6 +368,11 @@ namespace SHADE } } + void SHLightingSubSystem::UpdateShadowMapDesc(void) noexcept + { + + } + /***************************************************************************/ /*! @@ -375,13 +383,14 @@ namespace SHADE */ /***************************************************************************/ - void SHLightingSubSystem::Init(Handle device, Handle descPool) noexcept + void SHLightingSubSystem::Init(Handle device, Handle descPool, Handle inShadowMapSampler) noexcept { SHComponentManager::CreateComponentSparseSet(); logicalDevice = device; uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); +#pragma region LIGHTING std::vector variableSizes{ NUM_LIGHT_TYPES }; std::fill (variableSizes.begin(), variableSizes.end(), 1); @@ -418,7 +427,21 @@ namespace SHADE dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count } +#pragma endregion + +#pragma region SHADOWS + std::vector shadowDescVariableSizes{ MAX_SHADOWS }; + shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); + +#ifdef _DEBUG + const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); + for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) + SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); +#endif + + shadowMapSampler = inShadowMapSampler; //numLightComponents = 0; +#pragma endregion } /***************************************************************************/ @@ -526,6 +549,36 @@ namespace SHADE } + void SHLightingSubSystem::AddShadowMap(Handle newShadowMap) noexcept + { + // Add to container of shadow maps + shadowMaps.emplace_back(newShadowMap); + + // Just use the image view stored in the resource + Handle const NEW_IMAGE_VIEW = newShadowMap->GetImageView(); + + // Prepare to write to descriptor + shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); + + static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; + uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = shadowMapImageSamplers.size() - 1; + shadowMapDescriptorSet->ModifyWriteDescImage + ( + SHADOW_MAP_DESC_SET_INDEX, + SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, + shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], + SHADOW_MAP_DESC_ARRAY_INDEX + ); + + // TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array + shadowMapDescriptorSet->UpdateDescriptorSetImages + ( + SHADOW_MAP_DESC_SET_INDEX, + SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA + ); + + } + Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept { return lightingDataDescSet; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index fa103136..ec42193a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -6,6 +6,7 @@ #include "SHLightData.h" #include #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/RenderGraph/SHRenderGraphResource.h" namespace SHADE { @@ -16,6 +17,9 @@ namespace SHADE class SHVkBuffer; class SHLightComponent; class SHVkCommandBuffer; + class SHSamplerCache; + class SHVkImageView; + class SHVkSampler; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. struct SHDirectionalLightData @@ -69,7 +73,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t STARTING_NUM_LIGHTS = 50; + static constexpr uint32_t STARTING_NUM_LIGHTS = 50; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -123,50 +127,78 @@ namespace SHADE }; private: + /*-----------------------------------------------------------------------*/ + /* STATIC MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + + static constexpr uint32_t MAX_SHADOWS = 200; //! logical device used for creation - Handle logicalDevice; + Handle logicalDevice; //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required. - Handle lightingDataDescSet; - - //! Each type will have some data associated with it for processing - std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; - - //! Container to store dynamic offsets for binding descriptor sets - DynamicOffsetArray dynamicOffsets; - - //! holds the data that represents how many lights are in the scene - std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; - - //! GPU buffer to hold lightCountData - Handle lightCountsBuffer; - - //! For padding in the buffer - uint32_t lightCountsAlignedSize; + Handle lightingDataDescSet; + + //! Each type will have some data associated with it for processing + std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; + + //! Container to store dynamic offsets for binding descriptor sets + DynamicOffsetArray dynamicOffsets; + + //! holds the data that represents how many lights are in the scene + std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; + + //! GPU buffer to hold lightCountData + Handle lightCountsBuffer; + + //! For padding in the buffer + uint32_t lightCountsAlignedSize; //! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more, //! don't do anything. //uint32_t numLightComponents; + //! Handle to sampler that all shadow map descriptors will use + Handle shadowMapSampler; + + //! Shadow maps for every light that casts a shadow + std::vector> shadowMaps; + + //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. + //! It will also be preallocated. + Handle shadowMapDescriptorSet; + + //! Combined image samplers for the texture descriptors + std::vector, Handle, vk::ImageLayout>> shadowMapImageSamplers; + + //! Barriers required to transition the resources from whatever layout they are in (probably from VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + //! to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + std::vector shadowMapMemoryBarriers; + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ void UpdateDescSet (uint32_t binding) noexcept; void ComputeDynamicOffsets (void) noexcept; void ResetNumLights (void) noexcept; + void UpdateShadowMapDesc (void) noexcept; public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool) noexcept; - void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; - void Exit (void) noexcept; + void Init (Handle device, Handle descPool, Handle inShadowMapSampler) noexcept; + void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; + void Exit (void) noexcept; + void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + void AddShadowMap (Handle newShadowMap) noexcept; + //void RemoveShadowMap (uint32_t index) noexcept; - void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; }; From 58a44997b2dd50a63e5fc57f6e1a0123110eb417 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 2 Jan 2023 22:31:48 +0800 Subject: [PATCH 062/134] 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 */ /*-----------------------------------------------------------------------------*/ From 1f2a9820d1cc96a7d78e2842969a04e8f7c27cc4 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 2 Jan 2023 22:49:12 +0800 Subject: [PATCH 063/134] 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(); From b771cdbfc6a0f0a96fba73a1e69d85c18d69af48 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 3 Jan 2023 07:41:37 +0800 Subject: [PATCH 064/134] Added barrier for shadow maps --- .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 7a4a3203..87b2ab62 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -560,6 +560,7 @@ namespace SHADE // Prepare to write to descriptor shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); + // Update descriptor set static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = shadowMapImageSamplers.size() - 1; shadowMapDescriptorSet->ModifyWriteDescImage @@ -577,6 +578,23 @@ namespace SHADE SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA ); + // add to barriers + shadowMapMemoryBarriers.push_back (vk::ImageMemoryBarrier + { + .oldLayout = vk::ImageLayout::eDepthAttachmentOptimal, + .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = newShadowMap->GetImage()->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); } Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept From 1b5024793ca71587230f711c91be8f2b3250d27f Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 10:14:39 +0800 Subject: [PATCH 065/134] 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 */ From 0460d776b09d0cb21166d708ec375a4ff3b9d621 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 10:40:02 +0800 Subject: [PATCH 066/134] 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(); } From b2645fb584009c22383dab40f1cd1ca108f103c8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 18:53:21 +0800 Subject: [PATCH 067/134] 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; From f7e867098dff21acd65bbbfb4a25ce0b1cae967e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Tue, 3 Jan 2023 20:30:20 +0800 Subject: [PATCH 068/134] 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(); From 87b2103f6eb48b02ff95c449b28c52599e33cdf6 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 3 Jan 2023 22:05:36 +0800 Subject: [PATCH 069/134] Shadows WIP --- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 7 +++++++ .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 11 ++++++++--- .../MiddleEnd/Lights/SHLightingSubSystem.h | 17 ++++++++++------- .../RenderGraph/SHRenderGraphNode.cpp | 4 ++-- .../Graphics/RenderGraph/SHRenderGraphNode.h | 2 +- .../RenderGraph/SHRenderGraphNodeCompute.cpp | 19 ++++++++++++++++--- .../RenderGraph/SHRenderGraphNodeCompute.h | 2 +- 7 files changed, 45 insertions(+), 17 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 6647ea74..98c897f3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -279,6 +279,13 @@ namespace SHADE }, { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()}); + // Add subpass with exterior draw call to transition shadow maps + //auto shadowMapTransitionSubpass = deferredCompositeNode->AddSubpass("Shadow Map Transition", {}, {}); + //shadowMapTransitionSubpass->AddExteriorDrawCalls([=](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) + // { + // lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); + // }); + /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 87b2ab62..997fe68a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -526,7 +526,6 @@ namespace SHADE // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing. ComputeDynamicOffsets(); - } /***************************************************************************/ @@ -549,10 +548,10 @@ namespace SHADE } - void SHLightingSubSystem::AddShadowMap(Handle newShadowMap) noexcept + void SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept { // Add to container of shadow maps - shadowMaps.emplace_back(newShadowMap); + shadowMaps.emplace(lightEntity, newShadowMap); // Just use the image view stored in the resource Handle const NEW_IMAGE_VIEW = newShadowMap->GetImageView(); @@ -597,6 +596,12 @@ namespace SHADE }); } + void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept + { + // Issue barrier to transition shadow maps for reading in compute shader + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, shadowMapMemoryBarriers); + } + Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept { return lightingDataDescSet; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index ec42193a..65b58174 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -7,6 +7,7 @@ #include #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/RenderGraph/SHRenderGraphResource.h" +#include "ECS_Base/SHECSMacros.h" namespace SHADE { @@ -162,8 +163,9 @@ namespace SHADE //! Handle to sampler that all shadow map descriptors will use Handle shadowMapSampler; - //! Shadow maps for every light that casts a shadow - std::vector> shadowMaps; + //std::vector> shadowMaps; + //! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it + std::unordered_map> shadowMaps; //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. //! It will also be preallocated. @@ -189,11 +191,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool, Handle inShadowMapSampler) noexcept; - void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; - void Exit (void) noexcept; - void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; - void AddShadowMap (Handle newShadowMap) noexcept; + void Init (Handle device, Handle descPool, Handle inShadowMapSampler) noexcept; + void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; + void Exit (void) noexcept; + void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + void AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; + void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; //void RemoveShadowMap (uint32_t index) noexcept; /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index cc9d61a9..122f41da 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -431,7 +431,7 @@ namespace SHADE return subpass; } - Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept + Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, Handle customComputeLayout/* = {}*/, float numWorkGroupScale/* = 1.0f*/) noexcept { // Look for the required resources in the graph std::vector> nodeComputeResources{}; @@ -447,7 +447,7 @@ namespace SHADE std::vector> temp (nodeComputeResources); // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), customComputeLayout); nodeComputes.push_back(nodeCompute); for (auto& resource : temp) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index d8e4caa4..8744184f 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -109,7 +109,7 @@ namespace SHADE /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; - Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; + Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, Handle customComputeLayout = {}, float numWorkGroupScale = 1.0f) noexcept; void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index e1bc3842..fd46cfe7 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -62,7 +62,8 @@ namespace SHADE followingEndRenderpass = flag; } - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept + + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, Handle customComputeLayout, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} @@ -116,10 +117,22 @@ namespace SHADE // check if all layouts are there if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) { + Handle computeResourceLayout = {}; + uint32_t variableCounts = 0; + if (customComputeLayout) + { + // Just use the descriptor counts in bindings as the variable descriptor counts + auto const& bindings = customComputeLayout->GetBindings(); + variableCounts = bindings.back().DescriptorCount; + computeResourceLayout = customComputeLayout; + } + else + computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; + + // create compute resources computeResource = graphStorage->resourceHub->Create(); - auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; - computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 }); + computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableCounts}); #ifdef _DEBUG for (auto set : computeResource->descSet->GetVkHandle()) SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index 476099c7..5f68cf2c 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -86,7 +86,7 @@ namespace SHADE void SetFollowingEndRenderpass (uint32_t flag) noexcept; public: - SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, Handle customComputeLayout, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; From db87bea002395ecfc632d240b602c9a39aedb52c Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Wed, 4 Jan 2023 09:58:29 +0800 Subject: [PATCH 070/134] Added pre compute functions for render graph node compute --- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 15 ++++---- .../RenderGraph/SHRenderGraphNode.cpp | 22 ++++++++---- .../RenderGraph/SHRenderGraphNodeCompute.cpp | 10 ++++++ .../RenderGraph/SHRenderGraphNodeCompute.h | 8 +++++ .../src/Graphics/RenderGraph/SHSubpass.cpp | 35 ++++++++++--------- 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 98c897f3..19a24e0c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -262,7 +262,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. // It will initially also not have any subpasses since they will be added for each light that casts shadows. - auto shadowMapPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {}); + auto shadowMapPassNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ @@ -279,17 +279,16 @@ namespace SHADE }, { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()}); - // Add subpass with exterior draw call to transition shadow maps - //auto shadowMapTransitionSubpass = deferredCompositeNode->AddSubpass("Shadow Map Transition", {}, {}); - //shadowMapTransitionSubpass->AddExteriorDrawCalls([=](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) - // { - // lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); - // }); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); + deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) + { + lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); + }); + /*-----------------------------------------------------------------------*/ /* DEBUG DRAW PASS INIT */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 122f41da..cf4623e6 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -129,20 +129,25 @@ namespace SHADE if (subpasses.empty()) return; + uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle subpass) {return !subpass->HasNoAttachments();}); + // Create subpass description and dependencies based on number of subpasses - spDescs.resize(subpasses.size()); - spDeps.resize(subpasses.size()); + spDescs.resize(numValidSubpasses); + spDeps.resize(numValidSubpasses); // Now we want to loop through all attachments in all subpasses in the node and query // the resources being used. For each resource we want to query the type and record it // in bit fields (1 bit for each subpass). uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0; - uint32_t i = 0; // For all subpasses (see above description about bit field for this). - for (auto& subpass : subpasses) + for (uint32_t i = 0; auto& subpass : subpasses) { + // skip if subpass is not valid + if (subpass->HasNoAttachments()) + continue; + // Configure subpass description auto& desc = spDescs[i]; desc.pColorAttachments = subpass->colorReferences.data(); @@ -198,8 +203,11 @@ namespace SHADE // Loop through all subpasses again but this time we use the bit field to initialize // the dependencies. - for (i = 0; i < subpasses.size(); ++i) + for (uint32_t i = 0; auto & subpass : subpasses) { + if (subpass->HasNoAttachments()) + continue; + vk::PipelineStageFlags srcStage; vk::PipelineStageFlags dstStage; vk::AccessFlags srcAccess; @@ -257,6 +265,8 @@ namespace SHADE // initialize input descriptors subpasses[i]->CreateInputDescriptors(); + + ++i; } } @@ -639,7 +649,7 @@ namespace SHADE subpasses[i]->Execute(commandBuffer, descPool, frameIndex); // Go to next subpass if not last subpass - if (i != static_cast(subpasses.size()) - 1u) + if (i != static_cast(subpasses.size()) - 1u && !subpasses[i]->HasNoAttachments()) commandBuffer->NextSubpass(); } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index fd46cfe7..55f8a9c9 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -152,6 +152,11 @@ namespace SHADE void SHRenderGraphNodeCompute::Execute(Handle cmdBuffer, uint32_t frameIndex) noexcept { + for (auto& fn : preComputeFunctions) + { + fn (cmdBuffer, frameIndex); + } + // bind the compute pipeline cmdBuffer->BindPipeline(computePipeline); @@ -252,4 +257,9 @@ namespace SHADE } + void SHRenderGraphNodeCompute::AddPreComputeFunction(PreComputeFunction const& fn) noexcept + { + preComputeFunctions.push_back(fn); + } + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index 5f68cf2c..9352f1d9 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -25,6 +25,10 @@ namespace SHADE class SHRenderGraphNodeCompute { + public: + using PreComputeFunction = std::function, uint32_t)>; + + private: // Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE struct ComputeResource @@ -73,6 +77,9 @@ namespace SHADE //! Name of this node std::string name; + std::vector preComputeFunctions; + + private: /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ @@ -97,6 +104,7 @@ namespace SHADE void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span const& viewSamplerLayouts) noexcept; + void AddPreComputeFunction (PreComputeFunction const& fn) noexcept; friend class SHRenderGraph; friend class SHRenderGraphNode; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 1f03bbc4..c7982906 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -211,25 +211,28 @@ namespace SHADE { commandBuffer->BeginLabeledSegment(name); - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex, descPool); - - if (viewport) + if (!HasNoAttachments()) { - // set viewport and scissor - uint32_t w = static_cast(viewport->GetWidth()); - uint32_t h = static_cast(viewport->GetHeight()); - commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + if (viewport) + { + // set viewport and scissor + uint32_t w = static_cast(viewport->GetWidth()); + uint32_t h = static_cast(viewport->GetHeight()); + commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + } + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); + + if (renderer) + renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); + + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); } - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); - - if (renderer) - renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - // Draw all the exterior draw calls for (auto& drawCall : exteriorDrawCalls) { From a49c674c2b445032ff2bb1f159c16b3c97abb728 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 4 Jan 2023 15:03:58 +0800 Subject: [PATCH 071/134] 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); } From dd2fc934a2dd6c12439dea9d49fbe8bae891895c Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 4 Jan 2023 17:48:08 +0800 Subject: [PATCH 072/134] 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; From dffdec9d9c428573ecb3c6dfe2cae0ad4cd68055 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Wed, 4 Jan 2023 19:45:41 +0800 Subject: [PATCH 073/134] 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++)); } } From c484a088fdc13471a1e16d057dae61409ebeec76 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 01:12:25 +0800 Subject: [PATCH 074/134] 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: /*---------------------------------------------------------------------------------*/ From 68e11ba48ed0d27d7ea78fc180738b787920acd9 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 13:42:17 +0800 Subject: [PATCH 075/134] 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 From 016f6c804da9cb64c3721bcbdb5191e1ae2120bd Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 14:40:06 +0800 Subject: [PATCH 076/134] 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; From 0c92e7ff6cee8ff37d9da3d7c52e4fe270915635 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 14:40:06 +0800 Subject: [PATCH 077/134] 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; From 8ca4045d555d3002d66ff6d358c758dd606b0145 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Thu, 5 Jan 2023 17:53:48 +0800 Subject: [PATCH 078/134] 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; + +} From 19f9b67550a53b8e2f660e59053a86a42882c64c Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Fri, 6 Jan 2023 10:40:19 +0800 Subject: [PATCH 079/134] Shadow map WIP - Added companion subpass object to subpass - Lighting sub system updates a light's renderer when it is a valid handle - Light component's renderer will be created in the graphics system event when a light's shadow is enabled --- Assets/Shaders/ShadowMap_VS.glsl | 21 +++++++++++ .../src/Graphics/Events/SHGraphicsEvents.h | 3 ++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 26 +++++++++++-- .../Graphics/MiddleEnd/Interface/SHRenderer.h | 2 +- .../MiddleEnd/Lights/SHLightComponent.cpp | 13 +++++++ .../MiddleEnd/Lights/SHLightComponent.h | 7 ++++ .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 37 ++++++++++++++++++- .../MiddleEnd/Lights/SHLightingSubSystem.h | 7 +++- .../RenderGraph/SHRenderGraphNode.cpp | 4 +- .../Graphics/RenderGraph/SHRenderGraphNode.h | 2 +- .../src/Graphics/RenderGraph/SHSubpass.cpp | 6 +++ .../src/Graphics/RenderGraph/SHSubpass.h | 35 ++++++++++++++---- 12 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 Assets/Shaders/ShadowMap_VS.glsl diff --git a/Assets/Shaders/ShadowMap_VS.glsl b/Assets/Shaders/ShadowMap_VS.glsl new file mode 100644 index 00000000..bf353eb5 --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.glsl @@ -0,0 +1,21 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + +//#include "ShaderDescriptorDefinitions.glsl" + + +layout(location = 0) in vec3 aVertexPos; + +layout(set = 1, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 projMat; +} cameraData; + +void main() +{ + // clip space for rendering + gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h index ab120a1f..06c480ef 100644 --- a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h +++ b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h @@ -10,5 +10,8 @@ namespace SHADE { //! We need to get the light component and initialize the relevant variables. EntityID lightEntity; + + //! Generate a renderer for the light component + bool generateRenderer; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 19a24e0c..19ad5473 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -46,6 +46,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Events/SHEvent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Input/SHInputManager.h" namespace SHADE { @@ -400,7 +401,7 @@ namespace SHADE postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); lightingSubSystem = resourceManager.Create(); - lightingSubSystem->Init(device, descPool, samplerCache.GetSampler (device, SHVkSamplerParams + lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams { // nothing for now }) @@ -557,6 +558,15 @@ namespace SHADE #endif } + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B)) + { + auto& lightComps = SHComponentManager::GetDense(); + for (auto& comp : lightComps) + { + comp.SetEnableShadow(true); + } + } + renderGraph->Begin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); @@ -746,18 +756,26 @@ namespace SHADE auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + if (EVENT_DATA->generateRenderer) + { + // Create new renderer for the light component and give it to the light component + Handle newRenderer = resourceManager.Create(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); + lightComp->SetRenderer (newRenderer); + } + // Add the shadow map resource to the graph - renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint); + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); shadowMapNode->RuntimeLinkResource(resourceName); // Add a subpass to render to that shadow map - shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, worldRenderer); + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); + newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); // regenerate the node - //shadowMapNode->RuntimeStandaloneRegenerate(); + shadowMapNode->RuntimeStandaloneRegenerate(); return eventPtr->handle; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index baf76187..a17ab1a9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -18,9 +18,9 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "SHCamera.h" #include "Resource/SHHandle.h" -#include "Graphics/RenderGraph/SHRenderGraph.h" #include "Math/SHMath.h" #include +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index 362b0e8f..4dc6e83e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -2,6 +2,7 @@ #include "SHLightComponent.h" #include "Graphics/Events/SHGraphicsEvents.h" #include "Events/SHEventManager.hpp" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" namespace SHADE { @@ -14,6 +15,7 @@ namespace SHADE //indexInBuffer = std::numeric_limits::max(); isActive = true; //Unbind(); + renderer = {}; } @@ -116,11 +118,17 @@ namespace SHADE // Create new event and broadcast it SHLightEnableShadowEvent newEvent; newEvent.lightEntity = GetEID(); + newEvent.generateRenderer = static_cast(!renderer); SHEventManager::BroadcastEvent(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); } } + void SHLightComponent::SetRenderer(Handle newRenderer) noexcept + { + renderer = newRenderer; + } + SHLightData const& SHLightComponent::GetLightData(void) const noexcept { return lightData; @@ -172,6 +180,11 @@ namespace SHADE return lightData.strength; } + Handle SHLightComponent::GetRenderer(void) const noexcept + { + return renderer; + } + } RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index 1d636595..4019d2f4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -3,9 +3,11 @@ #include #include "ECS_Base/Components/SHComponent.h" #include "SHLightData.h" +#include "Resource/SHHandle.h" namespace SHADE { + class SHRenderer; class SH_API SHLightComponent final : public SHComponent { @@ -14,6 +16,9 @@ namespace SHADE //! GPU depends on the type of the light. SHLightData lightData; + //! Renderer to calculate light world to projection matrix + Handle renderer; + //! Since the lighting system is gonna be self contained and light weight, we store this //! so that we only write this to the CPU buffer when this light component change, we don't //! rewrite everything. However we still write to the GPU buffer when everything changes. @@ -49,6 +54,7 @@ namespace SHADE //void SetBound (uint32_t inIndexInBuffer) noexcept; void SetStrength (float value) noexcept; // serialized void SetEnableShadow (bool flag) noexcept; + void SetRenderer (Handle newRenderer) noexcept; SHLightData const& GetLightData (void) const noexcept; @@ -61,6 +67,7 @@ namespace SHADE //bool GetBound (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept; float GetStrength (void) const noexcept; + Handle GetRenderer (void) const noexcept; RTTR_ENABLE() }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 997fe68a..31512f9b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -13,6 +13,9 @@ #include "Graphics/Images/SHVkImageView.h" #include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h" #include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Events/SHGraphicsEvents.h" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" +#include "Math/Transform/SHTransformComponent.h" namespace SHADE { @@ -373,6 +376,27 @@ namespace SHADE } + SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept + { + SHTransformComponent* transform = SHComponentManager::GetComponent(lightComp->GetEID()); + switch (lightComp->GetLightData().type) + { + case SH_LIGHT_TYPE::DIRECTIONAL: + return SHMatrix::LookAtRH(transform->GetLocalPosition(), lightComp->GetLightData().position, SHVec3(0.0f, 1.0f, 0.0f)); + case SH_LIGHT_TYPE::POINT: + return {}; + case SH_LIGHT_TYPE::SPOT: + return {}; + case SH_LIGHT_TYPE::AMBIENT: + return {}; + case SH_LIGHT_TYPE::NUM_TYPES: + return {}; + default: + return {}; + + } + } + /***************************************************************************/ /*! @@ -383,11 +407,12 @@ namespace SHADE */ /***************************************************************************/ - void SHLightingSubSystem::Init(Handle device, Handle descPool, Handle inShadowMapSampler) noexcept + void SHLightingSubSystem::Init(Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept { SHComponentManager::CreateComponentSparseSet(); logicalDevice = device; + resourceHub = rh; uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); #pragma region LIGHTING @@ -496,6 +521,14 @@ namespace SHADE // Light is now updated in the container //light.ClearDirtyFlag(); } + + + if (auto renderer = light.GetRenderer()) + { + //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() + renderer->UpdateDataManual (frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicRH(80.0f, 80.0f, 0.01f, 10000.0f)); + + } } // Write data to GPU @@ -561,7 +594,7 @@ namespace SHADE // Update descriptor set static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; - uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = shadowMapImageSamplers.size() - 1; + uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; shadowMapDescriptorSet->ModifyWriteDescImage ( SHADOW_MAP_DESC_SET_INDEX, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index 65b58174..320c18b7 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -178,6 +178,10 @@ namespace SHADE //! to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) std::vector shadowMapMemoryBarriers; + //! Resource hub from Graphics System + SHResourceHub* resourceHub; + + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ @@ -185,13 +189,14 @@ namespace SHADE void ComputeDynamicOffsets (void) noexcept; void ResetNumLights (void) noexcept; void UpdateShadowMapDesc (void) noexcept; + SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept; public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool, Handle inShadowMapSampler) noexcept; + void Init (Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept; void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; void Exit (void) noexcept; void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index cf4623e6..2f498d5a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -743,9 +743,9 @@ namespace SHADE resourceAttachmentMapping->try_emplace(newResource.GetId().Raw, attachmentDescriptions.size() - 1); } - void SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept + Handle SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept { - AddSubpass(std::move (subpassName), viewport, renderer); + return AddSubpass(std::move (subpassName), viewport, renderer); } /***************************************************************************/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 8744184f..27fdaa19 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -117,7 +117,7 @@ namespace SHADE // Runtime functions that don't affect the renderpass void RuntimeLinkResource(std::string resourceName) noexcept; - void RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + Handle RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; void RuntimeStandaloneRegenerate (void) noexcept; /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index c7982906..cd5bae58 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -443,6 +443,12 @@ namespace SHADE subpassIndex = index; } + void SHSubpass::SetCompanionSubpass(Handle companion, Handle pipeline) noexcept + { + companionSubpass.companion = companion; + companionSubpass.pipeline = pipeline; + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 7f1bd3da..f84d4dee 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -21,12 +21,23 @@ namespace SHADE class SHVkSampler; class SHRenderer; class SHViewport; + class SHVkPipeline; class SH_API SHSubpass : public ISelfHandle { public: using ExteriorDrawCallFunction = std::function, Handle, uint32_t)>; + // Allows for subpasses to run using a companions data + struct CompanionSubpass + { + // subpass whose data will be borrowed to draw + Handle companion; + + // Pipeline that will be used for all the draw calls from all batches of the companion subpass + Handle pipeline; + }; + private: /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -94,6 +105,9 @@ namespace SHADE // For identifying subpasses std::string name; + //! Optional component to a companion subpass. If the subpass handle of this object + //! is valid, the subpass will be drawn using this companion's data. + CompanionSubpass companionSubpass; private: /*-----------------------------------------------------------------------*/ @@ -133,19 +147,24 @@ namespace SHADE void CreateInputDescriptors (void) noexcept; void UpdateWriteDescriptors (void) noexcept; - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ void SetIndex (uint32_t index) noexcept; public: - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch(void) const noexcept; + /*-----------------------------------------------------------------------*/ + /* PUBLIC SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetCompanionSubpass (Handle companion, Handle pipeline) noexcept; + + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; std::vector const& GetColorAttachmentReferences (void) const noexcept; - vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; - const std::string& GetName() const; + vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; + const std::string& GetName() const; friend class SHRenderGraphNode; friend class SHRenderGraph; From d3cd36984d879f63ee812b24e803a72d76c8094b Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sat, 7 Jan 2023 07:42:42 +0800 Subject: [PATCH 080/134] Shadow map WIP --- Assets/Shaders/ShadowMap_VS.glsl | 1 + Assets/Shaders/ShadowMap_VS.shshaderb | Bin 0 -> 1537 bytes Assets/Shaders/ShadowMap_VS.shshaderb.shmeta | 3 + .../Graphics/MiddleEnd/Batching/SHBatch.cpp | 7 +- .../src/Graphics/MiddleEnd/Batching/SHBatch.h | 2 +- .../MiddleEnd/Batching/SHSuperBatch.cpp | 4 +- .../MiddleEnd/Batching/SHSuperBatch.h | 2 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 22 +++- .../MiddleEnd/Interface/SHGraphicsSystem.h | 2 + .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 3 +- .../MiddleEnd/Pipeline/SHPipelineLibrary.cpp | 8 +- .../Graphics/Pipeline/SHVkPipelineLayout.cpp | 112 +++++++++--------- .../src/Graphics/RenderGraph/SHSubpass.cpp | 13 +- 13 files changed, 111 insertions(+), 68 deletions(-) create mode 100644 Assets/Shaders/ShadowMap_VS.shshaderb create mode 100644 Assets/Shaders/ShadowMap_VS.shshaderb.shmeta diff --git a/Assets/Shaders/ShadowMap_VS.glsl b/Assets/Shaders/ShadowMap_VS.glsl index bf353eb5..e078679e 100644 --- a/Assets/Shaders/ShadowMap_VS.glsl +++ b/Assets/Shaders/ShadowMap_VS.glsl @@ -5,6 +5,7 @@ layout(location = 0) in vec3 aVertexPos; +layout(location = 4) in mat4 worldTransform; layout(set = 1, binding = 0) uniform CameraData { diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb b/Assets/Shaders/ShadowMap_VS.shshaderb new file mode 100644 index 0000000000000000000000000000000000000000..3a8734c9daf1a50b7a6993c299eb04bab307964a GIT binary patch literal 1537 zcmZ9LTW`}q5QVq7wY0RQlwN>Rl7^dvRPg`^2?0Vaavy>kRK%-gB?c{W9LsT2;Hf{M z@RRseeL>=Uwl}i6)nshUe|`(gSeOtbKZLZJoDp4@n1 zGdqrj&gXpe=eUit6Z=b@sVQ=3R_-9O$)TNOK|Ba&Ic`txG>T@qrtZnTSxx<|$sYux zFbxiaEGV>qu@Wal`&P+C%QX2IWEBhzQyZRvIv%}~bo?ERKI@7Hl|IaZ*`JNmX!tn| z;>p)>Iw~~rJ%VC9nuRe(s%LI2=N*O~FucRi1BM2Nu?OROc*?McN8a7HtC)2p78qyp z{2YfE&W$UW9%hLZb(~wRBc`q|b7z5FtwUqAj+nX&nX3bHb=(7;oaIR~Gv1S-)5RU_ zS;X$G7c*$&@19w+)^!T!baW;?*l%jrl5fklR8L=G>NoVue^gt>dRoTUw5R`$;zfD* zV7uBeb9V+gtS#Pkd3ut6UB>w`H75AL3ORYg;kjgLBbEA7hH;u1BXw{yus+_W^2s(JNS=; zQ;YVOdI{*_PAu?CA-s?G`bFEO4E<<+BPP1GWZ*8oqdgk`sD}Jq860ppXuB^%*C%n% z)G0B!8MaqqXm`ABiJ`ME)#!d8qaHr_w(PggCHGK9e>mKM`#zTOt@)mBbxUG+|1_mn Fvi~Asj5 literal 0 HcmV?d00001 diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta new file mode 100644 index 00000000..837cec19 --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ShadowMap_VS +ID: 44646107 +Type: 2 diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 7e4069f6..fd2ccd3b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -551,7 +551,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* SHBatch - Usage Functions */ /*---------------------------------------------------------------------------------*/ - void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) + void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -566,7 +566,10 @@ namespace SHADE // Bind all required objects before drawing static std::array dynamicOffset{ 0 }; cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); - cmdBuffer->BindPipeline(pipeline); + + if (bindBatchPipeline) + cmdBuffer->BindPipeline(pipeline); + cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); if (matPropsDescSet[frameIndex]) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d4ce068e..6d1f775f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -87,7 +87,7 @@ namespace SHADE void UpdateTransformBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex); void Build(Handle device, Handle descPool, uint32_t frameIndex) ; - void Draw(Handle cmdBuffer, uint32_t frameIndex); + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index 58993026..8006d0be 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -107,12 +107,12 @@ namespace SHADE } } - void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept + void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline /*= true*/) noexcept { // Build all batches for (auto& batch : batches) { - batch.Draw(cmdBuffer, frameIndex); + batch.Draw(cmdBuffer, frameIndex, bindBatchPipeline); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index 75bd1829..4d831b9c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -57,7 +57,7 @@ namespace SHADE void Clear() noexcept; void UpdateBuffers(uint32_t frameIndex, Handle descPool); void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; - void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true) noexcept; /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 19ad5473..ec592522 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -127,6 +127,8 @@ namespace SHADE SHFreetypeInstance::Init(); + SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMap_VS.glsl", false); + // Load Built In Shaders static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet(FS_DEFAULT); @@ -140,6 +142,8 @@ namespace SHADE static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet(TEXT_FS); static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet(RENDER_SC_VS); static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet(RENDER_SC_FS); + static constexpr AssetID SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet(SHADOW_MAP_VS); + } void SHGraphicsSystem::InitRenderGraph(void) noexcept @@ -752,9 +756,20 @@ namespace SHADE // we need to wait for the device to finish using the graph first device->WaitIdle(); - auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; - auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); - std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; + auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); + std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); + + if (!shadowMapPipeline) + { + SHPipelineLibrary tempLibrary{}; + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + + tempLibrary.Init(device); + tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, rgNode->GetRenderpass(), companionSubpass); + shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); + } if (EVENT_DATA->generateRenderer) { @@ -773,6 +788,7 @@ namespace SHADE // Add a subpass to render to that shadow map auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); + newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline // regenerate the node shadowMapNode->RuntimeStandaloneRegenerate(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 88d66ded..b8c43c75 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -464,6 +464,7 @@ namespace SHADE Handle textFS; Handle renderToSwapchainVS; Handle renderToSwapchainFS; + Handle shadowMapVS; // Fonts Handle testFont; @@ -478,6 +479,7 @@ namespace SHADE Handle debugDrawWireMeshDepthPipeline; Handle debugDrawFilledPipeline; Handle debugDrawFilledDepthPipeline; + Handle shadowMapPipeline; // initialized only when a shadow map is needed // Built-In Textures Handle defaultTexture; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 31512f9b..17cffe17 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -378,11 +378,10 @@ namespace SHADE SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept { - SHTransformComponent* transform = SHComponentManager::GetComponent(lightComp->GetEID()); switch (lightComp->GetLightData().type) { case SH_LIGHT_TYPE::DIRECTIONAL: - return SHMatrix::LookAtRH(transform->GetLocalPosition(), lightComp->GetLightData().position, SHVec3(0.0f, 1.0f, 0.0f)); + return SHMatrix::LookAtRH(lightComp->GetLightData().position, lightComp->GetLightData().position + lightComp->GetLightData().direction, SHVec3(0.0f, 1.0f, 0.0f)); case SH_LIGHT_TYPE::POINT: return {}; case SH_LIGHT_TYPE::SPOT: diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index baf09a2d..daa4d154 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -10,9 +10,15 @@ namespace SHADE Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept { + std::vector> modules{}; + if (vsFsPair.first) + modules.push_back(vsFsPair.first); + if (vsFsPair.second) + modules.push_back(vsFsPair.second); + SHPipelineLayoutParams params { - .shaderModules = {vsFsPair.first, vsFsPair.second}, + .shaderModules = std::move (modules), .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts }; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index c2d83052..325b3f56 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -19,69 +19,71 @@ namespace SHADE for (auto& shaderModule : shaderModules) { - // References for convenience - auto const& reflectedData = shaderModule->GetReflectedData(); - auto const& pcInfo = reflectedData.GetPushConstantInfo(); - - // If a push constant block exists for the shader module - if (pcInfo.memberCount != 0) + if (shaderModule) { - bool exists = false; + // References for convenience + auto const& reflectedData = shaderModule->GetReflectedData(); + auto const& pcInfo = reflectedData.GetPushConstantInfo(); - // Check if push constant block already exists - for (uint32_t i = 0; i < pcInfos.size(); ++i) + // If a push constant block exists for the shader module + if (pcInfo.memberCount != 0) { - // If there is a block with the same name, member count and size - if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + bool exists = false; + + // Check if push constant block already exists + for (uint32_t i = 0; i < pcInfos.size(); ++i) { - // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages - vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); + // If there is a block with the same name, member count and size + if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + { + // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages + vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); - // Set flag and stop checking - exists = true; - break; - } - } - - // If the block doesn't exist yet - if (!exists) - { - // Loop through all member variables of the new push constant block - for (uint32_t i = 0; i < pcInfo.memberCount; ++i) - { - std::string variableName; - variableName.reserve(50); - variableName += pcInfo.name; - variableName += "."; - variableName += pcInfo.members[i].name; - - // Add the variable's offset info to the interface - pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + // Set flag and stop checking + exists = true; + break; + } } - // New push constant range - vk::PushConstantRange newRange; + // If the block doesn't exist yet + if (!exists) + { + // Loop through all member variables of the new push constant block + for (uint32_t i = 0; i < pcInfo.memberCount; ++i) + { + std::string variableName; + variableName.reserve(50); + variableName += pcInfo.name; + variableName += "."; + variableName += pcInfo.members[i].name; - // set offset and size - newRange.offset = startOffset; - newRange.size = pcInfo.size; + // Add the variable's offset info to the interface + pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + } - // Stage flags will be whatever shader stage of the shader that contains the push constant block - newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); + // New push constant range + vk::PushConstantRange newRange; - // Add to the list foe checking later - pcInfos.push_back(&pcInfo); + // set offset and size + newRange.offset = startOffset; + newRange.size = pcInfo.size; - // For pipeline layout to consume - vkPcRanges.push_back(newRange); + // Stage flags will be whatever shader stage of the shader that contains the push constant block + newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); - // Next push constant block will start next to the previous push constant block - startOffset += pcInfo.size; + // Add to the list foe checking later + pcInfos.push_back(&pcInfo); + + // For pipeline layout to consume + vkPcRanges.push_back(newRange); + + // Next push constant block will start next to the previous push constant block + startOffset += pcInfo.size; + } + + stageFlags |= shaderModule->GetShaderStageFlagBits(); } - - stageFlags |= shaderModule->GetShaderStageFlagBits(); } - } // After all the sizes of the push constant blocks have been added, record the size in the interface @@ -132,6 +134,9 @@ namespace SHADE //! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set for (auto& shaderModule : shaderModules) { + if (!shaderModule) + continue; + auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo(); auto const& reflectedSets = descBindingInfo.GetReflectedSets(); @@ -326,11 +331,10 @@ namespace SHADE { for (auto& mod : shaderModules) { - mod->AddCallback([this]() - { - RecreateIfNeeded(); - } - ); + if (mod) + { + mod->AddCallback([this]() { RecreateIfNeeded(); }); + } } RecreateIfNeeded (); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index cd5bae58..e1277953 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -229,8 +229,17 @@ namespace SHADE if (renderer) renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); + // If companion subpass is not a valid handle, render super batch normally + if (!companionSubpass.companion) + { + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + } + else + { + commandBuffer->BindPipeline(companionSubpass.pipeline); + companionSubpass.companion->superBatch->Draw(commandBuffer, frameIndex, false); + } } // Draw all the exterior draw calls From 3e01c9e80a18870ddb1411aeae13396a7c5753f0 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sat, 7 Jan 2023 12:01:09 +0800 Subject: [PATCH 081/134] shadows WIP --- .../GlobalData/SHGraphicsPredefinedData.cpp | 14 +++- .../GlobalData/SHGraphicsPredefinedData.h | 6 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 33 +++++---- .../MiddleEnd/Pipeline/SHPipelineLibrary.cpp | 5 +- .../MiddleEnd/Pipeline/SHPipelineLibrary.h | 4 +- .../src/Graphics/Pipeline/SHPipelineState.cpp | 7 +- .../src/Graphics/Pipeline/SHPipelineState.h | 2 +- .../Graphics/RenderGraph/SHRenderGraph.cpp | 70 +++++++++++++++++++ .../src/Graphics/RenderGraph/SHRenderGraph.h | 7 ++ .../RenderGraph/SHRenderGraphNode.cpp | 1 + .../src/Graphics/RenderGraph/SHSubpass.cpp | 3 + 11 files changed, 126 insertions(+), 26 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index d09ec5b4..4082ba0f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -13,6 +13,8 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ std::vector> SHGraphicsPredefinedData::predefinedLayouts; SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState; + SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState; + std::vector SHGraphicsPredefinedData::perSystemData; //SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData; @@ -193,7 +195,7 @@ namespace SHADE ); } - void SHGraphicsPredefinedData::InitDefaultVertexInputState(void) noexcept + void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept { defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 @@ -201,13 +203,16 @@ namespace SHADE defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3 defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots) defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 + + shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)}); + shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4); // Transform at binding 4 - 7 (4 slots) } void SHGraphicsPredefinedData::Init(Handle logicalDevice) noexcept { perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES)); InitDescSetLayouts(logicalDevice); - InitDefaultVertexInputState(); + InitPredefinedVertexInputState(); InitDescMappings(); InitDummyPipelineLayouts (logicalDevice); } @@ -231,6 +236,11 @@ namespace SHADE } + SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept + { + return shadowMapVertexInputState; + } + SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept { return perSystemData[static_cast(systemType)]; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h index b4004d5a..9331ed01 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h @@ -58,6 +58,9 @@ namespace SHADE //! Default vertex input state (used by everything). static SHVertexInputState defaultVertexInputState; + //! vertex input state for shadow mapping + static SHVertexInputState shadowMapVertexInputState; + //! Predefined data for each type of system static std::vector perSystemData; @@ -73,7 +76,7 @@ namespace SHADE static void InitDescMappings (void) noexcept; static void InitDummyPipelineLayouts (Handle logicalDevice) noexcept; static void InitDescSetLayouts (Handle logicalDevice) noexcept; - static void InitDefaultVertexInputState (void) noexcept; + static void InitPredefinedVertexInputState (void) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -91,6 +94,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ static std::vector> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept; + static SHVertexInputState const& GetShadowMapViState (void) noexcept; static PerSystem const& GetSystemData (SystemType systemType) noexcept; static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept; //static PerSystem const& GetBatchingSystemData(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index ec592522..e682e0a1 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -267,7 +267,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. // It will initially also not have any subpasses since they will be added for each light that casts shadows. - auto shadowMapPassNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {}); + //auto shadowMapPassNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ @@ -760,16 +760,6 @@ namespace SHADE auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); - - if (!shadowMapPipeline) - { - SHPipelineLibrary tempLibrary{}; - Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); - - tempLibrary.Init(device); - tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, rgNode->GetRenderpass(), companionSubpass); - shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); - } if (EVENT_DATA->generateRenderer) { @@ -782,16 +772,29 @@ namespace SHADE renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. - auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); - shadowMapNode->RuntimeLinkResource(resourceName); + //auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map - auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, worldRenderer); + //auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); - newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline // regenerate the node shadowMapNode->RuntimeStandaloneRegenerate(); + + + // Create pipeline from new renderpass and subpass if it's not created yet + if (!shadowMapPipeline) + { + SHPipelineLibrary tempLibrary{}; + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + + tempLibrary.Init(device); + tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState()); + shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); + } + newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline return eventPtr->handle; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index daa4d154..6d7e6104 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -1,14 +1,13 @@ #include "SHpch.h" #include "SHPipelineLibrary.h" #include "Graphics/Devices/SHVkLogicalDevice.h" -#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" #include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/SHVkUtil.h" namespace SHADE { - Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/) noexcept { std::vector> modules{}; if (vsFsPair.first) @@ -27,7 +26,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(viState); SHColorBlendState colorBlendState{}; colorBlendState.logic_op_enable = VK_FALSE; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index 5085f21f..b7485e50 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -3,6 +3,7 @@ #include #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" namespace SHADE { @@ -32,7 +33,8 @@ namespace SHADE Handle CreateGraphicsPipelines ( std::pair, Handle> const& vsFsPair, Handle renderpass, - Handle subpass + Handle subpass, + SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState() ) noexcept; Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp index c7ada11f..49fa9086 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp @@ -195,7 +195,7 @@ namespace SHADE return *this; } - void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept + void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedAttributeLocation/* = static_cast(-1)*/) noexcept { // add a binding and get ref to it bindings.emplace_back(); @@ -228,8 +228,9 @@ namespace SHADE // The binding for that attribute description is index of the new binding created earlier in this function vertexAttrib.binding = static_cast(bindings.size() - 1); - // Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously - vertexAttrib.location = static_cast(attributes.size () - 1); + //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously + vertexAttrib.location = (fixedAttributeLocation != static_cast(-1)) ? fixedAttributeLocation + i : static_cast(attributes.size () - 1); + //vertexAttrib.location = static_cast(attributes.size() - 1); // Get the vkFormat associated with the SHAttribFormat vertexAttrib.format = format; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h index 4c8d679a..380c726e 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h @@ -34,7 +34,7 @@ namespace SHADE SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; - void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept; + void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedAttributeLocation = static_cast(-1)) noexcept; friend class SHVkPipelineState; friend class SHVkPipeline; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index e6b9ae33..5f8b8624 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -275,6 +275,17 @@ namespace SHADE } } + void SHRenderGraph::ReindexNodes(void) noexcept + { + nodeIndexing.clear(); + uint32_t i = 0; + for (auto& node : nodes) + { + nodeIndexing.emplace (node->name, i); + ++i; + } + } + /***************************************************************************/ /*! @@ -415,6 +426,65 @@ namespace SHADE return node; } + /***************************************************************************/ + /*! + + \brief + This function is purely used for dynamic nodes (if such a thing were to + exist in our architecture). In other words, don't use this function unless + the new node is fully standalone and does not rely or is a prereq of + other nodes. + + \param nodeName + Name of new node + + \param resourceInstruction + Resources for the node + + \param nodeToAddAfter + The node to add the new node after. + + \return + + */ + /***************************************************************************/ + Handle SHRenderGraph::AddNodeAfter(std::string nodeName, std::initializer_list resourceInstruction, std::string nodeToAddAfter) noexcept + { + if (nodeIndexing.contains(nodeName)) + { + SHLOG_ERROR("Node already exists, cannot add node. "); + return {}; + } + + std::vector descInitParams; + for (auto const& instruction : resourceInstruction) + { + // If the resource that the new node is requesting for exists, allow the graph to reference it + if (renderGraphStorage->graphResources->contains(instruction.resourceName)) + { + descInitParams.push_back( + { + .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName), + .dontClearOnLoad = instruction.dontClearOnLoad, + } + ); + } + else + { + SHLOG_ERROR("Resource doesn't exist in graph yet. Cannot create new node."); + return{}; + } + } + + // get target node + auto targetNode = nodes.begin() + nodeIndexing.at(nodeToAddAfter); + + auto node = nodes.insert(targetNode, renderGraphStorage->resourceHub->Create(nodeName, renderGraphStorage, std::move(descInitParams), std::vector>())); + ReindexNodes (); + return *node; + + } + void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list predecessorNodes, std::pair, Handle> shaderModules) noexcept { for (auto& node : predecessorNodes) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 6dbc4308..6ee181f8 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -55,6 +55,7 @@ namespace SHADE void ConfigureRenderpasses (void) noexcept; void ConfigureSubSystems (void) noexcept; void ConfigureFramebuffers (void) noexcept; + void ReindexNodes (void) noexcept; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -123,6 +124,12 @@ namespace SHADE std::initializer_list resourceInstruction, std::initializer_list predecessorNodes ) noexcept; + Handle AddNodeAfter + ( + std::string nodeName, + std::initializer_list resourceInstruction, + std::string nodeToAddAfter + ) noexcept; void AddRenderToSwapchainNode ( diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 2f498d5a..fca003aa 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -365,6 +365,7 @@ namespace SHADE , spDeps{ std::move(rhs.spDeps) } , nodeComputes{ std::move(rhs.nodeComputes) } , name { std::move(rhs.name) } + , ISelfHandle{std::move(rhs)} { rhs.renderpass = {}; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index e1277953..c4d645db 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -77,6 +77,7 @@ namespace SHADE , name { rhs.name } , viewport {rhs.viewport} , renderer {rhs.renderer} + , companionSubpass {rhs.companionSubpass} { } @@ -113,6 +114,7 @@ namespace SHADE name = std::move(rhs.name); renderer = rhs.renderer; viewport = rhs.viewport; + companionSubpass = rhs.companionSubpass; return *this; @@ -237,6 +239,7 @@ namespace SHADE } else { + // if not bind pipeline for companion and and execute draw command commandBuffer->BindPipeline(companionSubpass.pipeline); companionSubpass.companion->superBatch->Draw(commandBuffer, frameIndex, false); } From 1188c61c7d8fdced73d73507cd1213205ab7992b Mon Sep 17 00:00:00 2001 From: SHAM-DP Date: Sat, 7 Jan 2023 15:25:50 +0800 Subject: [PATCH 082/134] Filter WIP (Need to optimize the search first) --- SHADE_Engine/src/Common/SHAllComponents.h | 13 ++ .../AssetBrowser/SHAssetBrowser.cpp | 3 - .../HierarchyPanel/SHHierarchyPanel.cpp | 111 ++++++++++++---- .../HierarchyPanel/SHHierarchyPanel.h | 8 +- .../Inspector/SHEditorInspector.cpp | 1 - .../EditorWindow/MenuBar/SHEditorMenuBar.cpp | 11 +- .../Editor/EditorWindow/SHEditorWindow.cpp | 3 + .../src/Editor/EditorWindow/SHEditorWindow.h | 4 +- .../ViewportWindow/SHEditorViewport.cpp | 1 - .../src/Serialization/SHSerialization.cpp | 9 +- .../src/Serialization/SHYAMLConverters.h | 4 +- .../src/Tools/Utilities/SHStringUtilities.cpp | 8 ++ .../src/Tools/Utilities/SHStringUtilities.h | 124 +++++++++--------- 13 files changed, 194 insertions(+), 106 deletions(-) create mode 100644 SHADE_Engine/src/Common/SHAllComponents.h diff --git a/SHADE_Engine/src/Common/SHAllComponents.h b/SHADE_Engine/src/Common/SHAllComponents.h new file mode 100644 index 00000000..594e0f69 --- /dev/null +++ b/SHADE_Engine/src/Common/SHAllComponents.h @@ -0,0 +1,13 @@ +#pragma once +#include "Camera/SHCameraComponent.h" +#include "Camera/SHCameraArmComponent.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "UI/SHCanvasComponent.h" +#include "UI/SHButtonComponent.h" +#include "UI/SHUIComponent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp index bd39b38e..6e982045 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp @@ -239,10 +239,7 @@ namespace SHADE case AssetType::TEXTURE: break; case AssetType::MESH: break; case AssetType::SCENE: - if(auto editor = SHSystemManager::GetSystem()) - { editor->LoadScene(asset->id); - } break; case AssetType::PREFAB: break; case AssetType::MATERIAL: diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp index 6ac5933c..ef4ad35e 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp @@ -3,6 +3,11 @@ //#==============================================================# #include "SHpch.h" +//#==============================================================# +//|| Library Includes || +//#==============================================================# +#include + //#==============================================================# //|| SHADE Includes || //#==============================================================# @@ -16,14 +21,11 @@ #include "Tools/SHException.h" #include "Editor/IconsMaterialDesign.h" #include "SHHierarchyPanelCommands.h" - -//#==============================================================# -//|| Library Includes || -//#==============================================================# -#include +#include "Common/SHAllComponents.h" #include "Serialization/SHSerialization.h" #include "Tools/Utilities/SHClipboardUtilities.h" +#include "Tools/Utilities/SHStringUtilities.h" namespace SHADE @@ -80,7 +82,6 @@ namespace SHADE if (ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - if (auto editor = SHSystemManager::GetSystem()) editor->selectedEntities.clear(); } ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal); @@ -99,7 +100,6 @@ namespace SHADE } if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V)) { - const auto editor = SHSystemManager::GetSystem(); if (editor->selectedEntities.size() == 1) { PasteEntities(editor->selectedEntities.back()); @@ -141,16 +141,18 @@ namespace SHADE //#==============================================================# //|| Private Member Functions || //#==============================================================# - void SHHierarchyPanel::DrawMenuBar() const noexcept + void SHHierarchyPanel::DrawMenuBar() noexcept { if (ImGui::BeginMenuBar()) { auto size = ImGui::GetWindowSize(); auto g = ImGui::GetCurrentContext(); + + DrawHierarchyPanelFilter(); + ImGui::SetCursorPosX(size.x - g->Style.FramePadding.x * 15.0f); if (ImGui::SmallButton(ICON_MD_CLEAR_ALL)) { - auto editor = SHSystemManager::GetSystem(); editor->selectedEntities.clear(); } if (ImGui::IsItemHovered()) @@ -173,6 +175,56 @@ namespace SHADE } } + void SHHierarchyPanel::DrawHierarchyPanelFilter() noexcept + { + if(ImGui::InputTextWithHint("##hierarchyPanelFilter", "Filter", &filter)) + { + + } + ImGui::SameLine(); + if(ImGui::Button("x")) + { + filter.clear(); + } + } + + bool SHHierarchyPanel::EntityFilterCheck(SHSceneNode* entityNode) noexcept + { + if(!entityNode || filter.empty()) + return false; + + EntityID const eid = entityNode->GetEntityID(); + SHEntity* entity = SHEntityManager::GetEntityByID(eid); + + bool result = false; + + result |= SHStringUtilities::StringFindInsensitive(entity->name, filter) != std::string::npos; + + if(SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos) + { + result |= SHComponentManager::HasComponent(eid); + } + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + //result |= SHStringUtilities::StringFindInsensitive(rttr::type::get().get_name().data(), filter) != std::string::npos; + + //std::vector const& children = entityNode->GetChildren(); + + //for (auto const& child : children) + //{ + // result |= EntityFilterCheck(child); + //} + + return result; + } + ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode) { if (currentNode == nullptr) @@ -189,21 +241,39 @@ namespace SHADE scrollTo = MAX_EID; } - auto editor = SHSystemManager::GetSystem(); + auto* entity = SHEntityManager::GetEntityByID(eid); const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end()); - const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow); - - //bool highlighted = false; - //if(highlighted) + bool highlighted = false; + //if(!filter.empty()) //{ - // ImGui::PushStyleColor(ImGuiCol_Text, highlightedColor); + // highlighted = EntityFilterCheck(currentNode); + // if (highlighted) + // { + // ImGui::PushStyleColor(ImGuiCol_Text, highlightedColor); + // + // ImGui::SetNextItemOpen(true); + // + // + // } + // else + // { + // + // } //} - auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID()); + const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow); + + //Draw Node - bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); + bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); + + if (highlighted) + { + ImGui::PopStyleColor(); + } + const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); //Check For Begin Drag @@ -336,6 +406,7 @@ namespace SHADE drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 2); ImGui::TreePop(); } + return nodeRect; } @@ -350,7 +421,6 @@ namespace SHADE std::vector entitiesToParent = CleanUpEIDList(entities); - //auto const editor = SHSystemManager::GetSystem(); SHEntityParentCommand::EntityParentData entityParentData; std::vector parentedEIDS; for (auto const& eid : entitiesToParent) @@ -371,7 +441,7 @@ namespace SHADE void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID) { bool startSelecting = false; bool endSelecting = false; - auto const editor = SHSystemManager::GetSystem(); + editor->selectedEntities.clear(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); sceneGraph.Traverse([&](SHSceneNode* nodePtr) @@ -403,7 +473,6 @@ namespace SHADE void SHHierarchyPanel::SelectAllEntities() { - const auto editor = SHSystemManager::GetSystem(); editor->selectedEntities.clear(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); sceneGraph.Traverse([&](SHSceneNode* nodePtr) @@ -415,7 +484,6 @@ namespace SHADE void SHHierarchyPanel::CopySelectedEntities() { - const auto editor = SHSystemManager::GetSystem(); std::vector entitiesToCopy = CleanUpEIDList(editor->selectedEntities); SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(entitiesToCopy)); } @@ -428,7 +496,6 @@ namespace SHADE void SHHierarchyPanel::DeleteSelectedEntities() { - const auto editor = SHSystemManager::GetSystem(); std::vector entitiesToDelete = CleanUpEIDList(editor->selectedEntities); SHCommandManager::PerformCommand(std::make_shared(entitiesToDelete)); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h index 9278a0a3..c6670948 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h @@ -10,6 +10,8 @@ #include "imgui_internal.h" #include "ECS_Base/SHECSMacros.h" #include "Editor/EditorWindow/SHEditorWindow.h" +#include "ECS_Base/Entity/SHEntity.h" + namespace SHADE { class SHSceneNode; @@ -24,7 +26,11 @@ namespace SHADE void Exit() override; void SetScrollTo(EntityID eid); private: - void DrawMenuBar() const noexcept; + void DrawMenuBar() noexcept; + void DrawHierarchyPanelFilter() noexcept; + + bool EntityFilterCheck(SHSceneNode* entityNode) noexcept; + ImRect RecursivelyDrawEntityNode(SHSceneNode* const); void CreateChildEntity(EntityID parentEID) const noexcept; void ParentSelectedEntities(EntityID parentEID, std::vector const& entities) noexcept; diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 83647da7..64691cc5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -93,7 +93,6 @@ namespace SHADE SHEditorWindow::Update(); if (Begin()) { - auto editor = SHSystemManager::GetSystem(); if (editor && !editor->selectedEntities.empty()) { EntityID const& eid = editor->selectedEntities[0]; diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 5014dbdd..3fe9ceb5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -110,7 +110,7 @@ namespace SHADE { ImGui::BeginMenuBar(); ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.5f - 80.f); - const auto editor = SHSystemManager::GetSystem(); + ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY); if(ImGui::SmallButton(ICON_MD_PLAY_ARROW)) { @@ -165,16 +165,18 @@ namespace SHADE { if (ImGui::Selectable("New Scene")) { - SHSystemManager::GetSystem()->NewScene(); + editor->NewScene(); } if (ImGui::Selectable("Save")) { - SHSystemManager::GetSystem()->SaveScene(); + editor->SaveScene(); } + ImGui::BeginDisabled(true); if (ImGui::Selectable("Load")) { //SHSystemManager::GetSystem()->LoadScene() } + ImGui::EndDisabled(); ImGui::EndMenu(); } } @@ -211,7 +213,7 @@ namespace SHADE auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); scriptEngine->OpenSolution(); } - ImGui::BeginDisabled(SHSystemManager::GetSystem()->editorState != SHEditor::State::STOP); + ImGui::BeginDisabled(editor->editorState != SHEditor::State::STOP); if (ImGui::Selectable("Build Scripts - Debug")) { auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -252,7 +254,6 @@ namespace SHADE { if (ImGui::Selectable(style.to_string().c_str())) { - if (auto editor = SHSystemManager::GetSystem()) editor->SetStyle(style.convert()); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp index 5f00cc37..05059336 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp @@ -7,6 +7,8 @@ //|| SHADE Includes || //#==============================================================# #include "SHEditorWindow.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/SHEditor.h" //#==============================================================# //|| Library Includes || @@ -21,6 +23,7 @@ namespace SHADE SHEditorWindow::SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags) :isOpen(true), isWindowHovered(false), windowName(name), windowFlags(inFlags), io(ImGui::GetIO()) { + editor = SHSystemManager::GetSystem(); } void SHEditorWindow::Init() diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h index faacd8f2..9b932827 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h @@ -12,9 +12,9 @@ //#==============================================================# struct ImGuiIO; typedef int ImGuiWindowFlags; - namespace SHADE { + class SHEditor; class SHEditorWindow { public: @@ -38,6 +38,6 @@ namespace SHADE ImGuiWindowFlags windowFlags = 0; ImGuiIO& io; - + SHEditor* editor; };//class SHEditorWindow }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp index 93f4a615..8c32b1c5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp @@ -35,7 +35,6 @@ namespace SHADE { SHEditorWindow::Update(); auto camSystem = SHSystemManager::GetSystem(); - SHEditor* editor = SHSystemManager::GetSystem(); if (!editor->selectedEntities.empty()) { diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index a0b961a3..6cb03195 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -11,15 +11,8 @@ #include #include "Assets/Asset Types/SHSceneAsset.h" -#include "Camera/SHCameraComponent.h" -#include "Camera/SHCameraArmComponent.h" -#include "Math/Transform/SHTransformComponent.h" -#include "Graphics/MiddleEnd/Interface/SHRenderable.h" -#include "Physics/Interface/SHRigidBodyComponent.h" -#include "UI/SHCanvasComponent.h" -#include "UI/SHButtonComponent.h" +#include "Common/SHAllComponents.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" #include "Tools/FileIO/SHFileIO.h" diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 58268b57..2e2d45f4 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -1,5 +1,7 @@ #pragma once #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Math/Geometry/SHBox.h" #include "Math/Geometry/SHSphere.h" @@ -11,8 +13,6 @@ #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "SHSerializationTools.h" -#include "Physics/Interface/SHColliderComponent.h" -#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Physics/Collision/SHCollisionTagMatrix.h" diff --git a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp index b9698071..f547da6c 100644 --- a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp +++ b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.cpp @@ -13,6 +13,7 @@ of DigiPen Institute of Technology is prohibited. #include // Primary Header #include "SHStringUtilities.h" +#include namespace SHADE { @@ -50,5 +51,12 @@ namespace SHADE { return std::system_category().message(errorCode); } + + size_t SHStringUtilities::StringFindInsensitive(std::string str, std::string search, size_t pos) + { + std::transform(str.begin(), str.end(), str.begin(), [](char c) {return static_cast(std::tolower(c)); }); + std::transform(search.begin(), search.end(), search.begin(), [](char c) {return static_cast(std::tolower(c)); }); + return str.find(search, pos); + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h index bac83b07..697e19f2 100644 --- a/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h +++ b/SHADE_Engine/src/Tools/Utilities/SHStringUtilities.h @@ -4,9 +4,9 @@ \par email: kahwei.tng\@digipen.edu \date Nov 29, 2021 \brief Contains the declaration of functions for working with files and folders. - + Copyright (C) 2021 DigiPen Institute of Technology. -Reproduction or disclosure of this file or its contents without the prior written consent +Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ #pragma once @@ -16,66 +16,68 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /// - /// Contains useful functions for operating on strings. - /// - class SHStringUtilities - { - public: - /*-----------------------------------------------------------------------------*/ - /* Utility Functions */ - /*-----------------------------------------------------------------------------*/ - - /// - /// Splits a string separated by a specified delimiter into a vector of strings. - /// - /// Internal type of each element in the string. - /// Read only reference to the string to split. - /// Read only reference to the delimiter. - /// Vector of strings that have been split. - template - static std::vector> Split(const std::basic_string& str, const T& delim); - /// - /// Splits a string separated by a specified delimiter into a vector of strings. - /// Overload of Split() to allow for string literals to be accepted. - /// - /// Read only reference to the string to split. - /// Read only reference to the delimiter. - /// Vector of strings that have been split. - static std::vector Split(const std::string& str, const char& delim); - /// - /// Splits a string separated by a specified delimiter into a vector of strings. - /// Overload of Split() to allow for wide string literals to be accepted. - /// - /// Read only reference to the string to split. - /// Read only reference to the delimiter. - /// Vector of strings that have been split. - static std::vector Split(const std::wstring& str, const wchar_t& delim); - /// - /// Converts a wstring to a string. - /// - /// wstring to convert. - /// The converted wstring in string form. - static std::string WstrToStr(const std::wstring& wstr); - /// - /// Converts a string to a wstring. - /// - /// string to convert. - /// The converted string in wstring form. - static std::wstring StrToWstr(const std::string& str); - /// - /// Retrieves the error message associated with a Win32 error code. - /// - /// Win32 error code to decode. - /// String that represents the Win32 error. - static std::string GetWin32ErrorMessage(unsigned long errorCode); + /// + /// Contains useful functions for operating on strings. + /// + class SHStringUtilities + { + public: + /*-----------------------------------------------------------------------------*/ + /* Utility Functions */ + /*-----------------------------------------------------------------------------*/ - private: - /*-------------------------------------------------------------------------------*/ - /* Constructors/Destructors */ - /*-------------------------------------------------------------------------------*/ - SHStringUtilities() = delete; - }; + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// + /// Internal type of each element in the string. + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + template + static std::vector> Split(const std::basic_string& str, const T& delim); + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// Overload of Split() to allow for string literals to be accepted. + /// + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + static std::vector Split(const std::string& str, const char& delim); + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// Overload of Split() to allow for wide string literals to be accepted. + /// + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + static std::vector Split(const std::wstring& str, const wchar_t& delim); + /// + /// Converts a wstring to a string. + /// + /// wstring to convert. + /// The converted wstring in string form. + static std::string WstrToStr(const std::wstring& wstr); + /// + /// Converts a string to a wstring. + /// + /// string to convert. + /// The converted string in wstring form. + static std::wstring StrToWstr(const std::string& str); + /// + /// Retrieves the error message associated with a Win32 error code. + /// + /// Win32 error code to decode. + /// String that represents the Win32 error. + static std::string GetWin32ErrorMessage(unsigned long errorCode); + + static size_t StringFindInsensitive(std::string str, std::string search, size_t pos = 0); + + private: + /*-------------------------------------------------------------------------------*/ + /* Constructors/Destructors */ + /*-------------------------------------------------------------------------------*/ + SHStringUtilities() = delete; + }; } #include "SHStringUtilities.hpp" From 8bb406e17febb512748f8c608c852e2138665d4d Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sat, 7 Jan 2023 15:27:08 +0800 Subject: [PATCH 083/134] Shadows WIP - new subpass generated for shadow maps now use light's renderer - Added support to pass in custom binding and location for vertex attributes - SHLightingSubSystem GetViewMatrix uses SHMatrix::LookAtLH but with hard-coded values for now. This will eventually be replaced with real position and target values - Created new shadow map rendering vertex input state. --- SHADE_Engine/src/Camera/SHCameraSystem.cpp | 8 ++++++-- .../MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp | 2 +- .../src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 +- .../src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp | 4 ++-- SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp | 6 +++--- SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 8ef7ff64..924100d4 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -270,8 +270,12 @@ namespace SHADE camera.viewMatrix(1, 3) = -UP.Dot(camera.position + camera.offset); camera.viewMatrix(2, 3) = -view.Dot(camera.position + camera.offset); - - + //SHVec3 target{ 0.0f,0.0f,-1.0f }; + //target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); + //target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw)); + //target += camera.position; + + //camera.viewMatrix = SHMatrix::Transpose(SHMatrix::LookAtLH(camera.position, target, SHVec3(0.0f, -1.0f, 0.0f))); camera.dirtyView = false; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index 4082ba0f..ca68c709 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -205,7 +205,7 @@ namespace SHADE defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)}); - shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4); // Transform at binding 4 - 7 (4 slots) + shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots) } void SHGraphicsPredefinedData::Init(Handle logicalDevice) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index e682e0a1..81d8b88e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -776,7 +776,7 @@ namespace SHADE auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map - auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, worldRenderer); + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); //auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 17cffe17..e16242cb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -381,7 +381,7 @@ namespace SHADE switch (lightComp->GetLightData().type) { case SH_LIGHT_TYPE::DIRECTIONAL: - return SHMatrix::LookAtRH(lightComp->GetLightData().position, lightComp->GetLightData().position + lightComp->GetLightData().direction, SHVec3(0.0f, 1.0f, 0.0f)); + return SHMatrix::Transpose (SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(-0.7768f, 3.82611f, 9.23839f), SHVec3(-0.7619f, 3.30361f, 8.38588f), SHVec3(0.0f, -1.0f, 0.0f))); case SH_LIGHT_TYPE::POINT: return {}; case SH_LIGHT_TYPE::SPOT: @@ -525,7 +525,7 @@ namespace SHADE if (auto renderer = light.GetRenderer()) { //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() - renderer->UpdateDataManual (frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicRH(80.0f, 80.0f, 0.01f, 10000.0f)); + renderer->UpdateDataManual (frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(12.0f, 12.0f, 0.1f, 20.0f)); } } diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp index 49fa9086..30d81d89 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp @@ -195,7 +195,7 @@ namespace SHADE return *this; } - void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedAttributeLocation/* = static_cast(-1)*/) noexcept + void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding /*= static_cast(-1)*/, uint32_t fixedAttributeLocation/* = static_cast(-1)*/) noexcept { // add a binding and get ref to it bindings.emplace_back(); @@ -210,7 +210,7 @@ namespace SHADE // Offset is 0 at first (for first element) uint32_t offset = 0; - binding.binding = static_cast(bindings.size() - 1); + binding.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); // for every attribute passed in for (auto const& attrib : inAttribs) @@ -226,7 +226,7 @@ namespace SHADE auto& vertexAttrib = attributes.back(); // The binding for that attribute description is index of the new binding created earlier in this function - vertexAttrib.binding = static_cast(bindings.size() - 1); + vertexAttrib.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously vertexAttrib.location = (fixedAttributeLocation != static_cast(-1)) ? fixedAttributeLocation + i : static_cast(attributes.size () - 1); diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h index 380c726e..73eb1ef5 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h @@ -34,7 +34,7 @@ namespace SHADE SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; - void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedAttributeLocation = static_cast(-1)) noexcept; + void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding = static_cast(-1), uint32_t fixedAttributeLocation = static_cast(-1)) noexcept; friend class SHVkPipelineState; friend class SHVkPipeline; From c3582cf5eed1bcc68c50268024ed1209e8f203f5 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 7 Jan 2023 16:14:55 +0800 Subject: [PATCH 084/134] Added a rotate method with quaternions for Vector3 --- SHADE_Engine/src/Math/Transform/SHTransform.cpp | 12 +++++++++++- SHADE_Managed/src/Math/Vector3.cxx | 4 ++++ SHADE_Managed/src/Math/Vector3.hxx | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.cpp b/SHADE_Engine/src/Math/Transform/SHTransform.cpp index ef7c5fda..7be2a60c 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransform.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransform.cpp @@ -35,7 +35,17 @@ namespace SHADE : position { pos } , orientation { SHQuaternion::FromEuler(rot) } , scale { scl } - {} + { + ComputeTRS(); + } + + SHTransform::SHTransform(const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl) noexcept + : position { pos } + , orientation { quat } + , scale { scl } + { + ComputeTRS(); + } /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ diff --git a/SHADE_Managed/src/Math/Vector3.cxx b/SHADE_Managed/src/Math/Vector3.cxx index d2862ac7..647174a2 100644 --- a/SHADE_Managed/src/Math/Vector3.cxx +++ b/SHADE_Managed/src/Math/Vector3.cxx @@ -167,6 +167,10 @@ namespace SHADE { return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(axis), radians)); } + Vector3 Vector3::Rotate(Vector3 vec, Quaternion quat) + { + return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(quat))); + } Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs) { float lx = lhs.x, rx = rhs.x; diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx index 76b11420..31a373ba 100644 --- a/SHADE_Managed/src/Math/Vector3.hxx +++ b/SHADE_Managed/src/Math/Vector3.hxx @@ -19,10 +19,17 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Vector2.hxx" -value struct Quaternion; - namespace SHADE { + /*---------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-------------------------------------------------------------------------- --- */ + value struct Quaternion; + + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------- --- */ + /// /// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector. /// Designed to closely match Unity's Vector3 struct. @@ -308,6 +315,12 @@ namespace SHADE /// The Vector3 that represents the rotated vector. static Vector3 Rotate(Vector3 vec, Vector3 axis, float radians); /// + /// Rotates a Vector3 using a Quaternion. + /// + /// A Vector3 to rotate. + /// A Quaternion to rotate the vector with. + static Vector3 Rotate(Vector3 vec, Quaternion quat); + /// /// Computes and returns a Vector3 that is made from the smallest components of /// the two specified Vector3s. /// From 222bda9a13436cfc71a0fbd8f7043fb5ee4ec686 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sat, 7 Jan 2023 16:16:35 +0800 Subject: [PATCH 085/134] Replaced Transform's Forward.get with new rotate method --- SHADE_Managed/src/Components/Transform.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx index bc61eff3..d5b38967 100644 --- a/SHADE_Managed/src/Components/Transform.cxx +++ b/SHADE_Managed/src/Components/Transform.cxx @@ -107,8 +107,7 @@ namespace SHADE Vector3 Transform::Forward::get() { - const SHVec3 DIRECTION = SHVec3::Rotate(-SHVec3::UnitZ, Convert::ToNative(GlobalRotation)); - return Convert::ToCLI(DIRECTION); + return Vector3::Rotate(Vector3::Forward, GlobalRotation); } /*-----------------------------------------------------------------------------------*/ From f72659255701a8705b9a5fb0cc2fc09967c9b45d Mon Sep 17 00:00:00 2001 From: SHAM-DP Date: Sat, 7 Jan 2023 17:34:07 +0800 Subject: [PATCH 086/134] Popup window base & popup management Added Scene save prompt popup (WIP) --- .../EditorPopups/SHEditorPopups.cpp | 33 +++++++++++ .../EditorPopups/SHEditorPopups.h | 16 +++++ .../EditorWindow/SHEditorWindowManager.cpp | 2 + .../EditorWindow/SHEditorWindowManager.h | 58 +++++++++++++++++++ .../src/Editor/EditorWindow/SHPopUpWindow.cpp | 21 +++++++ .../src/Editor/EditorWindow/SHPopUpWindow.h | 29 ++++++++++ SHADE_Engine/src/Editor/SHEditor.cpp | 7 ++- 7 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp create mode 100644 SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h create mode 100644 SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp create mode 100644 SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h diff --git a/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp new file mode 100644 index 00000000..31e6edde --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.cpp @@ -0,0 +1,33 @@ +#include "SHpch.h" +#include "SHEditorPopups.h" +#include "Editor/SHEditor.h" +#include "misc/cpp/imgui_stdlib.h" + +namespace SHADE +{ + void SHSceneSavePrompt::Draw() + { + if(Begin()) + { + static std::string newSceneName{}; + ImGui::Text("Enter new scene name"); + ImGui::InputText("##name", &newSceneName); + ImGui::BeginDisabled(newSceneName.empty()); + if (ImGui::Button("Save")) + { + editor->SaveScene(newSceneName); + newSceneName.clear(); + isOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndDisabled(); + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + { + isOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h new file mode 100644 index 00000000..f1ce4fb5 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Editor/EditorWindow/SHPopUpWindow.h" + +namespace SHADE +{ + class SHSceneSavePrompt : SHPopUpWindow + { + public: + SHSceneSavePrompt():SHPopUpWindow("Save Scene As", true, 0, 0){} + void Draw() override; + + private: + + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp index 420b5414..a63e659b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.cpp @@ -4,5 +4,7 @@ namespace SHADE { SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{}; + SHEditorWindowManager::PopupWindowMap SHEditorWindowManager::popupWindows{}; SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{}; + SHEditorWindowManager::EditorWindowID SHEditorWindowManager::popupWindowCount{}; } diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h index 60730f0e..062f864a 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowManager.h @@ -3,6 +3,7 @@ #include #include #include "SHEditorWindow.h" +#include "SHPopUpWindow.h" #include "Tools/Logger/SHLog.h" namespace SHADE @@ -16,6 +17,10 @@ namespace SHADE using EditorWindowID = uint8_t; using EditorWindowPtr = std::unique_ptr; using EditorWindowMap = std::unordered_map; + + using PopupWindowPtr = std::unique_ptr; + using PopupWindowMap = std::unordered_map; + /** * @brief Get ID for the Editor Window Type * @@ -67,10 +72,63 @@ namespace SHADE return reinterpret_cast(editorWindows[GetEditorWindowID()].get()); } + /** + * @brief Get ID for the Popup Window Type + * + * @tparam T Type of Popup Window + * @return EditorWindowID ID of Popup Window Type + */ + template , bool> = true> + static EditorWindowID GetPopupWindowID() + { + static EditorWindowID id; + static bool idCreated = false; + if (!idCreated) + { + id = popupWindowCount++; + idCreated = true; + } + return id; + } + + /** + * @brief Create an Popup Window + * + * @tparam T Type of Popup Window to create + */ + template , bool> = true> + static void CreatePopupWindow() + { + static bool isCreated = false; + if (!isCreated) + { + popupWindows[GetPopupWindowID()] = std::make_unique(); + isCreated = true; + } + else + { + SHLog::Warning("Attempt to create duplicate of Popup window type"); + } + } + + /** + * @brief Get pointer to the Editor Window + * + * @tparam T Type of editor window to retrieve + * @return T* Pointer to the editor window + */ + template , bool> = true> + static T* GetPopupWindow() + { + return reinterpret_cast(popupWindows[GetPopupWindowID()].get()); + } + static EditorWindowMap editorWindows; + static PopupWindowMap popupWindows; private: // Number of windows; used for Editor Window ID Generation static EditorWindowID windowCount; + static EditorWindowID popupWindowCount; // Map of Editor Windows friend class SHEditor; }; diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp new file mode 100644 index 00000000..f82a7495 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.cpp @@ -0,0 +1,21 @@ +#include "SHpch.h" +#include "SHPopUpWindow.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/SHEditor.h" + +namespace SHADE +{ + SHPopUpWindow::SHPopUpWindow(std::string_view const& name, bool modal, ImGuiPopupFlags inPopupFlags, ImGuiWindowFlags inWindowFlags) + :editor(nullptr), windowName(name), popupFlags(inPopupFlags), windowFlags(inWindowFlags), isOpen(false), isModal(modal) + { + editor = SHSystemManager::GetSystem(); + } + + bool SHPopUpWindow::Begin() + { + if (isOpen) + ImGui::OpenPopup(windowName.data(), popupFlags); + + return isModal ? ImGui::BeginPopupModal(windowName.data(), &isOpen, windowFlags) : ImGui::BeginPopup(windowName.data(), windowFlags); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h new file mode 100644 index 00000000..5d4e5117 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h @@ -0,0 +1,29 @@ +#pragma once + +//#==============================================================# +//|| STL Includes || +//#==============================================================# +#include +#include + +namespace SHADE +{ + class SHEditor; + class SHPopUpWindow + { + public: + SHPopUpWindow(std::string_view const& name, bool modal, ImGuiPopupFlags inPopupFlags, ImGuiWindowFlags inWindowFlags); + + virtual void Draw(){}; + + protected: + virtual bool Begin(); + + SHEditor* editor; + std::string_view windowName; + ImGuiPopupFlags popupFlags; + ImGuiWindowFlags windowFlags; + bool isOpen; + bool isModal; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 2b8ddbb5..4556ae36 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -150,7 +150,7 @@ namespace SHADE { (void)dt; NewFrame(); - for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) + for (auto const& window : SHEditorWindowManager::editorWindows | std::views::values) { if(window->isOpen) { @@ -158,6 +158,11 @@ namespace SHADE } } + for(auto const& popupWindow : SHEditorWindowManager::popupWindows | std::views::values) + { + popupWindow->Draw(); + } + RenderSceneNamePrompt(); RenderUnsavedChangesPrompt(); //PollPicking(); From 77a5829fc914eeac5bd5f44e1d2decca1a8cef77 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sat, 7 Jan 2023 17:45:49 +0800 Subject: [PATCH 087/134] Shadows WIP --- Assets/Application.SHConfig | 2 +- Assets/Shaders/DeferredComposite_CS.glsl | 3 +++ Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 5501 -> 5749 bytes .../GlobalData/SHGraphicsPredefinedData.cpp | 2 +- .../GlobalData/SHPredefinedDescriptorTypes.h | 2 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 7 +++++-- .../MiddleEnd/Interface/SHRenderer.cpp | 5 +++++ .../Graphics/MiddleEnd/Interface/SHRenderer.h | 1 + .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 19 ++++++++++-------- .../MiddleEnd/Lights/SHLightingSubSystem.h | 5 +++++ .../Graphics/Pipeline/SHVkPipelineLayout.cpp | 2 ++ 11 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 5673556d..370665d2 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97158628 +Starting Scene ID: 86098106 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 0a8085b1..e73ea9eb 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -6,6 +6,7 @@ struct DirectionalLightStruct uint isActive; uint cullingMask; vec4 diffuseColor; + mat4 pvMatrix; }; struct AmbientLightStruct @@ -24,6 +25,8 @@ layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; layout(set = 3, binding = 5, rgba8) uniform image2D targetImage; +layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global) + layout(set = 1, binding = 0) uniform LightCounts { uint directionalLights; diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index cabce080c7257a3946de1cbe9f94d151884ade21..df956040e255167463b8ea8206fcc2b8074e10fb 100644 GIT binary patch literal 5749 zcmZve`*&Sc5ywxPXK4$q6sXYFl=uL_Qjr3swwN}MMpF`OtxpUm$!&7mn|tHEH*JHc zMFqqMzEJT^u|7dW@rlpnFaAfq)^aUBpL6!4hc0&4bY{LYduI0R*(Z0XadlR#p0&dR zS+*v-EZdmw0 zKV8#ru;N#5&Ni0kst$d4RP*jQf#=CJ9>lFKLL2uOO7rGPqO08Yyxb+p-Xx`1s9DBh}wDb8xtwsx1 z_V;A_;q^l9%kG6w80%1Lx!LVd?O=fcXQ{2NX5J`Vtg)Ye?(y!ITJ>f(SpxUII!mp9 z@g6Aroq~LEre0g!QPy`Dyf{nBZ{MfDM$0Q*&3&}nUY_li`L(-N>q9obxOLS#BWW5g z;?_00++bYhkK~yIq?bU(DxgK-l`S=i%MFJzwjVu-ISqU&!ZLXO84c4C@#%{l2V+ zwn6H?&Fdl068cVL&#XQSuiDkMyR`cjt9EtmYm(h}ShcHbH{W4u^zFEe>k7>MV$NJ( z)+9Dq!Hgre0U9H!@$|Dc-;%kb7IkyGj2Z97{jR_ww=n~Y+?y&`sp3Aze*V%N%{=ni~aR&Y3Tw9RC z&phtk3YqUQxb+P|`otVZeCrc)pZ?BswLW$0vlrSgBzyR)SMAQS`@^oT-M+g2Wwy$><%L+H+!n56$@1ngZ<#PVlGnb$L}EABzNv8u~jJ+t}kh08lLzq)VR zWsdD|W9VDC6~U& zRQDUpz`j^Qh0lJ+nOu|C7iuXQz;jZ!KZ>$JiRkp7?!;xw%+(Pw_p_ zX1$NYAA`*I8MyJptXJK)AH8}y$=2h1JPTJgUv=s4dokt@l0jc%s$WQ$x^wRL!R5TX z0Jm0ScqZe&1ZCN|yVbS*9@+$j{s&}haDIHhFGKoB+N|}D@K>ufYQK(N{0SfZwvp%0 zaCP^4j=#WN;?}M1cgl4;UpDJ?R$SiCzd`)o>Fc*>9pqiA`+e}Yc2ys`M8Bb;`z~*( z=`VJKN-iv+=GM~2NQ0#plvi5(Z9=#vgc;e5cT0Vd* zeh2g~di5c=%eu6E5E8R4<*4Jsg} zjjvA)5)1tVvUBnjb#H;sL;8qspci5bka6|93)08feh0Kg?e#(~Yd?kDfTDJ7CkuP| z`(rWLV~(5XVv@^zYawG>LklwBR66TY!o;OVso(Q`1TvQPIAa^xw;VnlWc|d$r;F@7 zKa%1sBa7)9vo7ZR#=Xha55m1idGz9RA!pe+;yK@EA+a-%@q900)%P-zY%2vXZ4V(E zTkczW82&NH<=&6OwaX*-CyRb9Oy7}WReGd5v$l29)5{kW_N7f#1=?lol6OXs_B(iwCr7t17tV`P$ zAu;PxHny|yWypJvzI+8a>T*863PoMo;%#k5ek$2xKEIYQaaYV|%+%Mx%%@-E`v!94 zdm8zhP~_8g2GVy6{9BOrnD1{VOk9dQ-$6E)_BiKvk@rF|yWc|=(>G>U%z24E$<>`D z`zDXNzmII)F}u$oi&?Mnv^@j4-??AgOOET&(aSxo<}@Sj7^Cw)Eq7tls%l5gA#@D~#% z?(%+pKi2V0q82dvDV9;%rD(+AhIo1bG-*$%~Ho zR_Ic2v2CTSUilBPcO&v&Ni>^7g|=d(C_ql{&}E+FI?!nbI`dIo@sLgQDA+ zoi6R8*$((>aiZCtE{+^o>yzDm!`YkQd3&k3+*KdVCeT;A{ld+Mi{|5~;3L^&4euxH zT6m}1Tgls%r}3^^$NJ^I8`0ZE>*!!EKiTY6Id1tMY&sw0RgQh&M|yedK)2n+mHk86 zUGSomN3#3ibH+N*UF!_`R6AZ`z*%Z*x0AO^7i%2lpL@Lf)o#%lBun7lSAVq|Fy3RO zzf+K}EEUc59aVh?!OOFx{PukwY`VJA_1uRBy|u=m%CFtEULUgg#jUI8Po-%%k6Tw` zt zS74Fbn1MxZzpsHs?g=pSEx<=1Ki>MpoJV}?6LX*b&U?K+b?Y;~`<*9O><=vJi(2%H z`nDs7U(|OcnE9T8Ti*nv&uO?T;#;3s)aMM=>r=Nr@5Fd#lRf;^>vreQ{b5(vJ_5P_ zb-1(mM(8q5;2Cz~t-tc+_(Z)M(08EoV_IU`C(y^?Vv_zBl{kM``Ws)&nEHFC#uC3X z>As1Ge+jZV^}m9@_HzOnF10MXfezctI};`@ndd!lYx54=C*KdbcA?z|H+G%eHv?w9 z+O1FB_b#S=Hp%YW4mt-np5Fj#iFo#ZCpWwR*R~7UH>+-(_rr}TW*&9ltyt9ifu!sI zNRrK=z6AGt_9OfY09o(T$>#p^H4l|mn##BF>Fm-3zx9)N_UV&SyF+7v;UxTvj)ZOaZ z{sdhLh5lz`Yj9S4tFJ@)NZM}WD`Gt7&1L`o3F5cK8vHJ7g6y@rZ*|87`osnLwKd&0 za$`+*|Gt{;oce#kdVK$%68aKyqo(VBqNZyO`7L@9-Co-dv4=R-D12MO zVC&c$5@xR!@H78qkiOdX(;539W*)ygZ-)HlsOx_fq|Xxjox5F-KH~Fq(%F3rBrdtk zXa9|FU$q-=H~boCGU>*DD^!pFHgtW&BmUcw#U)og{sg-Ai2n}c>ymE#>!Eu58_@L; zkNEFI7MEQ0_};sAFAhPzqr5=3<*?8jT zQY{}w7QY?(2mSdd++|(bJ_3nZmvYqc@lvkpcm#P7iaNB#`JLTIA?;h}pn48@|MuWf z$b0eaiW^^_Wk@XaCbDz#Jaun}AA$4{-$F0MT99$|^Y=_2V>jU1qV}VuT-AOI`7tPJ z*H)DF>i+`mWRE#sK^K!;=JOpI+ZsBM`4-Yyy9pDQo}qrvw+b0cdz|qT$iC(9=^^VU z9zK0!=lQ7=XMilGZ_K)w^BeajS9i9(M|t#Ot(3Fu6!Dzz$04!fP`nqh`g@s5wi6|< zY$uV8E%z;b68_v z()JuAW?jm0r(Z+%-lH#HM~=FVA%6pky0pdH+KK$lWRLlLK4Idnn9rE07r@M?U*vlc zIr6=P{4FT*X>%6z-46dYq&?>QI|&n)BF}e`&80og`90))P|WW4k;U|l*%fnMqEB*l zXUV?FqwXIdTX)Rv50S-UcD0GQ|0LY~&V~D5hW{8kn{An6ESxmn;vzY!@!hZ#wOZsN`uc58bJm0ui;J-a JAEMj={TD+43N`=$ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index ca68c709..d5f744fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -158,7 +158,7 @@ namespace SHADE .Type = vk::DescriptorType::eCombinedImageSampler, .Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute, .BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, - .DescriptorCount = 200, // we can have up to 2000 textures for now + .DescriptorCount = 200, // we can have up to 200 textures for now .flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount, }; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h index 931101f4..fc7f6a1b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h @@ -13,7 +13,7 @@ namespace SHADE CAMERA, MATERIALS, FONT, - RENDER_GRAPH_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE, + RENDER_GRAPH_RESOURCE, }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 81d8b88e..57c83e10 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -127,7 +127,10 @@ namespace SHADE SHFreetypeInstance::Init(); - SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMap_VS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false); // Load Built In Shaders static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); @@ -288,7 +291,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }, {}/*SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)[0]*/); deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) { lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index f1d4dc7f..731489fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -122,4 +122,9 @@ namespace SHADE return cameraDirector; } + SHShaderCameraData SHRenderer::GetCPUCameraData(void) const noexcept + { + return cpuCameraData; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index a17ab1a9..867851ee 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -93,6 +93,7 @@ namespace SHADE /* Setters and Getters */ /*-----------------------------------------------------------------------------*/ Handle GetCameraDirector (void) const noexcept; + SHShaderCameraData GetCPUCameraData (void) const noexcept; private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index e16242cb..88dc0f48 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -56,6 +56,11 @@ namespace SHADE //lightPtr->direction = lightData.direction; lightPtr->diffuseColor = lightData.color; lightPtr->active = lightComp->isActive; + + // write view projection matrix if renderer is available + auto lightRenderer = lightComp->GetRenderer(); + if (lightRenderer) + lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix; break; } case SH_LIGHT_TYPE::POINT: @@ -499,6 +504,12 @@ namespace SHADE for (auto& light : lightComps) { + if (auto renderer = light.GetRenderer()) + { + //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(12.0f, 12.0f, 0.1f, 20.0f)); + } + auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); // First we want to make sure the light is already bound to the system. if it @@ -520,14 +531,6 @@ namespace SHADE // Light is now updated in the container //light.ClearDirtyFlag(); } - - - if (auto renderer = light.GetRenderer()) - { - //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() - renderer->UpdateDataManual (frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(12.0f, 12.0f, 0.1f, 20.0f)); - - } } // Write data to GPU diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index 320c18b7..d1b9e003 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -3,12 +3,14 @@ #include "Resource/SHHandle.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" +#include "Math/SHMatrix.h" #include "SHLightData.h" #include #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/RenderGraph/SHRenderGraphResource.h" #include "ECS_Base/SHECSMacros.h" + namespace SHADE { class SHVkLogicalDevice; @@ -39,6 +41,9 @@ namespace SHADE //! Diffuse color emitted by the light alignas (16) SHVec4 diffuseColor; + //! Matrix for world to projection from light's perspective + SHMatrix pvMatrix; + }; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 325b3f56..d9ff07dd 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -208,7 +208,9 @@ namespace SHADE newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; } else + { SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. "); + } } setsWithBindings[CURRENT_SET].emplace_back(newBinding); From 1a0edf30d7ea5e648c558bd99bc17a0ebc73c7d9 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sat, 7 Jan 2023 22:40:29 +0800 Subject: [PATCH 088/134] Will update commit message tomorrow. Fuck Vulkan. *KW in BG: DiReCtX* --- SHADE_Engine/src/Editor/SHEditor.cpp | 4 +- .../Descriptors/SHVkDescriptorSetGroup.cpp | 22 ++++++++ .../Descriptors/SHVkDescriptorSetGroup.h | 1 + .../Graphics/Devices/SHVkLogicalDevice.cpp | 1 + .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 4 +- .../MiddleEnd/Interface/SHGraphicsConstants.h | 15 ++++- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 42 ++++++++------ .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 56 +++++++++++-------- .../MiddleEnd/Lights/SHLightingSubSystem.h | 10 +++- .../RenderGraph/SHRenderGraphNode.cpp | 15 ++++- .../Graphics/RenderGraph/SHRenderGraphNode.h | 3 +- .../RenderGraph/SHRenderGraphNodeCompute.cpp | 22 ++++---- .../RenderGraph/SHRenderGraphNodeCompute.h | 3 +- .../src/Graphics/RenderGraph/SHSubpass.cpp | 4 +- 14 files changed, 136 insertions(+), 66 deletions(-) diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index f3fe6b72..9e7ffcc6 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -502,7 +502,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetRenderpass(); + auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) { @@ -521,7 +521,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index 7c5c0e48..19ec721b 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -215,6 +215,28 @@ namespace SHADE } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept + { + vk::WriteDescriptorSet writeDescSet{}; + + // Get binding + set hash + BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); + + // to index a write for a binding + uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; + + // Initialize info for write + writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type; + writeDescSet.dstArrayElement = descArrayIndex; + writeDescSet.dstSet = descSets[set]; + writeDescSet.dstBinding = binding; + + writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex; + writeDescSet.descriptorCount = 1u; + + device->UpdateDescriptorSet(writeDescSet); + } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept { vk::WriteDescriptorSet writeDescSet{}; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index 4538b271..5b65174a 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -63,6 +63,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Public member functions */ /*-----------------------------------------------------------------------------*/ + void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept; void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 6a6e385f..3e504fb5 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -191,6 +191,7 @@ namespace SHADE features.multiDrawIndirect = VK_TRUE; features.independentBlend = VK_TRUE; + // for wide lines features.wideLines = true; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index fc701da3..a5bc4ccd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,7 +101,7 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); + auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); @@ -125,7 +125,7 @@ namespace SHADE } cmdBuffer->EndLabeledSegment(); }); - auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); + auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index b061dde3..b3945689 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,7 +31,7 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - struct RenderGraphNodeNames + struct RenderGraphEntityNames { /***************************************************************************/ /*! @@ -103,6 +103,18 @@ namespace SHADE /***************************************************************************/ static constexpr std::string_view IMGUI_PASS = "ImGui Pass"; + /***************************************************************************/ + /*! + + \brief + Name of deferred composite compute. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite"; + + + }; struct DescriptorSetBindings @@ -178,6 +190,7 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 57c83e10..1fadc7b1 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -208,7 +208,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* MAIN NODE */ /*-----------------------------------------------------------------------*/ - auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), + auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), //auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data() { "Position", @@ -276,7 +276,7 @@ namespace SHADE /* DEFERRED COMPOSITE NODE */ /*-----------------------------------------------------------------------*/ // This pass will facilitate both lighting and shadows in 1 single pass. - auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), + auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), { "Position", "Light Layer Indices", @@ -285,13 +285,13 @@ namespace SHADE "Scene", "SSAO Blur" }, - { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()}); + { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }, {}/*SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)[0]*/); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) { lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); @@ -303,19 +303,19 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - Depth Tested - auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data()}); + auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()}); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - No Depth Test - auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data()}); + auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()}); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* SCREEN SPACE PASS */ /*-----------------------------------------------------------------------*/ - auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data()}); + auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()}); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -330,16 +330,16 @@ namespace SHADE #ifdef SHEDITOR { // Dummy Node to transition scene render graph resource - auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}); + auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); dummySubpass->AddInput("Scene"); - auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data(), {"Present"}, {}); + auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -417,7 +417,7 @@ namespace SHADE textRenderingSubSystem = resourceManager.Create(); // initialize the text renderer - auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data()); + auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data()); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -444,7 +444,7 @@ namespace SHADE defaultMaterial = AddMaterial ( defaultVertShader, defaultFragShader, - renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") ); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); } @@ -762,7 +762,7 @@ namespace SHADE auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); - Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); + Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); if (EVENT_DATA->generateRenderer) { @@ -772,16 +772,16 @@ namespace SHADE } // Add the shadow map resource to the graph - renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint); + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD32Sfloat); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. //auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); - auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); + auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); //auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); - newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); + newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); // regenerate the node shadowMapNode->RuntimeStandaloneRegenerate(); @@ -791,7 +791,7 @@ namespace SHADE if (!shadowMapPipeline) { SHPipelineLibrary tempLibrary{}; - Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); tempLibrary.Init(device); tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState()); @@ -799,6 +799,12 @@ namespace SHADE } newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline + // add the shadow map to the lighting system + uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), EVENT_DATA->lightEntity); + + auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); + nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); + return eventPtr->handle; } @@ -1142,7 +1148,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 88dc0f48..8a2fb3e3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -459,14 +459,14 @@ namespace SHADE #pragma endregion #pragma region SHADOWS - std::vector shadowDescVariableSizes{ MAX_SHADOWS }; - shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); + //std::vector shadowDescVariableSizes{ MAX_SHADOWS }; + //shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); -#ifdef _DEBUG - const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); - for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) - SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); -#endif +//#ifdef _DEBUG +// const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); +// for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) +// SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); +//#endif shadowMapSampler = inShadowMapSampler; //numLightComponents = 0; @@ -583,7 +583,7 @@ namespace SHADE } - void SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept + uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept { // Add to container of shadow maps shadowMaps.emplace(lightEntity, newShadowMap); @@ -595,26 +595,28 @@ namespace SHADE shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); // Update descriptor set - static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; - uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; - shadowMapDescriptorSet->ModifyWriteDescImage - ( - SHADOW_MAP_DESC_SET_INDEX, - SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, - shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], - SHADOW_MAP_DESC_ARRAY_INDEX - ); + //static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; + //uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; + //shadowMapDescriptorSet->ModifyWriteDescImage + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, + // shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], + // SHADOW_MAP_DESC_ARRAY_INDEX + //); - // TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array - shadowMapDescriptorSet->UpdateDescriptorSetImages - ( - SHADOW_MAP_DESC_SET_INDEX, - SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA - ); + //// TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array + //shadowMapDescriptorSet->UpdateDescriptorSetImages + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA + //); // add to barriers shadowMapMemoryBarriers.push_back (vk::ImageMemoryBarrier { + .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, .oldLayout = vk::ImageLayout::eDepthAttachmentOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, @@ -629,6 +631,9 @@ namespace SHADE .layerCount = 1, } }); + + // return new index of shadow map + return static_cast(shadowMapImageSamplers.size()) - 1u; } void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept @@ -642,4 +647,9 @@ namespace SHADE return lightingDataDescSet; } + std::tuple, Handle, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept + { + return shadowMapImageSamplers[index]; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index d1b9e003..3cc5bac8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -70,11 +70,15 @@ namespace SHADE { public: using DynamicOffsetArray = std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; + static constexpr uint32_t MAX_SHADOWS = 200; private: class PerTypeData { + public: + + private: /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ @@ -137,7 +141,6 @@ namespace SHADE /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t MAX_SHADOWS = 200; //! logical device used for creation Handle logicalDevice; @@ -174,7 +177,7 @@ namespace SHADE //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. //! It will also be preallocated. - Handle shadowMapDescriptorSet; + //Handle shadowMapDescriptorSet; //! Combined image samplers for the texture descriptors std::vector, Handle, vk::ImageLayout>> shadowMapImageSamplers; @@ -205,7 +208,7 @@ namespace SHADE void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; void Exit (void) noexcept; void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; - void AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; + uint32_t AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; //void RemoveShadowMap (uint32_t index) noexcept; @@ -213,6 +216,7 @@ namespace SHADE /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; + std::tuple, Handle, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index fca003aa..ff540ce1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -442,7 +442,7 @@ namespace SHADE return subpass; } - Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, Handle customComputeLayout/* = {}*/, float numWorkGroupScale/* = 1.0f*/) noexcept + Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept { // Look for the required resources in the graph std::vector> nodeComputeResources{}; @@ -458,7 +458,7 @@ namespace SHADE std::vector> temp (nodeComputeResources); // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), customComputeLayout); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount); nodeComputes.push_back(nodeCompute); for (auto& resource : temp) @@ -810,4 +810,15 @@ namespace SHADE return attResources; } + Handle SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept + { + for (auto nc : nodeComputes) + { + if (nc->name == nodeComputeName) + return nc; + } + + return {}; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 27fdaa19..b070b8fa 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -109,7 +109,7 @@ namespace SHADE /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; - Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, Handle customComputeLayout = {}, float numWorkGroupScale = 1.0f) noexcept; + Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; @@ -127,6 +127,7 @@ namespace SHADE Handle GetSubpass(std::string_view subpassName) const noexcept; Handle GetResource (uint32_t resourceIndex) const noexcept; std::vector> const& GetResources (void) const noexcept; + Handle GetNodeCompute (std::string nodeComputeName) const noexcept; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index 55f8a9c9..ef1b6b03 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -63,7 +63,7 @@ namespace SHADE } - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, Handle customComputeLayout, float inNumWorkGroupScale/* = 1.0f*/) noexcept + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} @@ -118,21 +118,11 @@ namespace SHADE if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) { Handle computeResourceLayout = {}; - uint32_t variableCounts = 0; - if (customComputeLayout) - { - // Just use the descriptor counts in bindings as the variable descriptor counts - auto const& bindings = customComputeLayout->GetBindings(); - variableCounts = bindings.back().DescriptorCount; - computeResourceLayout = customComputeLayout; - } - else computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; - // create compute resources computeResource = graphStorage->resourceHub->Create(); - computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableCounts}); + computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount}); #ifdef _DEBUG for (auto set : computeResource->descSet->GetVkHandle()) SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); @@ -257,6 +247,14 @@ namespace SHADE } + void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept + { + static constexpr uint32_t COMPUTE_RESOURCE_SET_INDEX = 0; + computeResource->descSet->ModifyWriteDescImage(COMPUTE_RESOURCE_SET_INDEX, binding, viewSamplerLayout, descArrayIndex); + computeResource->descSet->UpdateDescriptorSetImage(COMPUTE_RESOURCE_SET_INDEX, binding, descArrayIndex); + + } + void SHRenderGraphNodeCompute::AddPreComputeFunction(PreComputeFunction const& fn) noexcept { preComputeFunctions.push_back(fn); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index 9352f1d9..83bc5d33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -93,7 +93,7 @@ namespace SHADE void SetFollowingEndRenderpass (uint32_t flag) noexcept; public: - SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, Handle customComputeLayout, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; @@ -103,6 +103,7 @@ namespace SHADE void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span const& viewSamplerLayouts) noexcept; + void ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept; void AddPreComputeFunction (PreComputeFunction const& fn) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index c4d645db..5205b44d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -164,7 +164,7 @@ namespace SHADE switch (attachmentDescriptionType) { case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; break; case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; @@ -299,6 +299,8 @@ namespace SHADE if (inputReferences[i].attachment == attachmentIndex) return true; } + + return false; } bool SHSubpass::HasNoAttachments(void) const noexcept From 98bfbc1048fca2e11683ce8947c18d65fc5f561d Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 8 Jan 2023 01:06:50 +0800 Subject: [PATCH 089/134] Added DrawWireCapsule for debug draw (doesn't support orientation changes yet) --- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 58 ++++++++++++++++++ .../MiddleEnd/Interface/SHDebugDrawSystem.h | 23 ++++++++ .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 + .../MiddleEnd/Interface/SHGraphicsSystem.h | 5 +- .../MiddleEnd/Meshes/SHPrimitiveGenerator.cpp | 59 +++++++++++++++++++ .../MiddleEnd/Meshes/SHPrimitiveGenerator.h | 41 +++++++++++++ SHADE_Engine/src/Tools/SHDebugDraw.cpp | 8 +++ SHADE_Engine/src/Tools/SHDebugDraw.h | 24 ++++++++ 8 files changed, 218 insertions(+), 2 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index b57249de..fdd21fd4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -207,6 +207,11 @@ namespace SHADE drawSphere(getMeshBatch(true, depthTested), matrix, color); } + void SHDebugDrawSystem::DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + drawWireCapsule(getLineBatch(depthTested), getMeshBatch(false, depthTested), position, rotation, height, radius, color); + } + /*-----------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ /*-----------------------------------------------------------------------------------*/ @@ -264,6 +269,12 @@ namespace SHADE markPersistentDrawsDirty(); } + void SHDebugDrawSystem::DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + drawWireCapsule(getPersistentLineBatch(depthTested), getPersistentMeshBatch(false, depthTested), position, rotation, height, radius, color); + markPersistentDrawsDirty(); + } + void SHDebugDrawSystem::ClearPersistentDraws() { for (auto& batch : persistentLineBatches) @@ -348,6 +359,53 @@ namespace SHADE ); } + void SHDebugDrawSystem::drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color) + { + // Get local axis vectors + const SHVec3 LOCAL_UP = SHVec3::Up; + const SHVec3 LOCAL_RIGHT = SHVec3::Right; + const SHVec3 LOCAL_FORWARD = SHVec3::Forward; + + // Rotate the circle + SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)); + + // Compute top and bottom of the cylinder + const SHVec3 HALF_UP = LOCAL_UP * (height * 0.5f - radius); + const SHVec3 TOP_POS = position + HALF_UP; + const SHVec3 BOT_POS = position - HALF_UP; + + // Render circles + const SHVec3 CIRCLE_SCALE = SHVec3(radius * 2.0f, radius * 2.0, radius * 2.0); + drawCircle(meshBatch, SHMatrix::Transform(TOP_POS, circleOrientation, CIRCLE_SCALE), color); + drawCircle(meshBatch, SHMatrix::Transform(BOT_POS, circleOrientation, CIRCLE_SCALE), color); + + // Render connecting lines + drawLine(lineBatch, TOP_POS + LOCAL_RIGHT * radius, BOT_POS + LOCAL_RIGHT * radius, color); + drawLine(lineBatch, TOP_POS - LOCAL_RIGHT * radius, BOT_POS - LOCAL_RIGHT * radius, color); + drawLine(lineBatch, TOP_POS + LOCAL_FORWARD * radius, BOT_POS + LOCAL_FORWARD * radius, color); + drawLine(lineBatch, TOP_POS - LOCAL_FORWARD * radius, BOT_POS - LOCAL_FORWARD * radius, color); + + // Render caps + const SHVec3 RADIUS_SCALE = SHVec3(radius * 2.0, radius * 2.0f, radius * 2.0); + const SHMatrix TOP_CAP_MAT = SHMatrix::Transform(TOP_POS, rotation, RADIUS_SCALE); + drawMesh + ( + gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap), + meshBatch, TOP_CAP_MAT, color + ); + const SHMatrix BOT_CAP_MAT = SHMatrix::Transform + ( + BOT_POS, + rotation * SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)), + RADIUS_SCALE + ); + drawMesh + ( + gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap), + meshBatch, BOT_CAP_MAT, color + ); + } + /*-----------------------------------------------------------------------------------*/ /* Helper Batch Functions - Lines */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h index 2978d68e..3997b6df 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h @@ -163,6 +163,17 @@ namespace SHADE /// Colour to draw with. /// Whether or not drawn object will be occluded. void DrawSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// + /// Draws the outline of a capsule. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ @@ -269,6 +280,17 @@ namespace SHADE /// Whether or not drawn object will be occluded. void DrawPersistentSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false); /// + /// Draws a persistent outline of a capsule. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// /// Clears any persistent drawn debug primitives. /// void ClearPersistentDraws(); @@ -386,6 +408,7 @@ namespace SHADE void drawCube(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); void drawSphere(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); void drawCircle(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); + void drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color); /*---------------------------------------------------------------------------------*/ /* Helper Batch Functions - Lines */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index b1256921..f3bcc8f7 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -419,6 +419,7 @@ namespace SHADE primitiveMeshes[static_cast(PrimitiveType::Sphere)] = SHPrimitiveGenerator::Sphere(meshLibrary); primitiveMeshes[static_cast(PrimitiveType::LineCube)] = SHPrimitiveGenerator::LineCube(meshLibrary); primitiveMeshes[static_cast(PrimitiveType::LineCircle)] = SHPrimitiveGenerator::LineCircle(meshLibrary); + primitiveMeshes[static_cast(PrimitiveType::LineCapsuleCap)] = SHPrimitiveGenerator::LineCapsuleCap(meshLibrary); BuildMeshBuffers(); // Create default materials @@ -819,6 +820,7 @@ namespace SHADE case PrimitiveType::Sphere: case PrimitiveType::LineCube: case PrimitiveType::LineCircle: + case PrimitiveType::LineCapsuleCap: return primitiveMeshes[static_cast(type)]; default: return {}; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 40148e05..707862f9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -72,9 +72,10 @@ namespace SHADE Cube, Sphere, LineCube, - LineCircle + LineCircle, + LineCapsuleCap }; - static constexpr int MAX_PRIMITIVE_TYPES = 4; + static constexpr int MAX_PRIMITIVE_TYPES = 5; enum class DebugDrawPipelineType { LineNoDepthTest, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp index 444a6630..d5a0073f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp @@ -29,6 +29,7 @@ namespace SHADE SHMeshData SHPrimitiveGenerator::sphereMesh; SHMeshData SHPrimitiveGenerator::lineCubeMesh; SHMeshData SHPrimitiveGenerator::lineCircleMesh; + SHMeshData SHPrimitiveGenerator::lineCapsuleCapMesh; /*-----------------------------------------------------------------------------------*/ /* Primitive Generation Functions */ @@ -392,6 +393,64 @@ namespace SHADE return addMeshDataTo(lineCircleMesh, gfxSystem); } + SHADE::SHMeshData SHPrimitiveGenerator::LineCapsuleCap() noexcept + { + SHMeshData mesh; + + // Have multiple semi-circles for the cap + static constexpr int SPLITS = 36; + static constexpr float ANGLE_INCREMENTS = (std::numbers::pi_v * 2.0f) / static_cast(SPLITS); + + /* X-Axis */ + // Generate points of the circle + for (int i = 0; i <= SPLITS / 2; ++i) + { + const float ANGLE = ANGLE_INCREMENTS * i; + mesh.VertexPositions.emplace_back(cos(ANGLE) * 0.5f, sin(ANGLE) * 0.5f, 0.0f); + } + + // Generate lines of the circle + for (int i = 1; i <= SPLITS / 2; ++i) + { + mesh.Indices.emplace_back(static_cast(i - 1)); + mesh.Indices.emplace_back(static_cast(i)); + } + + /* Z-Axis */ + // Generate points of the circle + for (int i = 0; i <= SPLITS / 2; ++i) + { + const float ANGLE = ANGLE_INCREMENTS * i; + mesh.VertexPositions.emplace_back(0.0f, sin(ANGLE) * 0.5f, cos(ANGLE) * 0.5f); + } + + // Generate lines of the circle + for (int i = 2 + SPLITS / 2; i <= SPLITS + 1; ++i) + { + mesh.Indices.emplace_back(static_cast(i - 1)); + mesh.Indices.emplace_back(static_cast(i)); + } + + mesh.VertexNormals.resize(mesh.VertexPositions.size()); + mesh.VertexTangents.resize(mesh.VertexPositions.size()); + mesh.VertexTexCoords.resize(mesh.VertexPositions.size()); + + return mesh; + } + Handle SHPrimitiveGenerator::LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept + { + if (lineCapsuleCapMesh.VertexPositions.empty()) + lineCapsuleCapMesh = LineCapsuleCap(); + + return addMeshDataTo(lineCapsuleCapMesh, meshLibrary); + } + Handle SHPrimitiveGenerator::LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept + { + if (lineCapsuleCapMesh.VertexPositions.empty()) + lineCapsuleCapMesh = LineCapsuleCap(); + + return addMeshDataTo(lineCapsuleCapMesh, gfxSystem); + } /*-----------------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h index 9bcd2f3c..e8c7c3fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h @@ -194,6 +194,46 @@ namespace SHADE */ /***********************************************************************************/ [[nodiscard]] static Handle LineCircle(SHGraphicsSystem& gfxSystem) noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a circle that is comprised only of lines with no diagonal lines and + store the data in a SHMeshData object. + + \return + SHMeshData object containing vertex data for the line circle. + */ + /***********************************************************************************/ + [[nodiscard]] static SHMeshData LineCapsuleCap() noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a line circle and constructs a SHMesh using the SHGraphicsSystem + provided. + + \param meshLibrary + Reference to the SHMeshLibrary to produce and store a line circle mesh in. + + \return + SHMesh object that points to the generated line circle mesh in the SHMeshLibrary. + */ + /***********************************************************************************/ + [[nodiscard]] static Handle LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a line circle and constructs a SHMesh using the SHGraphicsSystem + provided. + + \param gfxSystem + Reference to the SHGraphicsSystem to produce and store a line circle mesh in. + + \return + SHMesh object that points to the generated line circle mesh in the + SHGraphicsSystem. + */ + /***********************************************************************************/ + [[nodiscard]] static Handle LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -209,5 +249,6 @@ namespace SHADE static SHMeshData sphereMesh; static SHMeshData lineCubeMesh; static SHMeshData lineCircleMesh; + static SHMeshData lineCapsuleCapMesh; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.cpp b/SHADE_Engine/src/Tools/SHDebugDraw.cpp index 02eca592..ee040d8b 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.cpp +++ b/SHADE_Engine/src/Tools/SHDebugDraw.cpp @@ -128,6 +128,10 @@ namespace SHADE dbgDrawSys->DrawWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested); } + void SHDebugDraw::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + dbgDrawSys->DrawWireCapsule(position, rotation, height, radius, color, depthTested); + } /*-----------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ /*-----------------------------------------------------------------------------------*/ @@ -216,6 +220,10 @@ namespace SHADE dbgDrawSys->DrawPersistentWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested); } + void SHDebugDraw::Persistent::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + dbgDrawSys->DrawPersistentWireCapsule(position, rotation, height, radius, color, depthTested); + } void SHDebugDraw::Persistent::ClearDraws() { dbgDrawSys->ClearPersistentDraws(); diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.h b/SHADE_Engine/src/Tools/SHDebugDraw.h index c28b93e6..3d7bee2f 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.h +++ b/SHADE_Engine/src/Tools/SHDebugDraw.h @@ -194,6 +194,18 @@ namespace SHADE /// Colour to draw with. /// Whether or not drawn object will be occluded. static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false); + /// + /// Draws the outline of a capsule. + /// This will remain drawn until ClearDraws() is called. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Function Class "Folder" */ @@ -366,6 +378,18 @@ namespace SHADE /// Whether or not drawn object will be occluded. static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false); /// + /// Draws the outline of a capsule. + /// This will remain drawn until ClearDraws() is called. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// /// Clears any persistent drawn debug primitives. /// static void ClearDraws(); From f44e7b7a1c2a17d41a0047049428192565463e6a Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 8 Jan 2023 01:43:40 +0800 Subject: [PATCH 090/134] Debug draw capsule now works with different orientations --- .../Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index fdd21fd4..ae8c62b2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -362,12 +362,12 @@ namespace SHADE void SHDebugDrawSystem::drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color) { // Get local axis vectors - const SHVec3 LOCAL_UP = SHVec3::Up; - const SHVec3 LOCAL_RIGHT = SHVec3::Right; - const SHVec3 LOCAL_FORWARD = SHVec3::Forward; + const SHVec3 LOCAL_UP = SHVec3::Rotate(SHVec3::Up, rotation); + const SHVec3 LOCAL_RIGHT = SHVec3::Rotate(SHVec3::Right, rotation); + const SHVec3 LOCAL_FORWARD = SHVec3::Rotate(SHVec3::Forward, rotation); // Rotate the circle - SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)); + SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)) * rotation; // Compute top and bottom of the cylinder const SHVec3 HALF_UP = LOCAL_UP * (height * 0.5f - radius); @@ -396,7 +396,7 @@ namespace SHADE const SHMatrix BOT_CAP_MAT = SHMatrix::Transform ( BOT_POS, - rotation * SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)), + SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)) * rotation, RADIUS_SCALE ); drawMesh From 686e141efaad45351a836dd91e42a792b52055c2 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 8 Jan 2023 01:46:52 +0800 Subject: [PATCH 091/134] Fixed comment for SHPrimitiveGenerator::LineCapsuleCap --- .../Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h index e8c7c3fb..839d0ef6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h @@ -197,7 +197,7 @@ namespace SHADE /***********************************************************************************/ /*! \brief - Produces a circle that is comprised only of lines with no diagonal lines and + Produces a cap of a wireframe capsule that is comprised only of lines and store the data in a SHMeshData object. \return @@ -208,8 +208,8 @@ namespace SHADE /***********************************************************************************/ /*! \brief - Produces a line circle and constructs a SHMesh using the SHGraphicsSystem - provided. + Produces a cap of a wireframe capsule that is comprised only of lines and + constructs a SHMesh using the SHGraphicsSystem provided. \param meshLibrary Reference to the SHMeshLibrary to produce and store a line circle mesh in. @@ -222,8 +222,8 @@ namespace SHADE /***********************************************************************************/ /*! \brief - Produces a line circle and constructs a SHMesh using the SHGraphicsSystem - provided. + Produces a cap of a wireframe capsule that is comprised only of lines and + constructs a SHMesh using the SHGraphicsSystem provided. \param gfxSystem Reference to the SHGraphicsSystem to produce and store a line circle mesh in. From baaeb9ee102d2b80b1b32d007f91d095cb5d0aaa Mon Sep 17 00:00:00 2001 From: mushgunAX Date: Sun, 8 Jan 2023 21:05:09 +0800 Subject: [PATCH 092/134] Input Binding File I/O --- Assets/Bindings.SHConfig | 52 +++++++ SHADE_Engine/src/Input/SHInputManager.cpp | 169 ++++++++++++++++++++++ SHADE_Engine/src/Input/SHInputManager.h | 11 ++ 3 files changed, 232 insertions(+) create mode 100644 Assets/Bindings.SHConfig diff --git a/Assets/Bindings.SHConfig b/Assets/Bindings.SHConfig new file mode 100644 index 00000000..e0023603 --- /dev/null +++ b/Assets/Bindings.SHConfig @@ -0,0 +1,52 @@ +4 +Horizontal +0 +0 +5 +0.2 +5 +0 +2 +39 +68 +2 +37 +65 +2 +3 +16 +1 +2 +Mouse Wheel +3 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 +Mouse X +1 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 +Mouse Y +2 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index cec78648..a94b66d4 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -11,6 +11,7 @@ #pragma once #include +#include #include "SHInputManager.h" #include "../Tools/SHException.h" @@ -99,6 +100,174 @@ namespace SHADE } } + //The Binding File format presently goes as such: + /* + * Name + Binding Type Enum + Inverted Bool + Gravity Double + Dead Double + Sensitivity Double + Snap Bool + PositiveKeyCode count + PositiveKeyCodes + NegativeKeyCode count + NegativeKeyCodes + PositiveControllerCode Count + PositiveControllerCodes + NegativeControllerCode Count + NegativeControllerCodes + */ + void SHInputManager::SaveBindings(std::string const& targetFile) noexcept + { + std::ofstream file; + file.open("../../Assets/Bindings.SHConfig"); + + //File cannot be written to + if (!file) return; + + //First write the number of bindings + file << bindings.size() << std::endl; + + for (auto& b : bindings) + { + //Name + file << b.first << std::endl; + + //Data + auto& lbd = b.second; + + file << static_cast(lbd.bindingType) << std::endl; + file << static_cast(lbd.inverted) << std::endl; + file << lbd.gravity << std::endl; + file << lbd.dead << std::endl; + file << lbd.sensitivity << std::endl; + file << static_cast(lbd.snap) << std::endl; + + //Bindings + file << lbd.positiveKeyCodes.size() << std::endl; + for (auto kc : lbd.positiveKeyCodes) + file << static_cast(kc) << std::endl; + file << lbd.negativeKeyCodes.size() << std::endl; + for (auto kc : lbd.negativeKeyCodes) + file << static_cast(kc) << std::endl; + file << lbd.positiveControllerCodes.size() << std::endl; + for (auto cc : lbd.positiveControllerCodes) + file << static_cast(cc) << std::endl; + file << lbd.negativeControllerCodes.size() << std::endl; + for (auto cc : lbd.negativeControllerCodes) + file << static_cast(cc) << std::endl; + } + + file.close(); + } + + void SHInputManager::LoadBindings(std::string const& sourceFile) noexcept + { + std::ifstream file; + file.open("../../Assets/Bindings.SHConfig"); + + //Check + if (!file) return; + + //Erase + ClearBindings(); + + //Read + std::string read; + + int count = 0; + std::getline(file, read); + count = std::stoi(read); + + std::string bindingName; + for (int b = 0; b < count; ++b) + { + //Name + std::getline(file, read); + SHLOGV_CRITICAL("Binding Name: {}", read); + bindingName = read; + AddBinding(bindingName); + + //Type + std::getline(file, read); + SHLOGV_CRITICAL("Binding Type: {}", read); + SetBindingType(bindingName, static_cast(std::stoi(read))); + + //Inversion + std::getline(file, read); + SHLOGV_CRITICAL("Inversion: {}", read); + SetBindingInverted(bindingName, static_cast(std::stoi(read))); + + //Gravity + std::getline(file, read); + SHLOGV_CRITICAL("Gravity: {}", read); + SetBindingGravity(bindingName, std::stod(read)); + + //Dead + std::getline(file, read); + SHLOGV_CRITICAL("Dead: {}", read); + SetBindingDead(bindingName, std::stod(read)); + + //Sensitivity + std::getline(file, read); + SHLOGV_CRITICAL("Sensitivity: {}", read); + SetBindingSensitivity(bindingName, std::stod(read)); + + //Snap + std::getline(file, read); + SHLOGV_CRITICAL("Snap: {}", read); + SetBindingSnap(bindingName, static_cast(std::stoi(read))); + + int count = 0; + //Positive Key Codes + std::getline(file, read); + SHLOGV_CRITICAL("Positive Key Count: {}", read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + SHLOGV_CRITICAL("Positive Key: {}", read); + AddBindingPositiveKeyCode(bindingName, static_cast(std::stoi(read))); + } + + //Negative Key Codes + std::getline(file, read); + SHLOGV_CRITICAL("Negative Key Count: {}", read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + SHLOGV_CRITICAL("Negative Key: {}", read); + AddBindingNegativeKeyCode(bindingName, static_cast(std::stoi(read))); + } + + //Positive Controller Codes + std::getline(file, read); + SHLOGV_CRITICAL("Positive Controller Count: {}", read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + SHLOGV_CRITICAL("Positive Controller: {}", read); + AddBindingPositiveControllerCode(bindingName, static_cast(std::stoi(read))); + } + + //Negative Controller Codes + std::getline(file, read); + SHLOGV_CRITICAL("Negative Controller Count: {}", read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + SHLOGV_CRITICAL("Negative Controller: {}", read); + AddBindingNegativeControllerCode(bindingName, static_cast(std::stoi(read))); + } + } + + file.close(); + } + void SHInputManager::UpdateInput(double dt) noexcept { //Keyboard and Mouse Buttons//////////////////////////////////////////////// diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 3f708124..977a2d08 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -681,6 +681,17 @@ namespace SHADE return controllersReleasedTime[controllerNum][static_cast(code)]; } + /*------------------------------------------------------------------------*/ + /* Binding I/O */ + /*------------------------------------------------------------------------*/ + + //Save bindings registered into a file + static void SaveBindings(std::string const& targetFile = "Assets/InputBindings.SHConfig") noexcept; + + //Load and register bindings from a file + //The current list of bindings will be overwritten, so save them somewhere else before loading + static void LoadBindings(std::string const& sourceFile = "Assets/InputBindings.SHConfig") noexcept; + /*------------------------------------------------------------------------*/ /* Binding Functions */ /*------------------------------------------------------------------------*/ From 4123e76a7d991add7f03f57b2b6ba9512b5f92b0 Mon Sep 17 00:00:00 2001 From: mushgunAX Date: Sun, 8 Jan 2023 21:36:19 +0800 Subject: [PATCH 093/134] Checking Input Binding I/O --- SHADE_Engine/src/Input/SHInputManager.cpp | 21 ++++----------------- SHADE_Engine/src/Input/SHInputManager.h | 4 ++-- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index a94b66d4..b8f329b9 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -102,6 +102,8 @@ namespace SHADE //The Binding File format presently goes as such: /* + * Binding count + * (For each binding:) * Name Binding Type Enum Inverted Bool @@ -121,7 +123,7 @@ namespace SHADE void SHInputManager::SaveBindings(std::string const& targetFile) noexcept { std::ofstream file; - file.open("../../Assets/Bindings.SHConfig"); + file.open(targetFile); //File cannot be written to if (!file) return; @@ -165,7 +167,7 @@ namespace SHADE void SHInputManager::LoadBindings(std::string const& sourceFile) noexcept { std::ifstream file; - file.open("../../Assets/Bindings.SHConfig"); + file.open(sourceFile); //Check if (!file) return; @@ -185,82 +187,67 @@ namespace SHADE { //Name std::getline(file, read); - SHLOGV_CRITICAL("Binding Name: {}", read); bindingName = read; AddBinding(bindingName); //Type std::getline(file, read); - SHLOGV_CRITICAL("Binding Type: {}", read); SetBindingType(bindingName, static_cast(std::stoi(read))); //Inversion std::getline(file, read); - SHLOGV_CRITICAL("Inversion: {}", read); SetBindingInverted(bindingName, static_cast(std::stoi(read))); //Gravity std::getline(file, read); - SHLOGV_CRITICAL("Gravity: {}", read); SetBindingGravity(bindingName, std::stod(read)); //Dead std::getline(file, read); - SHLOGV_CRITICAL("Dead: {}", read); SetBindingDead(bindingName, std::stod(read)); //Sensitivity std::getline(file, read); - SHLOGV_CRITICAL("Sensitivity: {}", read); SetBindingSensitivity(bindingName, std::stod(read)); //Snap std::getline(file, read); - SHLOGV_CRITICAL("Snap: {}", read); SetBindingSnap(bindingName, static_cast(std::stoi(read))); int count = 0; //Positive Key Codes std::getline(file, read); - SHLOGV_CRITICAL("Positive Key Count: {}", read); count = std::stoi(read); for (int i = 0; i < count; ++i) { std::getline(file, read); - SHLOGV_CRITICAL("Positive Key: {}", read); AddBindingPositiveKeyCode(bindingName, static_cast(std::stoi(read))); } //Negative Key Codes std::getline(file, read); - SHLOGV_CRITICAL("Negative Key Count: {}", read); count = std::stoi(read); for (int i = 0; i < count; ++i) { std::getline(file, read); - SHLOGV_CRITICAL("Negative Key: {}", read); AddBindingNegativeKeyCode(bindingName, static_cast(std::stoi(read))); } //Positive Controller Codes std::getline(file, read); - SHLOGV_CRITICAL("Positive Controller Count: {}", read); count = std::stoi(read); for (int i = 0; i < count; ++i) { std::getline(file, read); - SHLOGV_CRITICAL("Positive Controller: {}", read); AddBindingPositiveControllerCode(bindingName, static_cast(std::stoi(read))); } //Negative Controller Codes std::getline(file, read); - SHLOGV_CRITICAL("Negative Controller Count: {}", read); count = std::stoi(read); for (int i = 0; i < count; ++i) { std::getline(file, read); - SHLOGV_CRITICAL("Negative Controller: {}", read); AddBindingNegativeControllerCode(bindingName, static_cast(std::stoi(read))); } } diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 977a2d08..01ef6c42 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -686,11 +686,11 @@ namespace SHADE /*------------------------------------------------------------------------*/ //Save bindings registered into a file - static void SaveBindings(std::string const& targetFile = "Assets/InputBindings.SHConfig") noexcept; + static void SaveBindings(std::string const& targetFile = "../../Assets/Bindings.SHConfig") noexcept; //Load and register bindings from a file //The current list of bindings will be overwritten, so save them somewhere else before loading - static void LoadBindings(std::string const& sourceFile = "Assets/InputBindings.SHConfig") noexcept; + static void LoadBindings(std::string const& sourceFile = "../../Assets/Bindings.SHConfig") noexcept; /*------------------------------------------------------------------------*/ /* Binding Functions */ From 7dbd0b93b3cff3bb85bb48565e7a85ee68cb0caf Mon Sep 17 00:00:00 2001 From: mushgunAX Date: Sun, 8 Jan 2023 21:39:48 +0800 Subject: [PATCH 094/134] Minor comment fix --- SHADE_Engine/src/Input/SHInputManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 01ef6c42..30ee00e8 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -689,7 +689,7 @@ namespace SHADE static void SaveBindings(std::string const& targetFile = "../../Assets/Bindings.SHConfig") noexcept; //Load and register bindings from a file - //The current list of bindings will be overwritten, so save them somewhere else before loading + //If specified file exists, the current list of bindings will be overwritten, so save them somewhere else before loading static void LoadBindings(std::string const& sourceFile = "../../Assets/Bindings.SHConfig") noexcept; /*------------------------------------------------------------------------*/ From b293b28a56f66dfefd476c706f0cb5a2c7a3aec4 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 07:14:40 +0800 Subject: [PATCH 095/134] Button fix --- Assets/Application.SHConfig | 2 +- Assets/Scenes/UI Test.shade.shmeta | 2 +- SHADE_Engine/src/UI/SHUISystem.cpp | 54 ++++++++++++++++++++---------- SHADE_Engine/src/UI/SHUISystem.h | 2 ++ 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index c9b34a7a..bc619d3b 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 94246101 +Starting Scene ID: 93618245 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Scenes/UI Test.shade.shmeta b/Assets/Scenes/UI Test.shade.shmeta index cf38916e..f64d5657 100644 --- a/Assets/Scenes/UI Test.shade.shmeta +++ b/Assets/Scenes/UI Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI Test -ID: 87707373 +ID: 92351881 Type: 5 diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 1387bc6b..00aa0cda 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -149,9 +149,9 @@ namespace SHADE SHVec4 topExtent4 = uiComp->GetMatrix() * SHVec4(-comp.size.x * 0.5f, comp.size.y * 0.5f , 0.0f,1.0f); SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f); - SHVec2 topExtent{ topExtent4.x,-topExtent4.y }; - SHVec2 btmExtent{ btmExtent4.x,-btmExtent4.y }; - + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; + SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; + //SHLOG_INFO("TopExtent: {}, {}", topExtent.x, topExtent.y); SHVec2 windowSize; @@ -160,23 +160,24 @@ namespace SHADE windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; - - - + //SHLOG_INFO("MousePos: {}, {}", mousePos.x, mousePos.y); + //mousePos /= windowSize; #endif - SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0).x , cameraSystem->GetCameraWidthHeight(0).y }; + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; - topExtent += camSize * 0.5f; - btmExtent += camSize * 0.5f; + topExtent = CanvasToScreenPoint(topExtent); + btmExtent = CanvasToScreenPoint(btmExtent); - //Convert everything to using ratios - topExtent /= camSize; - btmExtent /= camSize; + //SHLOG_INFO("TopExtent Screen Point: {}, {}, Cam size: {}, {}", topExtent.x, topExtent.y, camSize.x, camSize.y); - mousePos /= windowSize; + //Convert everything to using ratios + //topExtent /= camSize; + //btmExtent /= camSize; + + //SHLOG_INFO("mousePos: {} , {}", mousePos.x, mousePos.y); comp.isClicked = false; @@ -187,6 +188,7 @@ namespace SHADE if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; + //SHLOG_INFO("BUTTON CLICKED"); } //SHLOG_INFO("BUTTON HOVERED"); @@ -202,11 +204,11 @@ namespace SHADE if (SHComponentManager::HasComponent(comp.GetEID())) { - //auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); - //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); - //auto material = renderable->GetModifiableMaterial(); - //material->SetProperty("texture", comp.GetDefaultTexture()); + auto material = renderable->GetModifiableMaterial(); + material->SetProperty("texture", comp.GetDefaultTexture()); } } @@ -221,4 +223,22 @@ namespace SHADE } } + SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint) noexcept + { + SHVec2 result{canvasPoint}; + + auto cameraSystem = SHSystemManager::GetSystem(); + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; + + + result.y *= -1.0f; + result += camSize * 0.5f; + + return result; + } + + + + }//end namespace diff --git a/SHADE_Engine/src/UI/SHUISystem.h b/SHADE_Engine/src/UI/SHUISystem.h index 04e057ad..21518f16 100644 --- a/SHADE_Engine/src/UI/SHUISystem.h +++ b/SHADE_Engine/src/UI/SHUISystem.h @@ -65,6 +65,8 @@ namespace SHADE void UpdateUIComponent(SHUIComponent& comp) noexcept; void UpdateButtonComponent(SHButtonComponent& comp) noexcept; void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept; + SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint) noexcept; + }; From 5f11a931c78ab54aa6b706b9cf8f3690d3bf7af2 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 09:24:20 +0800 Subject: [PATCH 096/134] Added Toggle Button, Fixed canvas Scalar --- Assets/Scenes/UI Test.shade | 24 +++- Assets/Scenes/UI Test.shade.shmeta | 2 +- .../Inspector/SHEditorInspector.cpp | 6 + .../src/Serialization/SHSerialization.cpp | 4 + SHADE_Engine/src/UI/SHButtonComponent.cpp | 2 +- SHADE_Engine/src/UI/SHButtonComponent.h | 1 - .../src/UI/SHToggleButtonComponent.cpp | 59 +++++++++ SHADE_Engine/src/UI/SHToggleButtonComponent.h | 48 ++++++++ SHADE_Engine/src/UI/SHUISystem.cpp | 116 +++++++++++++----- SHADE_Engine/src/UI/SHUISystem.h | 2 + 10 files changed, 229 insertions(+), 35 deletions(-) create mode 100644 SHADE_Engine/src/UI/SHToggleButtonComponent.cpp create mode 100644 SHADE_Engine/src/UI/SHToggleButtonComponent.h diff --git a/Assets/Scenes/UI Test.shade b/Assets/Scenes/UI Test.shade index e8ee4df2..0aea6f72 100644 --- a/Assets/Scenes/UI Test.shade +++ b/Assets/Scenes/UI Test.shade @@ -1,7 +1,7 @@ - EID: 0 Name: Canvas IsActive: true - NumberOfChildren: 1 + NumberOfChildren: 2 Components: Canvas Component: Canvas Width: 10 @@ -14,7 +14,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} + Translate: {x: -3.5999999, y: 3.0999999, z: 0} Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -28,6 +28,26 @@ Clicked Texture: 0 IsActive: true Scripts: ~ +- EID: 5 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 153.399994, y: 0, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 129340704 + IsActive: true + Toggle Button Component: + Non Toggled Texture: 0 + Toggled Texture: 0 + Value: false + IsActive: true + Scripts: ~ - EID: 1 Name: Camera IsActive: true diff --git a/Assets/Scenes/UI Test.shade.shmeta b/Assets/Scenes/UI Test.shade.shmeta index f64d5657..a889afd5 100644 --- a/Assets/Scenes/UI Test.shade.shmeta +++ b/Assets/Scenes/UI Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI Test -ID: 92351881 +ID: 94041256 Type: 5 diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 83647da7..ed6ea6bb 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -21,6 +21,7 @@ #include "UI/SHUIComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" +#include "UI/SHToggleButtonComponent.h" #include "SHEditorComponentView.h" #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" @@ -154,6 +155,10 @@ namespace SHADE { DrawComponent(buttonComponent); } + if (auto toggleButton = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(toggleButton); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -167,6 +172,7 @@ namespace SHADE DrawAddComponentButton(eid); DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); // Components that require Transforms diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 99e4fa41..89e947fc 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -18,6 +18,7 @@ #include "Physics/Interface/SHRigidBodyComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" +#include "UI/SHToggleButtonComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" @@ -218,6 +219,7 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); AddConvComponentToComponentNode(components, eid); @@ -275,6 +277,7 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); return componentIDList; @@ -356,6 +359,7 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } diff --git a/SHADE_Engine/src/UI/SHButtonComponent.cpp b/SHADE_Engine/src/UI/SHButtonComponent.cpp index 7b275128..8e87b10e 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.cpp +++ b/SHADE_Engine/src/UI/SHButtonComponent.cpp @@ -5,7 +5,7 @@ namespace SHADE { SHButtonComponent::SHButtonComponent() - :size(1.0f), offset(0.0f), isHovered(false), isClicked(false), + :size(1.0f), isHovered(false), isClicked(false), defaultTexture(0), hoveredTexture(0), clickedTexture(0) { } diff --git a/SHADE_Engine/src/UI/SHButtonComponent.h b/SHADE_Engine/src/UI/SHButtonComponent.h index 39790b6a..be6ada3e 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.h +++ b/SHADE_Engine/src/UI/SHButtonComponent.h @@ -18,7 +18,6 @@ namespace SHADE virtual ~SHButtonComponent() = default; SHVec2 size; - SHVec2 offset; AssetID GetClickedTexture() const noexcept; AssetID GetDefaultTexture() const noexcept; diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp b/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp new file mode 100644 index 00000000..527323ea --- /dev/null +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp @@ -0,0 +1,59 @@ +#include "SHpch.h" +#include "SHToggleButtonComponent.h" + + +namespace SHADE +{ + SHToggleButtonComponent::SHToggleButtonComponent() + :size(1.0f), isHovered(false), isClicked(false), value(false), + defaultTexture(0), toggledTexture(0) + { + } + + AssetID SHToggleButtonComponent::GetDefaultTexture() const noexcept + { + return defaultTexture; + } + + AssetID SHToggleButtonComponent::GetToggledTexture() const noexcept + { + return toggledTexture; + } + + bool SHToggleButtonComponent::GetValue() const noexcept + { + return value; + } + + + void SHToggleButtonComponent::SetDefaultTexture(AssetID texture) noexcept + { + defaultTexture = texture; + } + + void SHToggleButtonComponent::SetToggledTexture(AssetID texture) noexcept + { + toggledTexture = texture; + } + + void SHToggleButtonComponent::SetValue(bool value) noexcept + { + this->value = value; + } + +} + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Toggle Button Component") + .property("Non Toggled Texture", &SHToggleButtonComponent::GetDefaultTexture, &SHToggleButtonComponent::SetDefaultTexture) + .property("Toggled Texture", &SHToggleButtonComponent::GetToggledTexture, &SHToggleButtonComponent::SetToggledTexture) + .property("Value", &SHToggleButtonComponent::GetValue, &SHToggleButtonComponent::SetValue) + ; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.h b/SHADE_Engine/src/UI/SHToggleButtonComponent.h new file mode 100644 index 00000000..3217c892 --- /dev/null +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include "SH_API.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec2.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + + class SH_API SHToggleButtonComponent final: public SHComponent + { + public: + SHToggleButtonComponent(); + virtual ~SHToggleButtonComponent() = default; + + SHVec2 size; + + AssetID GetToggledTexture() const noexcept; + AssetID GetDefaultTexture() const noexcept; + bool GetValue() const noexcept; + + + void SetDefaultTexture(AssetID texture) noexcept; + void SetToggledTexture(AssetID texture) noexcept; + void SetValue(bool value) noexcept; + + + + friend class SHUISystem; + private: + + bool isHovered; + bool isClicked; + bool value; + AssetID defaultTexture; + AssetID toggledTexture; + + + + RTTR_ENABLE() + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 00aa0cda..f3b5cad8 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -103,7 +103,7 @@ namespace SHADE { auto transform = SHComponentManager::GetComponent(comp.GetEID()); if (canvasComp != nullptr) - comp.localToCanvasMatrix = canvasComp->GetMatrix()* transform->GetTRS(); + comp.localToCanvasMatrix = transform->GetTRS() * canvasComp->GetMatrix(); else comp.localToCanvasMatrix = transform->GetTRS(); } @@ -139,47 +139,38 @@ namespace SHADE void SHUISystem::UpdateButtonComponent(SHButtonComponent& comp) noexcept { - if (!SHComponentManager::HasComponent(comp.GetEID()) || !SHComponentManager::HasComponent(comp.GetEID())) + if (!SHComponentManager::HasComponent(comp.GetEID())) { return; } auto cameraSystem = SHSystemManager::GetSystem(); auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); - SHVec4 topExtent4 = uiComp->GetMatrix() * SHVec4(-comp.size.x * 0.5f, comp.size.y * 0.5f , 0.0f,1.0f); - SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f); + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); + //SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f); SHVec2 topExtent{ topExtent4.x,topExtent4.y }; SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; - //SHLOG_INFO("TopExtent: {}, {}", topExtent.x, topExtent.y); - - SHVec2 windowSize; + SHVec2 mousePos; + SHVec2 windowSize; #ifdef SHEDITOR - windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; - //SHLOG_INFO("MousePos: {}, {}", mousePos.x, mousePos.y); - //mousePos /= windowSize; + //mousePos.y = windowSize.y - mousePos.y; + mousePos /= windowSize; #endif - - SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; + //SHLOG_INFO("TopExtent: {}, {}", topExtent.x, topExtent.y) topExtent = CanvasToScreenPoint(topExtent); btmExtent = CanvasToScreenPoint(btmExtent); - - //SHLOG_INFO("TopExtent Screen Point: {}, {}, Cam size: {}, {}", topExtent.x, topExtent.y, camSize.x, camSize.y); + topExtent /= camSize; + btmExtent /= camSize; - //Convert everything to using ratios - //topExtent /= camSize; - //btmExtent /= camSize; - - - - //SHLOG_INFO("mousePos: {} , {}", mousePos.x, mousePos.y); comp.isClicked = false; if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) @@ -188,30 +179,88 @@ namespace SHADE if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; - //SHLOG_INFO("BUTTON CLICKED"); } - //SHLOG_INFO("BUTTON HOVERED"); - - + SHLOG_INFO("HOVERED") } else { comp.isHovered = false; - - //SHLOG_INFO("BUTTON NOT HOVERED") + SHLOG_INFO("NOT HOVERED") } if (SHComponentManager::HasComponent(comp.GetEID())) { - auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + /*auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); auto material = renderable->GetModifiableMaterial(); - material->SetProperty("texture", comp.GetDefaultTexture()); + material->SetProperty("texture", comp.GetDefaultTexture());*/ } } + + void SHUISystem::UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept + { + if (!SHComponentManager::HasComponent(comp.GetEID())) + { + return; + } + auto cameraSystem = SHSystemManager::GetSystem(); + auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); + + SHVec4 topExtent4 = uiComp->GetMatrix() * SHVec4(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f, 1.0f); + SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f, 1.0f); + + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; + SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; + + SHVec2 mousePos; + SHVec2 windowSize; +#ifdef SHEDITOR + windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; + mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; + mousePos /= windowSize; +#endif + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; + + + + topExtent = CanvasToScreenPoint(topExtent); + btmExtent = CanvasToScreenPoint(btmExtent); + topExtent /= camSize; + btmExtent /= camSize; + + + comp.isClicked = false; + if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x + && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) + { + comp.isHovered = true; + if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + comp.value = !comp.value; + } + } + else + { + comp.isHovered = false; + } + + + if (SHComponentManager::HasComponent(comp.GetEID())) + { + /*auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); + + auto material = renderable->GetModifiableMaterial(); + material->SetProperty("texture", comp.GetDefaultTexture());*/ + } + } + + void SHUISystem::UpdateButtonsRoutine::Execute(double dt) noexcept { SHUISystem* system = (SHUISystem*)GetSystem(); @@ -221,6 +270,13 @@ namespace SHADE if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) system->UpdateButtonComponent(comp); } + + auto& toggleButtonDense = SHComponentManager::GetDense(); + for (auto& comp : toggleButtonDense) + { + if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) + system->UpdateToggleButtonComponent(comp); + } } SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint) noexcept @@ -230,7 +286,7 @@ namespace SHADE auto cameraSystem = SHSystemManager::GetSystem(); SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; - + //camSize.y *= -1.0f; result.y *= -1.0f; result += camSize * 0.5f; diff --git a/SHADE_Engine/src/UI/SHUISystem.h b/SHADE_Engine/src/UI/SHUISystem.h index 21518f16..a5ba8c4f 100644 --- a/SHADE_Engine/src/UI/SHUISystem.h +++ b/SHADE_Engine/src/UI/SHUISystem.h @@ -5,6 +5,7 @@ #include "ECS_Base/System/SHSystemRoutine.h" #include "SHUIComponent.h" #include "SHButtonComponent.h" +#include "SHToggleButtonComponent.h" #include "SHCanvasComponent.h" #include "Scene/SHSceneGraph.h" #include "Scene/SHSceneManager.h" @@ -64,6 +65,7 @@ namespace SHADE private: void UpdateUIComponent(SHUIComponent& comp) noexcept; void UpdateButtonComponent(SHButtonComponent& comp) noexcept; + void UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept; void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept; SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint) noexcept; From e89b6f5c4cc421555a58e2973202a5dcb02cc944 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 09:38:53 +0800 Subject: [PATCH 097/134] Fixing button --- Assets/Scenes/UI Test.shade.shmeta | 2 +- SHADE_Engine/src/UI/SHUISystem.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Assets/Scenes/UI Test.shade.shmeta b/Assets/Scenes/UI Test.shade.shmeta index a889afd5..e65c0b8f 100644 --- a/Assets/Scenes/UI Test.shade.shmeta +++ b/Assets/Scenes/UI Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI Test -ID: 94041256 +ID: 96041206 Type: 5 diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index f3b5cad8..571eb167 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -145,10 +145,11 @@ namespace SHADE } auto cameraSystem = SHSystemManager::GetSystem(); auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); + //auto canvasComp = SHComponentManager::GetComponent_s(uiComp->canvasID); - SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); - SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); - //SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f); + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; From 4928ed4bcfa52d32493f873ae3499b26bed3bec0 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Sat, 7 Jan 2023 22:40:29 +0800 Subject: [PATCH 098/134] Will update commit message tomorrow. Fuck Vulkan. *KW in BG: DiReCtX* - Changed RenderGraphNodeNames to RenderGraphEntityNames - Managed to get shadow maps into desc sets --- SHADE_Engine/src/Editor/SHEditor.cpp | 4 +- .../Descriptors/SHVkDescriptorSetGroup.cpp | 22 ++++++++ .../Descriptors/SHVkDescriptorSetGroup.h | 1 + .../Graphics/Devices/SHVkLogicalDevice.cpp | 1 + .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 4 +- .../MiddleEnd/Interface/SHGraphicsConstants.h | 15 ++++- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 42 ++++++++------ .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 56 +++++++++++-------- .../MiddleEnd/Lights/SHLightingSubSystem.h | 10 +++- .../RenderGraph/SHRenderGraphNode.cpp | 15 ++++- .../Graphics/RenderGraph/SHRenderGraphNode.h | 3 +- .../RenderGraph/SHRenderGraphNodeCompute.cpp | 22 ++++---- .../RenderGraph/SHRenderGraphNodeCompute.h | 3 +- .../src/Graphics/RenderGraph/SHSubpass.cpp | 4 +- 14 files changed, 136 insertions(+), 66 deletions(-) diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index f3fe6b72..9e7ffcc6 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -502,7 +502,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetRenderpass(); + auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) { @@ -521,7 +521,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index 7c5c0e48..19ec721b 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -215,6 +215,28 @@ namespace SHADE } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept + { + vk::WriteDescriptorSet writeDescSet{}; + + // Get binding + set hash + BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); + + // to index a write for a binding + uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; + + // Initialize info for write + writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type; + writeDescSet.dstArrayElement = descArrayIndex; + writeDescSet.dstSet = descSets[set]; + writeDescSet.dstBinding = binding; + + writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex; + writeDescSet.descriptorCount = 1u; + + device->UpdateDescriptorSet(writeDescSet); + } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept { vk::WriteDescriptorSet writeDescSet{}; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index 4538b271..5b65174a 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -63,6 +63,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Public member functions */ /*-----------------------------------------------------------------------------*/ + void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept; void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 6a6e385f..3e504fb5 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -191,6 +191,7 @@ namespace SHADE features.multiDrawIndirect = VK_TRUE; features.independentBlend = VK_TRUE; + // for wide lines features.wideLines = true; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index fc701da3..a5bc4ccd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,7 +101,7 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); + auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); @@ -125,7 +125,7 @@ namespace SHADE } cmdBuffer->EndLabeledSegment(); }); - auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); + auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index b061dde3..b3945689 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,7 +31,7 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - struct RenderGraphNodeNames + struct RenderGraphEntityNames { /***************************************************************************/ /*! @@ -103,6 +103,18 @@ namespace SHADE /***************************************************************************/ static constexpr std::string_view IMGUI_PASS = "ImGui Pass"; + /***************************************************************************/ + /*! + + \brief + Name of deferred composite compute. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite"; + + + }; struct DescriptorSetBindings @@ -178,6 +190,7 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 57c83e10..1fadc7b1 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -208,7 +208,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* MAIN NODE */ /*-----------------------------------------------------------------------*/ - auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), + auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), //auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data() { "Position", @@ -276,7 +276,7 @@ namespace SHADE /* DEFERRED COMPOSITE NODE */ /*-----------------------------------------------------------------------*/ // This pass will facilitate both lighting and shadows in 1 single pass. - auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), + auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), { "Position", "Light Layer Indices", @@ -285,13 +285,13 @@ namespace SHADE "Scene", "SSAO Blur" }, - { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()}); + { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }, {}/*SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)[0]*/); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) { lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); @@ -303,19 +303,19 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - Depth Tested - auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data()}); + auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()}); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - No Depth Test - auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data()}); + auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()}); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* SCREEN SPACE PASS */ /*-----------------------------------------------------------------------*/ - auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data()}); + auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()}); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -330,16 +330,16 @@ namespace SHADE #ifdef SHEDITOR { // Dummy Node to transition scene render graph resource - auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}); + auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); dummySubpass->AddInput("Scene"); - auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data(), {"Present"}, {}); + auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -417,7 +417,7 @@ namespace SHADE textRenderingSubSystem = resourceManager.Create(); // initialize the text renderer - auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data()); + auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data()); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -444,7 +444,7 @@ namespace SHADE defaultMaterial = AddMaterial ( defaultVertShader, defaultFragShader, - renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") ); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); } @@ -762,7 +762,7 @@ namespace SHADE auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); - Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); + Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); if (EVENT_DATA->generateRenderer) { @@ -772,16 +772,16 @@ namespace SHADE } // Add the shadow map resource to the graph - renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint); + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD32Sfloat); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. //auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); - auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); + auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); //auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); - newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); + newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); // regenerate the node shadowMapNode->RuntimeStandaloneRegenerate(); @@ -791,7 +791,7 @@ namespace SHADE if (!shadowMapPipeline) { SHPipelineLibrary tempLibrary{}; - Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); tempLibrary.Init(device); tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState()); @@ -799,6 +799,12 @@ namespace SHADE } newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline + // add the shadow map to the lighting system + uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), EVENT_DATA->lightEntity); + + auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); + nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); + return eventPtr->handle; } @@ -1142,7 +1148,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 88dc0f48..8a2fb3e3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -459,14 +459,14 @@ namespace SHADE #pragma endregion #pragma region SHADOWS - std::vector shadowDescVariableSizes{ MAX_SHADOWS }; - shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); + //std::vector shadowDescVariableSizes{ MAX_SHADOWS }; + //shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); -#ifdef _DEBUG - const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); - for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) - SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); -#endif +//#ifdef _DEBUG +// const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); +// for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) +// SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); +//#endif shadowMapSampler = inShadowMapSampler; //numLightComponents = 0; @@ -583,7 +583,7 @@ namespace SHADE } - void SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept + uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept { // Add to container of shadow maps shadowMaps.emplace(lightEntity, newShadowMap); @@ -595,26 +595,28 @@ namespace SHADE shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); // Update descriptor set - static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; - uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; - shadowMapDescriptorSet->ModifyWriteDescImage - ( - SHADOW_MAP_DESC_SET_INDEX, - SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, - shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], - SHADOW_MAP_DESC_ARRAY_INDEX - ); + //static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; + //uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; + //shadowMapDescriptorSet->ModifyWriteDescImage + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, + // shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], + // SHADOW_MAP_DESC_ARRAY_INDEX + //); - // TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array - shadowMapDescriptorSet->UpdateDescriptorSetImages - ( - SHADOW_MAP_DESC_SET_INDEX, - SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA - ); + //// TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array + //shadowMapDescriptorSet->UpdateDescriptorSetImages + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA + //); // add to barriers shadowMapMemoryBarriers.push_back (vk::ImageMemoryBarrier { + .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, .oldLayout = vk::ImageLayout::eDepthAttachmentOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, @@ -629,6 +631,9 @@ namespace SHADE .layerCount = 1, } }); + + // return new index of shadow map + return static_cast(shadowMapImageSamplers.size()) - 1u; } void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept @@ -642,4 +647,9 @@ namespace SHADE return lightingDataDescSet; } + std::tuple, Handle, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept + { + return shadowMapImageSamplers[index]; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index d1b9e003..3cc5bac8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -70,11 +70,15 @@ namespace SHADE { public: using DynamicOffsetArray = std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; + static constexpr uint32_t MAX_SHADOWS = 200; private: class PerTypeData { + public: + + private: /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ @@ -137,7 +141,6 @@ namespace SHADE /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t MAX_SHADOWS = 200; //! logical device used for creation Handle logicalDevice; @@ -174,7 +177,7 @@ namespace SHADE //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. //! It will also be preallocated. - Handle shadowMapDescriptorSet; + //Handle shadowMapDescriptorSet; //! Combined image samplers for the texture descriptors std::vector, Handle, vk::ImageLayout>> shadowMapImageSamplers; @@ -205,7 +208,7 @@ namespace SHADE void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; void Exit (void) noexcept; void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; - void AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; + uint32_t AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; //void RemoveShadowMap (uint32_t index) noexcept; @@ -213,6 +216,7 @@ namespace SHADE /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; + std::tuple, Handle, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index fca003aa..ff540ce1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -442,7 +442,7 @@ namespace SHADE return subpass; } - Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, Handle customComputeLayout/* = {}*/, float numWorkGroupScale/* = 1.0f*/) noexcept + Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept { // Look for the required resources in the graph std::vector> nodeComputeResources{}; @@ -458,7 +458,7 @@ namespace SHADE std::vector> temp (nodeComputeResources); // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), customComputeLayout); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount); nodeComputes.push_back(nodeCompute); for (auto& resource : temp) @@ -810,4 +810,15 @@ namespace SHADE return attResources; } + Handle SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept + { + for (auto nc : nodeComputes) + { + if (nc->name == nodeComputeName) + return nc; + } + + return {}; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 27fdaa19..b070b8fa 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -109,7 +109,7 @@ namespace SHADE /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; - Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, Handle customComputeLayout = {}, float numWorkGroupScale = 1.0f) noexcept; + Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; @@ -127,6 +127,7 @@ namespace SHADE Handle GetSubpass(std::string_view subpassName) const noexcept; Handle GetResource (uint32_t resourceIndex) const noexcept; std::vector> const& GetResources (void) const noexcept; + Handle GetNodeCompute (std::string nodeComputeName) const noexcept; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index 55f8a9c9..ef1b6b03 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -63,7 +63,7 @@ namespace SHADE } - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, Handle customComputeLayout, float inNumWorkGroupScale/* = 1.0f*/) noexcept + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} @@ -118,21 +118,11 @@ namespace SHADE if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) { Handle computeResourceLayout = {}; - uint32_t variableCounts = 0; - if (customComputeLayout) - { - // Just use the descriptor counts in bindings as the variable descriptor counts - auto const& bindings = customComputeLayout->GetBindings(); - variableCounts = bindings.back().DescriptorCount; - computeResourceLayout = customComputeLayout; - } - else computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; - // create compute resources computeResource = graphStorage->resourceHub->Create(); - computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableCounts}); + computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount}); #ifdef _DEBUG for (auto set : computeResource->descSet->GetVkHandle()) SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); @@ -257,6 +247,14 @@ namespace SHADE } + void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept + { + static constexpr uint32_t COMPUTE_RESOURCE_SET_INDEX = 0; + computeResource->descSet->ModifyWriteDescImage(COMPUTE_RESOURCE_SET_INDEX, binding, viewSamplerLayout, descArrayIndex); + computeResource->descSet->UpdateDescriptorSetImage(COMPUTE_RESOURCE_SET_INDEX, binding, descArrayIndex); + + } + void SHRenderGraphNodeCompute::AddPreComputeFunction(PreComputeFunction const& fn) noexcept { preComputeFunctions.push_back(fn); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index 9352f1d9..83bc5d33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -93,7 +93,7 @@ namespace SHADE void SetFollowingEndRenderpass (uint32_t flag) noexcept; public: - SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, Handle customComputeLayout, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; @@ -103,6 +103,7 @@ namespace SHADE void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span const& viewSamplerLayouts) noexcept; + void ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept; void AddPreComputeFunction (PreComputeFunction const& fn) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index c4d645db..5205b44d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -164,7 +164,7 @@ namespace SHADE switch (attachmentDescriptionType) { case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; break; case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; @@ -299,6 +299,8 @@ namespace SHADE if (inputReferences[i].attachment == attachmentIndex) return true; } + + return false; } bool SHSubpass::HasNoAttachments(void) const noexcept From 88491ffbd80c4b022a1c91dfe91e7024c36cae51 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 09:56:46 +0800 Subject: [PATCH 099/134] ToggleButton fix --- Assets/Scenes/UI Test.shade.shmeta | 2 +- SHADE_Engine/src/UI/SHUISystem.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Assets/Scenes/UI Test.shade.shmeta b/Assets/Scenes/UI Test.shade.shmeta index e65c0b8f..ad821810 100644 --- a/Assets/Scenes/UI Test.shade.shmeta +++ b/Assets/Scenes/UI Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI Test -ID: 96041206 +ID: 88543249 Type: 5 diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 571eb167..95663bc0 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -161,7 +161,9 @@ namespace SHADE windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; //mousePos.y = windowSize.y - mousePos.y; + SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) mousePos /= windowSize; + SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) #endif SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; @@ -169,6 +171,7 @@ namespace SHADE topExtent = CanvasToScreenPoint(topExtent); btmExtent = CanvasToScreenPoint(btmExtent); + //SHLOG_INFO("TopExtent: {}, {} Btm Extent: {}, {}", topExtent.x, topExtent.y, btmExtent.x, btmExtent.y) topExtent /= camSize; btmExtent /= camSize; @@ -210,8 +213,9 @@ namespace SHADE auto cameraSystem = SHSystemManager::GetSystem(); auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); - SHVec4 topExtent4 = uiComp->GetMatrix() * SHVec4(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f, 1.0f); - SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f, 1.0f); + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; From 4f63558f4021d2fea154b59f83cfa0ec77022bae Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 10:44:36 +0800 Subject: [PATCH 100/134] Added GetComponents to Component Manager --- .../ECS_Base/Managers/SHComponentManager.h | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h index 8921fbce..9fcbf6f8 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h @@ -23,7 +23,7 @@ #include "SH_API.h" #include "Events/SHEventManager.hpp" - +#include #include namespace SHADE @@ -151,6 +151,32 @@ namespace SHADE return (componentSet.GetSparseSet()->GetElement_s(EntityHandleGenerator::GetIndex(entityID))); } + /*!************************************************************************* + * \brief + * Gets the Component of the entity with the specified entityID + * + * This is the safe version of GetComponent_s which does a HasComponent to make + * sure that the entity has such a component and returns nullptr if it doesn't + * + * This safe version also checks if the sparse set of this component type + * has been created in SHComponentManager and creates one if it doesn't + * + * @tparam T... + * Pack of Types for all the Components to get. + * \param entityID + * EntityID of the entity that we are trying to get the component of. + * \return + * A tuple of pointers to all the components specified. + * Returns nullptr if the entity does not contain such a component. + ***************************************************************************/ + + template + static std::enable_if_t<(... && std::is_base_of_v), std::tuple> GetComponents(EntityID entityID) noexcept + { + return std::make_tuple(GetComponent_s(entityID)...); + } + + /*!************************************************************************* * \brief * Gets the Component of the entity with the specified entityID From 28829213c9a310d9dd7719746f2b97bed252fe4a Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 10:53:56 +0800 Subject: [PATCH 101/134] merge --- Assets/Scenes/UI_Test.shade.shmeta | 4 ++-- SHADE_Engine/src/Serialization/SHSerialization.cpp | 2 +- SHADE_Engine/src/UI/SHUISystem.cpp | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Assets/Scenes/UI_Test.shade.shmeta b/Assets/Scenes/UI_Test.shade.shmeta index ad821810..f32277e0 100644 --- a/Assets/Scenes/UI_Test.shade.shmeta +++ b/Assets/Scenes/UI_Test.shade.shmeta @@ -1,3 +1,3 @@ -Name: UI Test -ID: 88543249 +Name: UI_Test +ID: 97161771 Type: 5 diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index e92a4d5f..a055d91c 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -350,7 +350,7 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); - SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + //SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 95663bc0..4d175e5f 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -161,9 +161,9 @@ namespace SHADE windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; //mousePos.y = windowSize.y - mousePos.y; - SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) - mousePos /= windowSize; - SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + //mousePos /= windowSize; + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) #endif SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; @@ -172,8 +172,8 @@ namespace SHADE topExtent = CanvasToScreenPoint(topExtent); btmExtent = CanvasToScreenPoint(btmExtent); //SHLOG_INFO("TopExtent: {}, {} Btm Extent: {}, {}", topExtent.x, topExtent.y, btmExtent.x, btmExtent.y) - topExtent /= camSize; - btmExtent /= camSize; + //topExtent /= camSize; + //btmExtent /= camSize; comp.isClicked = false; if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x From cb9223db0bc3f636650542ee3c12c38d50f69573 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 9 Jan 2023 11:06:10 +0800 Subject: [PATCH 102/134] Enabled partially bound bit for descriptor sets with variable size - Shadow maps can be sampled from compute shaders --- Assets/Shaders/DeferredComposite_CS.glsl | 12 ++++++++++++ Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 5749 -> 6529 bytes .../Graphics/Devices/SHVkLogicalDevice.cpp | 1 + .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 6 ------ .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 8 ++++++++ .../MiddleEnd/Lights/SHLightingSubSystem.h | 5 +++-- .../Graphics/Pipeline/SHVkPipelineLayout.cpp | 2 +- 7 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index e73ea9eb..2402d4f8 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -7,6 +7,7 @@ struct DirectionalLightStruct uint cullingMask; vec4 diffuseColor; mat4 pvMatrix; + uint shadowData; }; struct AmbientLightStruct @@ -65,6 +66,8 @@ void main() vec3 fragColor = vec3 (0.0f); + vec4 shadowMapColor = vec4 (1.0f); + for (int i = 0; i < lightCounts.directionalLights; ++i) { if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) @@ -77,6 +80,13 @@ void main() // Calculate the fragment color fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; + + if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) + { + // calculate shadow map here + vec2 texCoord = vec2 (gl_GlobalInvocationID.xy) / vec2 (imageSize (targetImage)); + shadowMapColor = texture (shadowMaps[0], texCoord).xxxx; + } } } @@ -95,6 +105,8 @@ void main() // store result into result image imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); + + imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapColor); //imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f)); } \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index df956040e255167463b8ea8206fcc2b8074e10fb..fc527efa0308db8d380e4a8cfabff95cb1ce335b 100644 GIT binary patch literal 6529 zcmZvfiJR4B6~})pGsCKqD5OGzv`7+~iAV%8fR5PUU?AB#{Fu4S+`Qa7-Ft^c&BhEf zDzl{3DB26MY~QTRLT%so^{;4qo}Q=A=Xc*T{NnNTIh=F8=e*~f_q^x#&b9a8)3ajD zn7+Ix%cf;>viaHHJ5aVDn+}o{{P~Gr0iT<77kK}`j)7IJ_Qxht9Sfouy;E0VkB<+v+J|bDp<13nOy+SYkMjq4fXD<7k#|Zs=9es zwQ>LzyenH?!dnTu1YU16_vN*Yr}0)yVXb1{W$3l)=vaFoKU8UUa(D-)u`PK!@8nnu zzPFi=Zf?{XxEA%ShquP^k;Z{-`FJvP(d$0&YT?tB-2fjj$L7XFz1`vzvkDA2OYLsd z^IG9z?cMz69ZjW+_uyQlDXI`Vycs+Fl7ow^6Wi}R%X-p5X`EuE{L z%DtoAoEUC*@@scZ)rV|;aqFtK`qGq~#;t33qQ)4FZp&M@7Io=wT_c@qjn+-Ya(>45 zZ_C@w>OsUQ+}ZB*HTpj*+XZ%J%^hoJpLW+s(XZIoo!tV)z7lF*dNQsx`QBJeN%gi$ zn%C}ZOk1aB+ES^Hw#SNjISk&e9NgS!G?Q;vc0??1j#k=R_vNFN!tVjFskz`%orz;$ zotfy#K8@U0x~tQ@@7OTMUH)Is+-Lt=Q53TGB5wcBycco%U%nU5eiE#lzuZS{uDsMS zzrBaR*i%A1*Uan`c&n8+cI7qnp6tn_Z>mi+o0XAHQ^5N1^^KYfU6gdc?~5U8)ULh^ z@+|7h;bptJc9-@Q@UmT9yFJqGw_LWXYd7EZRO@%S;eeDf4{NvS=BvjoZW9kd-$tsH?RBsUbI_p=-OT8 zcaB|=KQQBqMPKxbUM)lpKlAFh7&86|xaaGI^of~|_?}P9efm55<@2dqU)1Z&m(QnO zw*L*?x%cP5xm0M4%ZP4#<@1OX^?0U5=-!c-_Fi=7PE68&PJ#0eOMl~w8B>4f$5`U) zlJ55x@y|v!zW(R)ul?$UjCCGdJz|}Y+{x=1W*2?bZmjaMR(oRp^wX#CHNU#wx62$$ z;KtD3n9Gv>R58Vjc`@9juQAn^3$Q}>4RGnd3U1x@#To%r){4M6v*O=Q zxpyO&d%ZvR$~Qr-rD!+6t*cD#doh@2)$ZBUeV4?vZ%eZK7J_bvF9zQMw;s>DH2r?? zToGTJKI%)Dnw#M}p{2;a6Y9o)DcoFQ=2!Qv5Q}rXJn8xmC)r%;qj1k{kHg;|zcHu$ zOe|tWPwmU?knfEC)^{f~4e~DUh8ru+|3+lvi)+6J?jG&d>kJ=(T+Y+m;qEtHd4+x< zmEDg)zl+%a4!F8Cc%FB{UE;=9_bqg3KiUzCJ#pR#!Hn-c``&q0Yp_nq{-1zrv;QaI z>c;yF+_Q+8Pu;gH&i_b~jpz9uhdz|kOQRK0b?%W(M=^K%cm2~}2C4D{h+k>+p-{U*b?WO$@yNOdfw+j*mo5G%!uxaq^ z_}PzhA$_%NpmX*~%sl?RyAZk{>H7QIOP@XLcXpOS`iKwGX}`5+K;n|ieBO`o?Ynm4 zFM~f5TAp;{KMN|ye>S>4;t~Hj$l{W#9KRP`d&GY(@`|Jz|5B(NeZ+Peb2{)nt zn@(mZl*ez#0`;hwz>d6}LaVTon zR)_TUyL>IAJ!ZO@FmadprbGH$LklwB_H@>E!o;P+)bIHwAY*BdGww(ByAGcN$oh$g z&p~8o`>qt{5VDxQG52EnJFmAvaaQN$4k*s5?RH3C=k#@u_L!H~C+tr6i8L>h$l_wo z%NyV>=VcOp7bNDqC>wh&{7uk&XppzAQLN%s!E0!3ZEAzy`}E^XH5-X-v_LE7UD`Fg^{ zUC#b=D8Bn|Ae&FWxQA~dN4`gpzXe4;ZO($e3*p~}w8tCtorH-?k>^olb7_xreiwNy z6z|Jp$YPH|&XYDV=Oy|iS9g}|n>_0N9zngx9tdF?A3q1diA#s;ApMr};e|~~27H9q`vgf*w{oeJ@ATj;o%wqa4hW{Ko zl62p;UqJJrc-wxNFmcy3$nVGce+6le+`mRPchvqHWHDD@zeN@^PGG-Fm~*o|y-~kM zcEA4GH$cPWwO;dTk2CxMxqOB{qL8~^|S literal 5749 zcmZve`*&Sc5ywxPXK4$q6sXYFl=uL_Qjr3swwN}MMpF`OtxpUm$!&7mn|tHEH*JHc zMFqqMzEJT^u|7dW@rlpnFaAfq)^aUBpL6!4hc0&4bY{LYduI0R*(Z0XadlR#p0&dR zS+*v-EZdmw0 zKV8#ru;N#5&Ni0kst$d4RP*jQf#=CJ9>lFKLL2uOO7rGPqO08Yyxb+p-Xx`1s9DBh}wDb8xtwsx1 z_V;A_;q^l9%kG6w80%1Lx!LVd?O=fcXQ{2NX5J`Vtg)Ye?(y!ITJ>f(SpxUII!mp9 z@g6Aroq~LEre0g!QPy`Dyf{nBZ{MfDM$0Q*&3&}nUY_li`L(-N>q9obxOLS#BWW5g z;?_00++bYhkK~yIq?bU(DxgK-l`S=i%MFJzwjVu-ISqU&!ZLXO84c4C@#%{l2V+ zwn6H?&Fdl068cVL&#XQSuiDkMyR`cjt9EtmYm(h}ShcHbH{W4u^zFEe>k7>MV$NJ( z)+9Dq!Hgre0U9H!@$|Dc-;%kb7IkyGj2Z97{jR_ww=n~Y+?y&`sp3Aze*V%N%{=ni~aR&Y3Tw9RC z&phtk3YqUQxb+P|`otVZeCrc)pZ?BswLW$0vlrSgBzyR)SMAQS`@^oT-M+g2Wwy$><%L+H+!n56$@1ngZ<#PVlGnb$L}EABzNv8u~jJ+t}kh08lLzq)VR zWsdD|W9VDC6~U& zRQDUpz`j^Qh0lJ+nOu|C7iuXQz;jZ!KZ>$JiRkp7?!;xw%+(Pw_p_ zX1$NYAA`*I8MyJptXJK)AH8}y$=2h1JPTJgUv=s4dokt@l0jc%s$WQ$x^wRL!R5TX z0Jm0ScqZe&1ZCN|yVbS*9@+$j{s&}haDIHhFGKoB+N|}D@K>ufYQK(N{0SfZwvp%0 zaCP^4j=#WN;?}M1cgl4;UpDJ?R$SiCzd`)o>Fc*>9pqiA`+e}Yc2ys`M8Bb;`z~*( z=`VJKN-iv+=GM~2NQ0#plvi5(Z9=#vgc;e5cT0Vd* zeh2g~di5c=%eu6E5E8R4<*4Jsg} zjjvA)5)1tVvUBnjb#H;sL;8qspci5bka6|93)08feh0Kg?e#(~Yd?kDfTDJ7CkuP| z`(rWLV~(5XVv@^zYawG>LklwBR66TY!o;OVso(Q`1TvQPIAa^xw;VnlWc|d$r;F@7 zKa%1sBa7)9vo7ZR#=Xha55m1idGz9RA!pe+;yK@EA+a-%@q900)%P-zY%2vXZ4V(E zTkczW82&NH<=&6OwaX*-CyRb9Oy7}WReGd5v$l29)5{kW_N7f#1=?lol6OXs_B(iwCr7t17tV`P$ zAu;PxHny|yWypJvzI+8a>T*863PoMo;%#k5ek$2xKEIYQaaYV|%+%Mx%%@-E`v!94 zdm8zhP~_8g2GVy6{9BOrnD1{VOk9dQ-$6E)_BiKvk@rF|yWc|=(>G>U%z24E$<>`D z`zDXNzmII)F}u$oi&?Mnv^@j4-??AgOOET&(aSxo<}@Sj7^Cw)Eq7tls%l5gA#@D~#% z?(%+pKi2 ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); - /*-----------------------------------------------------------------------*/ - /* SHADOW MAP PASS */ - /*-----------------------------------------------------------------------*/ - // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. - // It will initially also not have any subpasses since they will be added for each light that casts shadows. - //auto shadowMapPassNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 8a2fb3e3..bc9554c4 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -60,7 +60,15 @@ namespace SHADE // write view projection matrix if renderer is available auto lightRenderer = lightComp->GetRenderer(); if (lightRenderer) + { lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix; + + // Boolean to cast shadows in first 8 bits (1 byte) + lightPtr->shadowData = lightData.castShadows; + + // Next 24 bits for shadow map index + lightPtr->shadowData |= (lightData.shadowMapIndex << 8); + } break; } case SH_LIGHT_TYPE::POINT: diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index 3cc5bac8..f3a98d14 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -44,6 +44,9 @@ namespace SHADE //! Matrix for world to projection from light's perspective SHMatrix pvMatrix; + //! Represents boolean for casting shadows in first byte and shadow map index in the other 3. + uint32_t shadowData; + }; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. @@ -62,8 +65,6 @@ namespace SHADE //! when a fragment is being evaluated, the shader will use the fragment's //! layer value to AND with the light's. If result is 1, do lighting calculations. uint32_t cullingMask; - - }; class SH_API SHLightingSubSystem diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index d9ff07dd..6a6ef879 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -205,7 +205,7 @@ namespace SHADE newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND; // Set the flags for variable bindings - newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; + newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound; } else { From 402bd165226338bfe6ed0c7a7cb69bd78a710484 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 17:18:22 +0800 Subject: [PATCH 103/134] fix for editor window size --- Assets/Application.SHConfig | 2 +- SHADE_Engine/src/UI/SHUISystem.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 5673556d..3cf8846b 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97158628 +Starting Scene ID: 97161771 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 4d175e5f..eef63a73 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -158,10 +158,11 @@ namespace SHADE SHVec2 mousePos; SHVec2 windowSize; #ifdef SHEDITOR - windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; //mousePos.y = windowSize.y - mousePos.y; - //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + SHLOG_INFO("window size: {}, {}", windowSize.x, windowSize.y) //mousePos /= windowSize; //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) #endif From 356ec24cc20f93693cef18aa6ff165c3f1cfa299 Mon Sep 17 00:00:00 2001 From: mushgunAX Date: Mon, 9 Jan 2023 17:21:24 +0800 Subject: [PATCH 104/134] Change default pathing for binding file I/O --- Assets/Bindings.SHConfig | 51 ------------------------- SHADE_Engine/src/Input/SHInputManager.h | 5 ++- 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/Assets/Bindings.SHConfig b/Assets/Bindings.SHConfig index e0023603..573541ac 100644 --- a/Assets/Bindings.SHConfig +++ b/Assets/Bindings.SHConfig @@ -1,52 +1 @@ -4 -Horizontal -0 -0 -5 -0.2 -5 -0 -2 -39 -68 -2 -37 -65 -2 -3 -16 -1 -2 -Mouse Wheel -3 -0 -1 -0.2 -1 -0 -0 -0 -0 -0 -Mouse X -1 -0 -1 -0.2 -1 -0 -0 -0 -0 -0 -Mouse Y -2 -0 -1 -0.2 -1 -0 -0 -0 -0 0 diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 30ee00e8..680035c3 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -14,6 +14,7 @@ #include #include #include "../../SHADE_Managed/src/SHpch.h" +#include "../../SHADE_Engine/src/Assets/SHAssetMacros.h" #include "SH_API.h" #pragma comment(lib, "xinput.lib") @@ -686,11 +687,11 @@ namespace SHADE /*------------------------------------------------------------------------*/ //Save bindings registered into a file - static void SaveBindings(std::string const& targetFile = "../../Assets/Bindings.SHConfig") noexcept; + static void SaveBindings(std::string const& targetFile = std::string(ASSET_ROOT) + "/Bindings.SHConfig") noexcept; //Load and register bindings from a file //If specified file exists, the current list of bindings will be overwritten, so save them somewhere else before loading - static void LoadBindings(std::string const& sourceFile = "../../Assets/Bindings.SHConfig") noexcept; + static void LoadBindings(std::string const& sourceFile = std::string(ASSET_ROOT) + "/Bindings.SHConfig") noexcept; /*------------------------------------------------------------------------*/ /* Binding Functions */ From 8b2297f45160b86cf4d2713114498f92d9b8cfba Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 9 Jan 2023 17:40:21 +0800 Subject: [PATCH 105/134] CreateSparseSet --- SHADE_Engine/src/UI/SHUISystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index eef63a73..cd2bef82 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -20,6 +20,7 @@ namespace SHADE SHComponentManager::CreateComponentSparseSet(); SHComponentManager::CreateComponentSparseSet(); SHComponentManager::CreateComponentSparseSet(); + SHComponentManager::CreateComponentSparseSet(); } void SHUISystem::Exit() From 9538636af6dd0e2c2450ec558a4559489be63749 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Tue, 10 Jan 2023 01:47:10 +0800 Subject: [PATCH 106/134] Shadows WIP --- .../Descriptors/SHVkDescriptorSetGroup.cpp | 6 +++ .../Graphics/Devices/SHVkLogicalDevice.cpp | 40 +++++++++++-------- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 26 ++++++------ .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 26 +++++++++++- .../MiddleEnd/Lights/SHLightingSubSystem.h | 11 +++-- .../Graphics/RenderGraph/SHRenderGraph.cpp | 11 +++-- .../src/Graphics/RenderGraph/SHRenderGraph.h | 1 + .../RenderGraph/SHRenderGraphResource.cpp | 7 +++- .../RenderGraph/SHRenderGraphResource.h | 5 ++- 9 files changed, 92 insertions(+), 41 deletions(-) diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index 19ec721b..8143ec0e 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -175,6 +175,12 @@ namespace SHADE writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].imageLayout = layout; } + + // Rest is not used, so it doesn't matter what's in them, we just want to pacify Vulkan + for (uint32_t i = imageViewsAndSamplers.size(); i < writeInfo.descImageInfos.size(); ++i) + { + writeInfo.descImageInfos[i].sampler = std::get>(imageViewsAndSamplers.back())->GetVkSampler(); + } } void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index b425bc5f..5653bbe7 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -183,35 +183,43 @@ namespace SHADE /*if (!extensionsSupported) SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/ - vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED + vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature + { + .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .descriptorBindingPartiallyBound = VK_TRUE, + .descriptorBindingVariableDescriptorCount = VK_TRUE, + .runtimeDescriptorArray = VK_TRUE, + }; + + vk::PhysicalDeviceRobustness2FeaturesEXT robustFeatures + { + .nullDescriptor = VK_TRUE, + }; + + robustFeatures.pNext = &descIndexingFeature; + + vk::PhysicalDeviceFeatures2 features{}; // ADD MORE FEATURES HERE IF NEEDED // point and lines fill mode - features.fillModeNonSolid = VK_TRUE; - features.samplerAnisotropy = VK_TRUE; - features.multiDrawIndirect = VK_TRUE; - features.independentBlend = VK_TRUE; + features.features.fillModeNonSolid = VK_TRUE; + features.features.samplerAnisotropy = VK_TRUE; + features.features.multiDrawIndirect = VK_TRUE; + features.features.independentBlend = VK_TRUE; + features.features.wideLines = VK_TRUE; - - // for wide lines - features.wideLines = true; - - vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{}; - descIndexingFeature.descriptorBindingVariableDescriptorCount = true; - descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true; - descIndexingFeature.descriptorBindingPartiallyBound = true; - descIndexingFeature.runtimeDescriptorArray = true; + features.pNext = &robustFeatures; // Prepare to create the device vk::DeviceCreateInfo deviceCreateInfo { - .pNext = &descIndexingFeature, + .pNext = &features, .queueCreateInfoCount = static_cast(queueCreateInfos.size()), .pQueueCreateInfos = queueCreateInfos.data(), .enabledLayerCount = 0, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored .enabledExtensionCount = !extensionsSupported ? 0 : static_cast(requiredExtensions.size()), .ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(), - .pEnabledFeatures = &features + //.pEnabledFeatures = &features }; // Actually create the device diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index eaf9b767..2e03d5a8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -193,17 +193,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Initialize world render graph renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); - renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); //worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); - renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second); - renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, true, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); + renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second); /*-----------------------------------------------------------------------*/ /* MAIN NODE */ @@ -766,21 +766,18 @@ namespace SHADE } // Add the shadow map resource to the graph - renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, resizeWidth, resizeHeight, vk::Format::eD32Sfloat); + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. - //auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); - //auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); // regenerate the node shadowMapNode->RuntimeStandaloneRegenerate(); - // Create pipeline from new renderpass and subpass if it's not created yet if (!shadowMapPipeline) { @@ -1110,6 +1107,7 @@ namespace SHADE mousePickSubSystem->HandleResize(); postOffscreenRenderSubSystem->HandleResize(); + //lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data())); worldViewport->SetWidth(static_cast(resizeWidth)); worldViewport->SetHeight(static_cast(resizeHeight)); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index bc9554c4..6beac351 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -16,6 +16,7 @@ #include "Graphics/Events/SHGraphicsEvents.h" #include "Graphics/MiddleEnd/Interface/SHRenderer.h" #include "Math/Transform/SHTransformComponent.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" namespace SHADE { @@ -594,7 +595,8 @@ namespace SHADE uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept { // Add to container of shadow maps - shadowMaps.emplace(lightEntity, newShadowMap); + shadowMapIndexing.emplace(lightEntity, shadowMaps.size()); + shadowMaps.emplace_back(newShadowMap); // Just use the image view stored in the resource Handle const NEW_IMAGE_VIEW = newShadowMap->GetImageView(); @@ -650,6 +652,28 @@ namespace SHADE cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, shadowMapMemoryBarriers); } + //void SHLightingSubSystem::HandleResize(Handle compute) noexcept + //{ + // uint32_t const NUM_SHADOW_MAPS = static_cast(shadowMaps.size()); + // for (uint32_t i = 0; i < NUM_SHADOW_MAPS; ++i) + // { + // // Just use the image view stored in the resource + // Handle const NEW_IMAGE_VIEW = shadowMaps[i]->GetImageView(); + + // // set new image view + // std::get>(shadowMapImageSamplers[i]) = NEW_IMAGE_VIEW; + + // // Set image for barrier + // shadowMapMemoryBarriers[i].image = shadowMaps[i]->GetImage()->GetVkImage(); + // } + + // if (NUM_SHADOW_MAPS > 0) + // { + // // modify descriptors in render graph node compute + // compute->ModifyWriteDescImageComputeResource (SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, shadowMapImageSamplers); + // } + //} + Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept { return lightingDataDescSet; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index f3a98d14..43d901fc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -23,6 +23,7 @@ namespace SHADE class SHSamplerCache; class SHVkImageView; class SHVkSampler; + class SHRenderGraphNodeCompute; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. struct SHDirectionalLightData @@ -72,7 +73,8 @@ namespace SHADE public: using DynamicOffsetArray = std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; static constexpr uint32_t MAX_SHADOWS = 200; - + static constexpr uint32_t SHADOW_MAP_WIDTH = 1024; + static constexpr uint32_t SHADOW_MAP_HEIGHT = 1024; private: class PerTypeData @@ -172,9 +174,11 @@ namespace SHADE //! Handle to sampler that all shadow map descriptors will use Handle shadowMapSampler; - //std::vector> shadowMaps; + //! For indexing shadow maps + std::unordered_map shadowMapIndexing; + //! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it - std::unordered_map> shadowMaps; + std::vector> shadowMaps; //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. //! It will also be preallocated. @@ -211,6 +215,7 @@ namespace SHADE void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; uint32_t AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; + //void HandleResize (Handle compute) noexcept; //void RemoveShadowMap (uint32_t index) noexcept; /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 5f8b8624..74ea951a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -54,7 +54,7 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) + void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, bool resizeWithWindow, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) { // If we set to if (w == static_cast(-1) && h == static_cast(-1)) @@ -64,7 +64,7 @@ namespace SHADE format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); + auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags, resizeWithWindow); renderGraphStorage->graphResources->try_emplace(resourceName, resource); } @@ -616,8 +616,11 @@ namespace SHADE // resize resources for (auto& [name, resource] : *renderGraphStorage->graphResources) { - if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) - resource->HandleResize(newWidth, newHeight); + if (resource->resizeWithWindow) + { + if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) + resource->HandleResize(newWidth, newHeight); + } } for (auto& node : nodes) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 6ee181f8..5abcd6b6 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -102,6 +102,7 @@ namespace SHADE ( std::string resourceName, std::initializer_list typeFlags, + bool resizeWithWindow = true, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index 5a34fa04..d0a88e86 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -78,7 +78,7 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } @@ -88,6 +88,7 @@ namespace SHADE , height{ h } , mipLevels{ levels } , resourceName{ name } + , resizeWithWindow { inResizeWithWindow } { // If the resource type is an arbitrary image and not swapchain image if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT) @@ -210,6 +211,7 @@ namespace SHADE , imageAspectFlags{ rhs.imageAspectFlags } , graphStorage{rhs.graphStorage} , infoTracker {std::move (rhs.infoTracker)} + , resizeWithWindow{rhs.resizeWithWindow} { } @@ -242,7 +244,8 @@ namespace SHADE mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; graphStorage = rhs.graphStorage; - infoTracker = std::move(infoTracker); + infoTracker = std::move(rhs.infoTracker); + resizeWithWindow = rhs.resizeWithWindow; return *this; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index 7ac2b824..b9fe219e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -96,11 +96,14 @@ namespace SHADE //! For tracking resource states in stages of the render graphs Handle infoTracker; + //! Whether or not to resize (recreate vulkan image) when window resizes + bool resizeWithWindow; + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; From 4a06032bea4167d487f83fc281509a7606a45248 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Wed, 11 Jan 2023 08:25:38 +0800 Subject: [PATCH 107/134] Shadows WIP --- Assets/Application.SHConfig | 2 +- Assets/Scenes/Scene2.shade | 25 ++++++++++++++- Assets/Shaders/DeferredComposite_CS.glsl | 29 ++++++++++-------- Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 6529 -> 6277 bytes Assets/Shaders/TestCube_FS.glsl | 5 ++- Assets/Shaders/TestCube_FS.shshaderb | Bin 2401 -> 2557 bytes Assets/Shaders/TestCube_VS.glsl | 5 ++- Assets/Shaders/TestCube_VS.shshaderb | Bin 3689 -> 3905 bytes .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 12 ++++++-- .../MiddleEnd/Lights/SHLightComponent.cpp | 5 +++ .../MiddleEnd/Lights/SHLightComponent.h | 1 + .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 12 ++++++-- .../MiddleEnd/Lights/SHLightingSubSystem.h | 1 + 13 files changed, 76 insertions(+), 21 deletions(-) diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 370665d2..10ba697b 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 86098106 +Starting Scene ID: 87285316 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 2f38a933..c8aa9c6d 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -5,8 +5,9 @@ Components: Transform Component: Translate: {x: 0, y: 0.304069757, z: 1.73034382} - Rotate: {x: 0, y: 0, z: 0} + Rotate: {x: -1.48352981, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Camera Component: Position: {x: 0, y: 0.304069757, z: 1.73034382} Pitch: 0 @@ -17,6 +18,7 @@ Near: 0.00999999978 Far: 10000 Perspective: true + IsActive: true Scripts: ~ - EID: 1 Name: Raccoon @@ -27,9 +29,11 @@ Translate: {x: 0, y: 0, z: 0} Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Renderable Component: Mesh: 149697411 Material: 126974645 + IsActive: true Scripts: ~ - EID: 3 Name: Bag @@ -40,9 +44,11 @@ Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Rotate: {x: -0, y: 2.79945588, z: 0} Scale: {x: 1.0000881, y: 1, z: 1.0000881} + IsActive: true Renderable Component: Mesh: 144838771 Material: 123745521 + IsActive: true Scripts: ~ - EID: 2 Name: DirectionalLight @@ -56,6 +62,7 @@ Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0 + IsActive: true Scripts: ~ - EID: 4 Name: AmbientLight @@ -69,4 +76,20 @@ Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0.600000024 + IsActive: true + Scripts: ~ +- EID: 5 + Name: Floor + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0.0810000002, z: 0} + Rotate: {x: -1.57079637, y: 0, z: 0} + Scale: {x: 50, y: 50, z: 50} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 124370424 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 2402d4f8..576ce74b 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -47,6 +47,11 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData AmbientLightStruct aLightData[]; } AmbLightData; +// bool IsInShadow (sampler2D shadowMap, vec2 coords, float depth, mat4 lightVP) +// { +// // vec4 fragPosLightPOV = lightVP * +// } + void main() { // convenient variables @@ -68,6 +73,16 @@ void main() vec4 shadowMapColor = vec4 (1.0f); + for (int i = 0; i < lightCounts.ambientLights; ++i) + { + if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) + { + // Just do some add + //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); + fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + } + } + for (int i = 0; i < lightCounts.directionalLights; ++i) { if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) @@ -81,32 +96,22 @@ void main() // Calculate the fragment color fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; + // If the shadow map is enabled (test the bit) if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) { // calculate shadow map here vec2 texCoord = vec2 (gl_GlobalInvocationID.xy) / vec2 (imageSize (targetImage)); - shadowMapColor = texture (shadowMaps[0], texCoord).xxxx; } } } - for (int i = 0; i < lightCounts.ambientLights; ++i) - { - if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) - { - // Just do some add - //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); - fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); - } - } - float ssaoVal = imageLoad (ssaoBlurredImage, globalThread).r; fragColor *= ssaoVal; // store result into result image imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); - imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapColor); + // imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapColor); //imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f)); } \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index fc527efa0308db8d380e4a8cfabff95cb1ce335b..633fd1975d4df1e6788128068fcfc40efa3fb9f7 100644 GIT binary patch literal 6277 zcmZveiJR4B6~})wFvB3Ak|Lx?gS220nu&@8I50M1Gb};0H~wbkGIR5C?{x1S7NdfQ zvLsq)U#%=l4J}(S%51THwST4Ud3v5cpWl7Y@QcTn=gc|hd)D`T&-=UdA6b?aYfks7 zd0Ez#U6d`#{@#JI#aTBOYkQ`em3#t~KKqK^CTpWZg=t&; zKw~^_R~z+hgN3~}TMD199;(y^tNZrNw5V>}-0VttUK^`SG}L>ue)Q=^t7`DxYULm* zcu%&fgtrp58eVTS_vf{ar}?g(#acz&_2{+gD}GT#J4-!dp}MMC0H{KAj9bob>>Bweac5?t%|nV{2ok-fpprz5)Zz(s4KHd984< z_g?-P!&R}@YQ3E-fqRdw=|;eK&nx_$j(q=EwK5yg>3bNw*iWk8ga00|fs*g;c5`OD zZS9T?bL5Kc7JV6KU#)htQlD&3>1SW!_El{Sr0F@2+t>I^jq#cs$y@huZu7FeVCDLq zQ|`oQbLGXp#c;Er6Co>b~!5AkQ-N zmB^mC`YL$YuCCps-S=F!t84E{cHeT@uCCpBchaNp%w=9zV8)AikAc~fSYHVz+?eR&Cs+Wy2?@3rt=s2?&e-cjVYKQZI< z_dS*SQ@6j^vvcf*;WxL4HMegd;?(u=2d<3qV_E!m1!jzX z(~!L%g}Ya|KF8p$=+(W7&4Khk4lnOjeI?YD?9RIO@K@JvUE`hevRz%f{cHad+_`>! z(w%+%!>+Es>oO*!8@`fi)>B@BXWX4VEk*YX#I*OLJ9lD|{udQEe^~lkU(B5Pdq3t9 z-;i|QU*x|8+5Gxn!Cz;qA2QbxxO(Ke0=ZMyJNk($}2o zem7k9y$)^;`@W99%C|r+b@y~zp=H?`PS~^DkT7w{Io|?)OGa`&g3WEZmR(x#&uEf8X`>Y?tBxF1Wtl!3ti6 z-y6^Qd@otyqi$bE;riIuF}S*Q-vc+Vn0=`qPgtDCiKOd)D#_MT{}|kRu&?lc5ZUjB zy7eD|x*%ugQMkU=H2zy~ zdio>!rI7RK_rdR%m}I}!`ZN5wYDMj~T^=AcGH*-Sv z?ESf%w|{|nZuVAKgUZD41psz0JYmu)n>Bg@w>At;z{4Yk=M?CVs1X)~imGk$bYmfXdMZPxa=D!Xq=U;=ak9g#N8M3(KD(81Dw4471 z_$#0rlWzW-pvb=t`DRETaqq_Wcq=6C@=Tm9F=gj!Lz11T%}E}BZ-M^JNp6KZ-|~OZ z#~tujK`!k>aP4yY?1kS6nZtRphi$W1PqrO-2Q&`U1`oXxu-XE6H8k)y9MP;d?y(;qCps1&93ewkaoXapKO1dK^q_I?7kP> z`Z2rjLp}~!PumG7V&9LfJ!bblWb=u~?0x`QJZATPWS4zu`yeD{U&?U~A3}~kP9c97 ziaxZ({=NT?B>TcNJ0C@NKD`rd-pfh2xcQCwI3yPOCy-Yccuz5ppDg4o6JN+Xc1Ax1 znODEtAbrez8m=vR|1@&+K8E}mD0AHkd>*o1ypt~^ zOk9e0@_?A7`F8Welg z_8_FMv-WjJd(6u>67~@MVdi@m{F{)tnBTfb;4bGy+ryBU^P+6-1@OnAMbHlJ>M{7Y z6DIER9H;Sp6#gAZyRpmQ--VulrqJiXzn8E^^8bFq?xRQJe*l?7+%q|oFyD0aCRe{7 zZm)9n14)<18U7I2GmP)ekC4TtAoFVzGv05B`DWn8KMDT{bS~-k|5Io_6#s8|3Rxd< zf0v!3pFvMSE^C~Hic2>selZtf`g^9oggjIA1@K=%<@ L+W$+ITcQ5}wX$pv literal 6529 zcmZvfiJR4B6~})pGsCKqD5OGzv`7+~iAV%8fR5PUU?AB#{Fu4S+`Qa7-Ft^c&BhEf zDzl{3DB26MY~QTRLT%so^{;4qo}Q=A=Xc*T{NnNTIh=F8=e*~f_q^x#&b9a8)3ajD zn7+Ix%cf;>viaHHJ5aVDn+}o{{P~Gr0iT<77kK}`j)7IJ_Qxht9Sfouy;E0VkB<+v+J|bDp<13nOy+SYkMjq4fXD<7k#|Zs=9es zwQ>LzyenH?!dnTu1YU16_vN*Yr}0)yVXb1{W$3l)=vaFoKU8UUa(D-)u`PK!@8nnu zzPFi=Zf?{XxEA%ShquP^k;Z{-`FJvP(d$0&YT?tB-2fjj$L7XFz1`vzvkDA2OYLsd z^IG9z?cMz69ZjW+_uyQlDXI`Vycs+Fl7ow^6Wi}R%X-p5X`EuE{L z%DtoAoEUC*@@scZ)rV|;aqFtK`qGq~#;t33qQ)4FZp&M@7Io=wT_c@qjn+-Ya(>45 zZ_C@w>OsUQ+}ZB*HTpj*+XZ%J%^hoJpLW+s(XZIoo!tV)z7lF*dNQsx`QBJeN%gi$ zn%C}ZOk1aB+ES^Hw#SNjISk&e9NgS!G?Q;vc0??1j#k=R_vNFN!tVjFskz`%orz;$ zotfy#K8@U0x~tQ@@7OTMUH)Is+-Lt=Q53TGB5wcBycco%U%nU5eiE#lzuZS{uDsMS zzrBaR*i%A1*Uan`c&n8+cI7qnp6tn_Z>mi+o0XAHQ^5N1^^KYfU6gdc?~5U8)ULh^ z@+|7h;bptJc9-@Q@UmT9yFJqGw_LWXYd7EZRO@%S;eeDf4{NvS=BvjoZW9kd-$tsH?RBsUbI_p=-OT8 zcaB|=KQQBqMPKxbUM)lpKlAFh7&86|xaaGI^of~|_?}P9efm55<@2dqU)1Z&m(QnO zw*L*?x%cP5xm0M4%ZP4#<@1OX^?0U5=-!c-_Fi=7PE68&PJ#0eOMl~w8B>4f$5`U) zlJ55x@y|v!zW(R)ul?$UjCCGdJz|}Y+{x=1W*2?bZmjaMR(oRp^wX#CHNU#wx62$$ z;KtD3n9Gv>R58Vjc`@9juQAn^3$Q}>4RGnd3U1x@#To%r){4M6v*O=Q zxpyO&d%ZvR$~Qr-rD!+6t*cD#doh@2)$ZBUeV4?vZ%eZK7J_bvF9zQMw;s>DH2r?? zToGTJKI%)Dnw#M}p{2;a6Y9o)DcoFQ=2!Qv5Q}rXJn8xmC)r%;qj1k{kHg;|zcHu$ zOe|tWPwmU?knfEC)^{f~4e~DUh8ru+|3+lvi)+6J?jG&d>kJ=(T+Y+m;qEtHd4+x< zmEDg)zl+%a4!F8Cc%FB{UE;=9_bqg3KiUzCJ#pR#!Hn-c``&q0Yp_nq{-1zrv;QaI z>c;yF+_Q+8Pu;gH&i_b~jpz9uhdz|kOQRK0b?%W(M=^K%cm2~}2C4D{h+k>+p-{U*b?WO$@yNOdfw+j*mo5G%!uxaq^ z_}PzhA$_%NpmX*~%sl?RyAZk{>H7QIOP@XLcXpOS`iKwGX}`5+K;n|ieBO`o?Ynm4 zFM~f5TAp;{KMN|ye>S>4;t~Hj$l{W#9KRP`d&GY(@`|Jz|5B(NeZ+Peb2{)nt zn@(mZl*ez#0`;hwz>d6}LaVTon zR)_TUyL>IAJ!ZO@FmadprbGH$LklwB_H@>E!o;P+)bIHwAY*BdGww(ByAGcN$oh$g z&p~8o`>qt{5VDxQG52EnJFmAvaaQN$4k*s5?RH3C=k#@u_L!H~C+tr6i8L>h$l_wo z%NyV>=VcOp7bNDqC>wh&{7uk&XppzAQLN%s!E0!3ZEAzy`}E^XH5-X-v_LE7UD`Fg^{ zUC#b=D8Bn|Ae&FWxQA~dN4`gpzXe4;ZO($e3*p~}w8tCtorH-?k>^olb7_xreiwNy z6z|Jp$YPH|&XYDV=Oy|iS9g}|n>_0N9zngx9tdF?A3q1diA#s;ApMr};e|~~27H9q`vgf*w{oeJ@ATj;o%wqa4hW{Ko zl62p;UqJJrc-wxNFmcy3$nVGce+6le+`mRPchvqHWHDD@zeN@^PGG-Fm~*o|y-~kM zcEA4GH$cPWwO;dTk2CxMxqOB{qL8~^|S diff --git a/Assets/Shaders/TestCube_FS.glsl b/Assets/Shaders/TestCube_FS.glsl index b6a1eab6..cb7bfefd 100644 --- a/Assets/Shaders/TestCube_FS.glsl +++ b/Assets/Shaders/TestCube_FS.glsl @@ -16,11 +16,12 @@ layout(location = 0) in struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } In; // material stuff -layout(location = 3) flat in struct +layout(location = 4) flat in struct { int materialIndex; uint eid; @@ -38,12 +39,14 @@ layout(location = 1) out uint outEntityID; layout(location = 2) out uint lightLayerIndices; layout(location = 3) out vec4 normals; layout(location = 4) out vec4 albedo; +layout(location = 5) out vec4 worldSpacePosition; void main() { position = In.vertPos; normals = In.normal; albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color; + worldSpacePosition = In.worldPos; outEntityID = In2.eid; lightLayerIndices = In2.lightLayerIndex; diff --git a/Assets/Shaders/TestCube_FS.shshaderb b/Assets/Shaders/TestCube_FS.shshaderb index abd90cf744ad1b20429e7740fe4354edc390101c..2974523d7405e05bdcf30d419f0663694bcc271b 100644 GIT binary patch delta 444 zcmYjLu}T9`5Zv|d@=WA3sJT*L!*Ke zWC_dzo|F6A>p}7$;y!ht4I}hs>iON})eTy48Yd%>06%vmkEtD{ar$!BfnvnEuD7e| zPoDhx7Kb;00O*OI4UlWj?c~EBuKb-xPQ(;3t`>aj#Xjtdpj^RZb?{}>X3jUkkMegF zm40$&qM!X^RG#|Zx2|uTzLp`kfDquyChSab2vBcf2~U%^k)NwhfE}O)(9g9UfI9s= bO+NQ`@uq(rnEQKpL$7257KFkKDffV1b_6lJ delta 288 zcmYk0ISRr+6o%h38G=#4jo67GT4-TmqqvR>Vq@(AY%J6!3N}_=Amko`4tO6c?;r&H zpC~x+G4n6;W}@69>!p`*`YbC}c8HiU%f*Ro&r9T4F&x2oo{Pm@;aTXon(H3|Ey#FFQ diff --git a/Assets/Shaders/TestCube_VS.glsl b/Assets/Shaders/TestCube_VS.glsl index 554ce379..041c552f 100644 --- a/Assets/Shaders/TestCube_VS.glsl +++ b/Assets/Shaders/TestCube_VS.glsl @@ -17,11 +17,12 @@ layout(location = 0) out struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } Out; // material stuff -layout(location = 3) out struct +layout(location = 4) out struct { int materialIndex; uint eid; @@ -49,6 +50,8 @@ void main() // gBuffer position will be in view space Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); + Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f); + // uvs for texturing in fragment shader Out.uv = aUV; diff --git a/Assets/Shaders/TestCube_VS.shshaderb b/Assets/Shaders/TestCube_VS.shshaderb index a1138f75c885a67d6cb7ac2abb1928fe9de3a08e..0467a41d3c9dffd337d9ea55d160e5a79bb1d13c 100644 GIT binary patch literal 3905 zcmZ9NX?GM=5QaP3fGh&CDu^?H21OASFp6vf1~8ByA?^-srU{LcnK+q*#V!5=@hADK z{Ng!2Pfu6q!_9fmt$J&@b?a77h9>_~=Tl4NsIEB48$ z+f&Dv`>o?APo2=^#bl)L)Mp!iu2Ha<<{jltU@O=K-Ujc3)8IPz4)nnq7~yZ2{T~vI z5;Zy1oSdGXoVwDSUs`G|_aC>jW;^d>%~sya=KJ|-rr*YjU*4H-ue7QTV|Y|+8RLwN zoZ+e^8`kB;w4e3zw0*79${rOqGuw$I$@12^ul2R_h5P-f^l{c3czcF-oL=dBwPcLE z-glwhyw+Lnr=9sM(qbDc`jB_}*+SO4oc2?gT5<&c#cnHW&*j;}8>uZRd|zk3lrCny zv~b0`~#N-I+=6%wer1Gst~QqY-qN)66ki%v5@FaF~8Qc-~?r>kX3WXASZ$ zZP7|+Lf-ldo`<@fKVj008Q8oFwoC1N>2f}J-*uaJ(zeoWuiLDDln1RFSuB*hv`;Qg+vw6^G`*R#0dC3jpyi+w! z-8g$3=gB=E=Y6Yj>c;&AB2F&iCh3KBn#+4ScZY!e4!wcwQg;TceQ`e2UE2K}sp`&$ zdgSx>McwnPC*IuNx`NYR&OJC|i+dKsJZAGsLL-dn0$O%o+Eoqi=yXzj^dmcb??5`wMNX_K4qs ztbH%`m)Jeqn)Tnwu1(&2>dvE_@%rutF8%kgYm53{M)o}QIB!3)`6K=SvN3z`tg{Pi zX_T`4-iLmOT~6Jz4zrtA{vbDUwzR7U^m_w+7-;tn>fU{23H!QKG!?!r9pv3qyz=23Ts<;-)EyWbM5E z=a9_R0MXkEC8zxwva!}>K6SqlIqg&I#%s5~H`zT~PWv>w{gsb;{H7wli9GOq_LeO; z`*MKzpV{k$Jm{0(U!&x-4eX-wyny{Ep6%QC%PH&huWd3pnTIFxNgHua7hS3NXhG zU=DSCBFC%9=5W>{hrbu{k>fRFbNGFjLtP*3&gh$99B4O(^Z6E#5B(ivXZ3Glv>ylh z$eYvN$c6t0$a3nw{fEGryG4AR{Uadf3hrZMIo~6=GbQKS%+Mj<`4eEg{@R`0r{vXk z7I?Nk-p^S+5Bxsj9n|%US}!7dx2W|~p*|Mvl~GFm=AS*;%>K)eTOYf=pptmfHf;?n=Rk_ zHnKMF*C_ZTk#kM+U&1%M17=IG6?wdC#LOWZWB!Qw5?Nljv{hriLN`V(V!lR}7p{nz z;SM*^zX8@_Zhh^O-=e(t*5_Lw7jODKvcECTiFf${=p%oTyiNAIz+UbLev|RmDYE`9 z&$`Pl7jZu#N1Web#LXicXZ^TWeBkmruarVSG{p4as7LX&(`!&$-1NrD- zUUKp-YcQX4;Qb$zoHMC!)btZ_e-pIpRsD{<8x zER}K51O4Re!BO@VFb#^drAabax_sqBD92qnWx_e3KUPID^nwWeh~${$70D&Z$C9g(mSkPBBiWOb^;gpV zuM$-h)$a7#YisS!?OuO8?oE&xH~8ks$vvtsp^cw zI)hbnhxYZMm-unug{#rP=iaq6Go5hG4+i^O>I;MI$4SR~=EoVEGq~g0Zo<`ERe8DZ zcGz2uCW#mIeM>7}HSI$XCH}S_uXu?kq~IIEGfJ|xO(38<186G`UTFyXD#FH!KpLF^&soPADSp) zG9NX|w;TrJl^}b^eINb9w;P80K6=9}v*;-^?QM9`wjZVM+0N%=PB`({%*m`|F}L|f z@H3-#l!G^AEo7Up%Kkf7g&Bu?z&UvU)5n}+SsZsN#$glJl~^vYgK^YbjKe1GFNwv0 zSzKE;q;_&~&!+Zy33Zy?kj}zp*0?v{DmL?h&BA6zigqivEg!!l_&JYy?9J&d%P{z0 z?1m8oM*W7NgJt!U(|mRp-j%c9oYslp4O!UeXB1V_UYBqVHhsZn&8a@#7Y=yltGJh> zlLOy%#bEQh0=AgvwENU$9~Dl1^1#Ptp1|<)OH3?&i$5hD|2g?z*3Q|~4F9xteBk86 zW*)(ahkHiCf`3*!KCAy#>70jc=e;hS{1$&fIx%O(tZPT8rIG9O`@HOV?O@oPwV<86 z;B&eWvxOhq1m4@SOA`Ft0lS%F_}|HOVz3vr&q%Q0V>63j)b)Y(x`dp(8^3oA2{=1B zKGM#;@sR_Y`2{1#W$pFchJQu+j07A$HuDWepX%DLNu2xh7W|vi$kmWwf2kcVH4u;8 zl7Qh~)(#&(y}YfRv%v6wt({(i+xdJy7QZPyNQibTDk*{!fg$X?}mi4;c!1@_m+h3!QKHI z9;KDunxwo2_uF)7Sm02>}**~S9jn$yf2{^a>M0KnQw6J z4d*)vn7!$SbiP}9&s`o!;DEQ3m+$y{3B6>tm~-w`*ZzY9K8v&9fmz&-(k+hJwz!|9 z6G#2T!2`3npQT&eL+KXxi*(}X332eiY({>SZgJeNA-g95w;pcg7&yy%$Q*EgFURQB zmc(lMO}gbS_Mk7E7#20b1GBh+bc-wYz!z?35eE;<;vN;^iaprQELEZ(l1HucVHwP4!F(5SbFhW|6Mj1%ibfF4n_|Ro8%bv*|(lZCmufj;agI_a9^e_#I(VS_DEFAULT); @@ -194,6 +196,7 @@ namespace SHADE // Initialize world render graph renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position World Space", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); //worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second); @@ -218,7 +221,8 @@ namespace SHADE "Albedo", "Depth Buffer", "SSAO", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, {}); // no predecessors @@ -231,6 +235,7 @@ namespace SHADE gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Albedo"); + gBufferSubpass->AddColorOutput("Position World Space"); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); @@ -277,7 +282,7 @@ namespace SHADE "Normals", "Albedo", "Scene", - "SSAO Blur" + "SSAO Blur", }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); @@ -763,6 +768,9 @@ namespace SHADE // Create new renderer for the light component and give it to the light component Handle newRenderer = resourceManager.Create(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); lightComp->SetRenderer (newRenderer); + + // assign shadow map index to light component + lightComp->SetShadowMapIndex (lightingSubSystem->GetNumShadowMaps()); } // Add the shadow map resource to the graph diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index 4dc6e83e..6943ec09 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -129,6 +129,11 @@ namespace SHADE renderer = newRenderer; } + void SHLightComponent::SetShadowMapIndex(uint32_t index) noexcept + { + lightData.shadowMapIndex = index; + } + SHLightData const& SHLightComponent::GetLightData(void) const noexcept { return lightData; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index 4019d2f4..4974f3f5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -55,6 +55,7 @@ namespace SHADE void SetStrength (float value) noexcept; // serialized void SetEnableShadow (bool flag) noexcept; void SetRenderer (Handle newRenderer) noexcept; + void SetShadowMapIndex (uint32_t index) noexcept; SHLightData const& GetLightData (void) const noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 6beac351..c3ba7ec3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -395,7 +395,7 @@ namespace SHADE switch (lightComp->GetLightData().type) { case SH_LIGHT_TYPE::DIRECTIONAL: - return SHMatrix::Transpose (SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(-0.7768f, 3.82611f, 9.23839f), SHVec3(-0.7619f, 3.30361f, 8.38588f), SHVec3(0.0f, -1.0f, 0.0f))); + return SHMatrix::Transpose (SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); case SH_LIGHT_TYPE::POINT: return {}; case SH_LIGHT_TYPE::SPOT: @@ -478,6 +478,7 @@ namespace SHADE //#endif shadowMapSampler = inShadowMapSampler; + shadowMaps.clear(); //numLightComponents = 0; #pragma endregion } @@ -516,7 +517,7 @@ namespace SHADE if (auto renderer = light.GetRenderer()) { //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() - renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(12.0f, 12.0f, 0.1f, 20.0f)); + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f)); } auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); @@ -595,7 +596,7 @@ namespace SHADE uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept { // Add to container of shadow maps - shadowMapIndexing.emplace(lightEntity, shadowMaps.size()); + shadowMapIndexing.emplace(lightEntity, static_cast (shadowMaps.size())); shadowMaps.emplace_back(newShadowMap); // Just use the image view stored in the resource @@ -684,4 +685,9 @@ namespace SHADE return shadowMapImageSamplers[index]; } + uint32_t SHLightingSubSystem::GetNumShadowMaps(void) const noexcept + { + return static_cast(shadowMaps.size()); + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index 43d901fc..7794a2fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -223,6 +223,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; std::tuple, Handle, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept; + uint32_t GetNumShadowMaps (void) const noexcept; }; } From 4cd9a6cea0af59019e70fd2780c1cc0775a4cab4 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Wed, 11 Jan 2023 10:35:29 +0800 Subject: [PATCH 108/134] shadows WIP --- Assets/Scenes/Scene2.shade | 10 +++---- Assets/Shaders/DeferredComposite_CS.glsl | 26 ++++++++++++------ Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 6277 -> 7493 bytes SHADE_Engine/src/Camera/SHCameraSystem.cpp | 4 ++- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 3 +- .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 5 ++-- .../MiddleEnd/Pipeline/SHPipelineLibrary.cpp | 3 +- 7 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index c8aa9c6d..de902c55 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -5,7 +5,7 @@ Components: Transform Component: Translate: {x: 0, y: 0.304069757, z: 1.73034382} - Rotate: {x: -1.48352981, y: 0, z: 0} + Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} IsActive: true Camera Component: @@ -26,8 +26,8 @@ NumberOfChildren: 1 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: -1.86388135, y: 0.0544953719, z: 0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true Renderable Component: @@ -56,9 +56,9 @@ NumberOfChildren: 0 Components: Light Component: - Position: {x: 0, y: 0, z: 0} + Position: {x: 3, y: 4.5, z: 7} Type: Directional - Direction: {x: 0, y: 0, z: 1} + Direction: {x: -0.298000008, y: 0.522498012, z: 0.798600018} Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0 diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 576ce74b..51f147bb 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -24,7 +24,8 @@ layout(set = 3, binding = 1, rgba32f) uniform image2D normals; layout(set = 3, binding = 2, rgba8) uniform image2D albedo; layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; -layout(set = 3, binding = 5, rgba8) uniform image2D targetImage; +layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace; +layout(set = 3, binding = 6, rgba8) uniform image2D targetImage; layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global) @@ -47,10 +48,12 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData AmbientLightStruct aLightData[]; } AmbLightData; -// bool IsInShadow (sampler2D shadowMap, vec2 coords, float depth, mat4 lightVP) -// { -// // vec4 fragPosLightPOV = lightVP * -// } +float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV) +{ + vec4 fragPosLightPOV = lightPV * worldSpaceFragPos; + vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f); + return step (fragPosLightPOV.z, texture(shadowMap, converted.xy).r); +} void main() { @@ -61,6 +64,9 @@ void main() vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; // Get position of fragment in world space + vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f); + + // Get position of fragment in view spacee vec3 positionView = imageLoad (positions, globalThread).rgb; // normal of fragment @@ -100,7 +106,7 @@ void main() if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) { // calculate shadow map here - vec2 texCoord = vec2 (gl_GlobalInvocationID.xy) / vec2 (imageSize (targetImage)); + fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx; } } } @@ -111,7 +117,11 @@ void main() // store result into result image imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); - // imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapColor); - //imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f)); + // vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f); + // vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords); + // if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f) + // shadowMapVal = vec4(0.0f); + + // imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx); } \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index 633fd1975d4df1e6788128068fcfc40efa3fb9f7..8a11aa08d53003ad9e277c52698e550336f1e4bb 100644 GIT binary patch literal 7493 zcmZ{n33#1V5r+R}2MR6wUQ!UPQh{Qnl$NEWG*nVrEEaGf+$J~am7CmfbJG??2qKH9 zC|Wmg7X-lt6mdlmRNPk-S40GNL0nh`eBb|`Nq_o0o<83*GvCaaGw1wsPH(yw@15nN zwPnA~ESr{Xoo$xhA?eEQ9 z%SYGO21<=eZFKq4G_MCaR@qptF0Bj=O^kCQ&TGq-AxqV@<-wYEM|Qk%wegCRPqzL% zt~2Y~lF#?moU^9jTT>}-z$90Dc4~od?!7%b4Q{knA1PIvk=D>Z#f|6lEG|EvzS3Fc zdUK6+&*GMr8l~nMHj8K1Q>)ep&G+CpnED>c(N51;LnV)C&(1;Shuu?~7;TKR^RAqO z&QjadMoZN^#CaY3bB?_|R;!FQk|%ikaeS;6G|`=Tyj@-zSz9Sj&1lwrE_}Ynw0=AB z7r`wl#IA1CCk7g>-Spv(T(RA}F6UX-c%xn(9d3A3Q@nLm#+Rg9u$i~6fr%>DWOzks z{0z>mGrI(?xPJ4Ln{)IzO8LIy{5!Hs;h0lk-Ct{V6@2royRsY5mo~5B)R}JHTSx9E zWb?VBd#=uNUt88M@4kxldq(o^Yp~hk&pIQ0ZD4Huic+Iq*@!x|hHp=^Ut(Wf*{9*Q zthsm|`W=IXoqK<7f@5BR^*lPWTc%=9$h*ICc7CPve!W9qvu2K^`3b#0_rOo}F-_=Q zxesovR4-WFJ$VsMpJb%STGX>F&2@kK=2U>cizmlkO#- z@9s8WFQD!FurKgj!=8=q`D^CJ2j~XI#GQ-$)+gsYe}l4le48nvHWE zj_)GL)&|xKk{kok9hAw(XXxF8lB(HLf(tr!H#rD3vxEu%%{E!T70|R zv#q#!&ACi_)(Cq~;_XA@y2-y)ijvzEduycmtWUpd8!NvXw%<-Y{M(}Im!Hkd?U2ql zuXFXA*ItviZu7by=gIGk?N7UI;5Z=Jv(O`cA9Ul*pay!uW9CW9g5x!rUBb$}hsN?OPZ5 zjzl+~@qWLhNbA#I9In>}T=UrEFxH&f%MurMU$SG5C+7C#QLb?^`u|(QbzS3>G~ZZr zYM+|8uzfQf#t$Mr2lwt8LrFJZak!7!z&XRoVXQf|*Co!gJOkZ)?mNCQKNmBED!eb4DFkpnJ~xuT1_9^5_N?B<0yB~Jqj%c(Sx&gWL)o$M*6FZ69)s~5T;nk0LSRp7`wsRL zY~Re|3%33>TiB-+Z0}vUU>on>CXwHKV+Gs$;NKPD*S@M?JO7q~?YnzN!8YH01>5)i z{(^11zXi>I1pD)hjsT0nIoQ5;M?E7pG_y6Z2YKPHiH0+#~!q_4Q{o3ZuZna=Anbo0qypK5svy8Jxw zDCc%L(qUct-U{TbOWiuWQ*Q%3$@W~{4x+A2=-q3 z(ax{XEc+d}2Q+{&p7rm+@xXoDmu&m|0rWqBsM}ok0_ROf{t@VR-u=m5n0n$**gF8% zGpGLeHh)IfA26T2_ZQ$f#&`H@;*5_omh+8>y(+cit|+yyMS2#>IE%lbdlvD2{T*HI z3SfSHa?ZaR>HKSu&VLB`Pw;TE7a;!y7J~Tw_HT4!|o%0W8C{eAo}7Ebp4L_zv4yc&X>0iW1eQFyuI*0T_-Rx literal 6277 zcmZveiJR4B6~})wFvB3Ak|Lx?gS220nu&@8I50M1Gb};0H~wbkGIR5C?{x1S7NdfQ zvLsq)U#%=l4J}(S%51THwST4Ud3v5cpWl7Y@QcTn=gc|hd)D`T&-=UdA6b?aYfks7 zd0Ez#U6d`#{@#JI#aTBOYkQ`em3#t~KKqK^CTpWZg=t&; zKw~^_R~z+hgN3~}TMD199;(y^tNZrNw5V>}-0VttUK^`SG}L>ue)Q=^t7`DxYULm* zcu%&fgtrp58eVTS_vf{ar}?g(#acz&_2{+gD}GT#J4-!dp}MMC0H{KAj9bob>>Bweac5?t%|nV{2ok-fpprz5)Zz(s4KHd984< z_g?-P!&R}@YQ3E-fqRdw=|;eK&nx_$j(q=EwK5yg>3bNw*iWk8ga00|fs*g;c5`OD zZS9T?bL5Kc7JV6KU#)htQlD&3>1SW!_El{Sr0F@2+t>I^jq#cs$y@huZu7FeVCDLq zQ|`oQbLGXp#c;Er6Co>b~!5AkQ-N zmB^mC`YL$YuCCps-S=F!t84E{cHeT@uCCpBchaNp%w=9zV8)AikAc~fSYHVz+?eR&Cs+Wy2?@3rt=s2?&e-cjVYKQZI< z_dS*SQ@6j^vvcf*;WxL4HMegd;?(u=2d<3qV_E!m1!jzX z(~!L%g}Ya|KF8p$=+(W7&4Khk4lnOjeI?YD?9RIO@K@JvUE`hevRz%f{cHad+_`>! z(w%+%!>+Es>oO*!8@`fi)>B@BXWX4VEk*YX#I*OLJ9lD|{udQEe^~lkU(B5Pdq3t9 z-;i|QU*x|8+5Gxn!Cz;qA2QbxxO(Ke0=ZMyJNk($}2o zem7k9y$)^;`@W99%C|r+b@y~zp=H?`PS~^DkT7w{Io|?)OGa`&g3WEZmR(x#&uEf8X`>Y?tBxF1Wtl!3ti6 z-y6^Qd@otyqi$bE;riIuF}S*Q-vc+Vn0=`qPgtDCiKOd)D#_MT{}|kRu&?lc5ZUjB zy7eD|x*%ugQMkU=H2zy~ zdio>!rI7RK_rdR%m}I}!`ZN5wYDMj~T^=AcGH*-Sv z?ESf%w|{|nZuVAKgUZD41psz0JYmu)n>Bg@w>At;z{4Yk=M?CVs1X)~imGk$bYmfXdMZPxa=D!Xq=U;=ak9g#N8M3(KD(81Dw4471 z_$#0rlWzW-pvb=t`DRETaqq_Wcq=6C@=Tm9F=gj!Lz11T%}E}BZ-M^JNp6KZ-|~OZ z#~tujK`!k>aP4yY?1kS6nZtRphi$W1PqrO-2Q&`U1`oXxu-XE6H8k)y9MP;d?y(;qCps1&93ewkaoXapKO1dK^q_I?7kP> z`Z2rjLp}~!PumG7V&9LfJ!bblWb=u~?0x`QJZATPWS4zu`yeD{U&?U~A3}~kP9c97 ziaxZ({=NT?B>TcNJ0C@NKD`rd-pfh2xcQCwI3yPOCy-Yccuz5ppDg4o6JN+Xc1Ax1 znODEtAbrez8m=vR|1@&+K8E}mD0AHkd>*o1ypt~^ zOk9e0@_?A7`F8Welg z_8_FMv-WjJd(6u>67~@MVdi@m{F{)tnBTfb;4bGy+ryBU^P+6-1@OnAMbHlJ>M{7Y z6DIER9H;Sp6#gAZyRpmQ--VulrqJiXzn8E^^8bFq?xRQJe*l?7+%q|oFyD0aCRe{7 zZm)9n14)<18U7I2GmP)ekC4TtAoFVzGv05B`DWn8KMDT{bS~-k|5Io_6#s8|3Rxd< zf0v!3pFvMSE^C~Hic2>selZtf`g^9oggjIA1@K=%<@ L+W$+ITcQ5}wX$pv diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 924100d4..703de2c0 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -313,7 +313,9 @@ namespace SHADE camera.orthoProjMatrix(2, 3) = -n / (f-n); camera.orthoProjMatrix(3, 3) = 1.0f; - //camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f); + camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(4.0f, 4.0f, 0.1f, 200.0f); //camera.projMatrix.Transpose(); camera.dirtyProj = false; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 64fc2431..14326b93 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -283,6 +283,7 @@ namespace SHADE "Albedo", "Scene", "SSAO Blur", + "Position World Space" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); @@ -290,7 +291,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Position World Space", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) { lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index c3ba7ec3..31f95921 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -395,7 +395,8 @@ namespace SHADE switch (lightComp->GetLightData().type) { case SH_LIGHT_TYPE::DIRECTIONAL: - return SHMatrix::Transpose (SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); + return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, lightComp->GetLightData().direction, SHVec3(0.0f, -1.0f, 0.0f))); + //return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); case SH_LIGHT_TYPE::POINT: return {}; case SH_LIGHT_TYPE::SPOT: @@ -517,7 +518,7 @@ namespace SHADE if (auto renderer = light.GetRenderer()) { //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() - renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f)); + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f)); } auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index 6d7e6104..a5dd929c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -17,7 +17,7 @@ namespace SHADE SHPipelineLayoutParams params { - .shaderModules = std::move (modules), + .shaderModules = std::move(modules), .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts }; @@ -35,6 +35,7 @@ namespace SHADE auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); colorBlendState.attachments.reserve(subpassColorReferences.size()); + for (auto& att : subpassColorReferences) { colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState From f217562fefe0f546dbdb2d760c8a0320e43da6a4 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Wed, 11 Jan 2023 20:04:53 +0800 Subject: [PATCH 109/134] Shadows are sort of working --- Assets/Application.SHConfig | 2 +- Assets/Scenes/MainGame.shade | 9 +++++++-- Assets/Shaders/DeferredComposite_CS.glsl | 14 +++++++++++++- Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 7493 -> 8333 bytes SHADE_Engine/src/Camera/SHCameraSystem.cpp | 2 +- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 9 +++++++-- .../MiddleEnd/Interface/SHGraphicsSystem.h | 1 + .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 4 ++-- .../MiddleEnd/Pipeline/SHPipelineLibrary.cpp | 4 +++- .../MiddleEnd/Pipeline/SHPipelineLibrary.h | 3 ++- 10 files changed, 37 insertions(+), 11 deletions(-) diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 10ba697b..370665d2 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 87285316 +Starting Scene ID: 86098106 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Scenes/MainGame.shade b/Assets/Scenes/MainGame.shade index 49602e78..69bb9e7d 100644 --- a/Assets/Scenes/MainGame.shade +++ b/Assets/Scenes/MainGame.shade @@ -8440,10 +8440,15 @@ IsActive: true NumberOfChildren: 0 Components: + Transform Component: + Translate: {x: 2.05652523, y: 1.65113854, z: -6.62914371} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true Light Component: - Position: {x: 0, y: 0, z: 0} + Position: {x: 0, y: 1.5, z: -6.71799994} Type: Directional - Direction: {x: 15, y: 90, z: 15} + Direction: {x: 0, y: 0, z: -1.11899996} Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 1 diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 51f147bb..b31daf25 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -52,7 +52,19 @@ float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV { vec4 fragPosLightPOV = lightPV * worldSpaceFragPos; vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f); - return step (fragPosLightPOV.z, texture(shadowMap, converted.xy).r); + + float sampledDepth = texture(shadowMap, converted.xy).r; + + if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f) + return 1.0f; + + if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f) + { + return 0.3f; + } + else + return 1.0f; + // return step (fragPosLightPOV.z, ); } void main() diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index 8a11aa08d53003ad9e277c52698e550336f1e4bb..31ea035c0a64e3e947bae4ceb483ce0661300999 100644 GIT binary patch literal 8333 zcmZ{n37A%86~`|Ov&fDsDBz5^paP2F2B{$ENI_s2TKU9tnfVyL{ARxKn{RN*3PX!F z&9VZ_$`&)Mv}`fUGPP{8eJ|5Cv$8$c()#`Gy=T16^Yr>0&pH2d-gC}-?s?z&=)9~m z$yUqQIqgX@CK;bhN*0XCv1!RzkR*{WgilD?GQE4%x>XB?n!O7a9ecE%lam%%W}AXf zEAlv~Kdlak_d!#^#inJldhXxC-m%Dcl4u;+yH{=KUbCiq)oB}g1_w6`H7}}FHq@#E zl?}bsMy01&-BQu7qvTf|=&23&mK|F0DCch_?w;gWp4NKSZBBdZ7pzZf!8KCq?IXjXc&y=}={_)ywESgZ7|s0=nYqh>L*_tokf z)7n{^8N_}*ig3bO7yI6tI~@qjXcL&pM|YRn`xe72e>_5Ua!@0Wq(_;3qJCl3PUTibS-!_ z^Jz`4hi4yQd3|`GImE7x3;G|ipcFh{I7ZdRB3tZS&*s0{SwvtnK1 z)>R!^R@{#K9OBm1GhE~P^sP>Z&ZBSb$;ZLU`SUL4d$hUI?A+1+w&WHt_LNZ1*OJ@| zp7**V`6=>>{ECkB^qI4@Wp-Si={vIZyU%ltu3y}9mFu@h;-0HFAMt1PNZUAQaLekn z*{EKKIFiFRDW8`(S4Z-5u+cS_`=Q;{TROS3cOMx0N~ry4PaYiceL*(;)r+&Mp3UpS z+VYxdOa2MHKW!X-WR4j^@5*?v!L*U~vqyd6D1Be|45f8mG3@Qhj6y%PHr!}bdRO+R zeZ}2xO}el((?(yVnZw=0^F5vb&4ko_9}a@-Yv^6b_Fvu0Ubd@ix2M{-jk2q2cWL+T zm-nk{A5+-9_hq}fcI!EVEZ#}ioScnd?icf$ho3czb(ApUh)smLiE2Fktj#-W?x;oG z+%98!k6i9|1s1veI~G{v_HRI7k$XCr`EG`{L7k93apxkw^@+JpfA3zoK6UGhGduIH z*l$d+sLwM87WGBVahKfNnfZ;&_8Qx78~fDtIeHYv4~Fb-WB9p8zd^{_e+KugTOobo zK1HpbRjdWl-+NU)tGZ|PEZV&*+N~#a?Jjlif%b@}u08y_M%mT1Tci8uqkAuAKzlJE z_N$9%##7!GDZbr|WDjm$zL#y!TA?3+zjLTxC-L_vyu|iH9}hR4^=UV^zT(r-{dUS> zpM&QZ%jU4_5BI|Dq?ec>m)+zJQ zjB^Mi7G&Nd(Dk)fv2Q-IEAkwbtNc#Ne^Z9v;tbzuDt@c2XWp_$nF(if?d6@!1S*o8&7|~dmZjM-BVuXi*Mx} zaOrDIb>CT6=-H1bbYor$|9>&f<2hafcj;>k^=$&I(0yB7`dCx`y?8s^c%Cz6VJEWRIcOePo!e_5ziXMy@h&jyN+G|m{N0diHeI+L zZjLg!??YhLs@>YueXqqL&WDlXyY4P*#xd?qaO<+q&%|!Y-ehgF+3DMRGi1I`z>O_t zK6T$;G3~b(vN0q7UC3h!``v}ze6x88d~dxwk=uRV#c-b;O~!*|j5(>%X`n^Vj> z)bA^>$a{aG>;F(8n=9;3A^Seh#6FG!eS?-l`nOszOWgSCzO}B{-+>;pJqg)*tlhcV zPk-cM3sS!HnF5((dSTSp9O}N$E_LrmSNNdMLAEc(um(JN$4-H=e%@qrOS#{x%F(PpR*x&+;K?BxY^CS6I9&nqxk z5?HOk2$ihGZzH@P(pTHbbk;tKnWqkKK<5{_{`{29d^WP*Ip?1^nUDAyrq9_NE^uuw z^ZEUZ?|0E2@h?R7y;L{;MUXW_{ELzG5s&zh zZ7tpPJgo}?Mb}3>>V6%vxa5kujlUILd&GYO zvTuI$<&DVY_-{hjM?B)c8ChI%mE$|#+KuPmfVV-u{}KOcO z3v3xR?MA*4x&iXvrTXKv9=A>(h5U{ELwGn3FpSOxzW7ayd1c>r0UN?tmiSoyd{zZsadRkx$!Q zkiKp3uRz+@q8aa=0uz@a&sUMnrQN;yehu0IU0T%g^#ap3=1k0ai9X5IohADwkGj8s zY~5Rlm%_gZiCM4lw277H^SZ)zFWf$A`xe~Ta%cBD@b5w{?calImq+gJBO4=T_Xo&g zF}puRc6Q@i%|iYWBp$Q-V`TSnv9M1p zX6H}nW1!Oto8Rm~WO3uW=g*K>=zl@p4qeSRZ-f68(nowE_gL(2ka6ci^C5kV{V-fx z)c$wmsQq^2e?U>Ywz&V^vws%$xM%+=Fmadp#zMxnhDRXt#XWhnz{I7vCyyZ;OM9I0 zapVCge4aqoPdt2{MBV|#UHUh&n7(nB#Nw>~L5{QTMt&NKvub+^(svg8zmWEr7Y`@4 z6xvPSeRs!rU`Wiju0@^Yyl5K>i8(LIQAay+UPmjxLiu+vy1!dvPVDsr^eu4D;cq8( z=iJ}0lcA{FSpLQ}_C)-r6n6Ld8%zDfVkV{{?^)zCruO(Y(~z|X8PD0<6U-jRci0PE zO#kSym~TX!RjwX)MXv69VlU*;i@ou+7x8}WgDw{Dmo_o?`!>1Xx554XCf^_O_qh5- z@B@&0;qm)wX5k|qzl&xei@Q97zdgl_;oQzf7E`we2O`^pD~dO}6J1Qd=z*C2b^H!O z_TL2R74(CV``~N%4s(zXfy5-2%s15f4@J=)xer4&cho)?UCb5O;RPlf*bxOb7A$`I z9SP=s{k1Q~)ek>)KLlzgaW_uuJ zz7F`|kUdp*-j0OyabAvq&nqx-*BIy=Z1!UT*|KPtV{fKNX)vFqpmZMN7uCyOg#GaJY=!xSHzJ= zUC&20x3%hT4(nJAcUgx%s~|D!P<|S2Ty^oNYb~<(WepVlIultu^cNyKYf~+ X46+VodvI={ixhA?eEQ9 z%SYGO21<=eZFKq4G_MCaR@qptF0Bj=O^kCQ&TGq-AxqV@<-wYEM|Qk%wegCRPqzL% zt~2Y~lF#?moU^9jTT>}-z$90Dc4~od?!7%b4Q{knA1PIvk=D>Z#f|6lEG|EvzS3Fc zdUK6+&*GMr8l~nMHj8K1Q>)ep&G+CpnED>c(N51;LnV)C&(1;Shuu?~7;TKR^RAqO z&QjadMoZN^#CaY3bB?_|R;!FQk|%ikaeS;6G|`=Tyj@-zSz9Sj&1lwrE_}Ynw0=AB z7r`wl#IA1CCk7g>-Spv(T(RA}F6UX-c%xn(9d3A3Q@nLm#+Rg9u$i~6fr%>DWOzks z{0z>mGrI(?xPJ4Ln{)IzO8LIy{5!Hs;h0lk-Ct{V6@2royRsY5mo~5B)R}JHTSx9E zWb?VBd#=uNUt88M@4kxldq(o^Yp~hk&pIQ0ZD4Huic+Iq*@!x|hHp=^Ut(Wf*{9*Q zthsm|`W=IXoqK<7f@5BR^*lPWTc%=9$h*ICc7CPve!W9qvu2K^`3b#0_rOo}F-_=Q zxesovR4-WFJ$VsMpJb%STGX>F&2@kK=2U>cizmlkO#- z@9s8WFQD!FurKgj!=8=q`D^CJ2j~XI#GQ-$)+gsYe}l4le48nvHWE zj_)GL)&|xKk{kok9hAw(XXxF8lB(HLf(tr!H#rD3vxEu%%{E!T70|R zv#q#!&ACi_)(Cq~;_XA@y2-y)ijvzEduycmtWUpd8!NvXw%<-Y{M(}Im!Hkd?U2ql zuXFXA*ItviZu7by=gIGk?N7UI;5Z=Jv(O`cA9Ul*pay!uW9CW9g5x!rUBb$}hsN?OPZ5 zjzl+~@qWLhNbA#I9In>}T=UrEFxH&f%MurMU$SG5C+7C#QLb?^`u|(QbzS3>G~ZZr zYM+|8uzfQf#t$Mr2lwt8LrFJZak!7!z&XRoVXQf|*Co!gJOkZ)?mNCQKNmBED!eb4DFkpnJ~xuT1_9^5_N?B<0yB~Jqj%c(Sx&gWL)o$M*6FZ69)s~5T;nk0LSRp7`wsRL zY~Re|3%33>TiB-+Z0}vUU>on>CXwHKV+Gs$;NKPD*S@M?JO7q~?YnzN!8YH01>5)i z{(^11zXi>I1pD)hjsT0nIoQ5;M?E7pG_y6Z2YKPHiH0+#~!q_4Q{o3ZuZna=Anbo0qypK5svy8Jxw zDCc%L(qUct-U{TbOWiuWQ*Q%3$@W~{4x+A2=-q3 z(ax{XEc+d}2Q+{&p7rm+@xXoDmu&m|0rWqBsM}ok0_ROf{t@VR-u=m5n0n$**gF8% zGpGLeHh)IfA26T2_ZQ$f#&`H@;*5_omh+8>y(+cit|+yyMS2#>IE%lbdlvD2{T*HI z3SfSHa?ZaR>HKSu&VLB`Pw;TE7a;!y7J~Tw_HT4!|o%0W8C{eAo}7Ebp4L_zv4yc&X>0iW1eQFyuI*0T_-Rx diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 703de2c0..6feece48 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -315,7 +315,7 @@ namespace SHADE //camera.perspProjMatrix = SHMatrix::OrthographicLH(9.0f, 9.0f, 0.1f, 20.0f); camera.orthoProjMatrix = SHMatrix::OrthographicRH(camera.GetWidth(), camera.GetHeight(), camera.GetNear(), camera.GetFar()); - //camera.perspProjMatrix = SHMatrix::OrthographicLH(4.0f, 4.0f, 0.1f, 200.0f); + //camera.perspProjMatrix = SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f); //camera.projMatrix.Transpose(); camera.dirtyProj = false; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 14326b93..79053c2f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -181,6 +181,8 @@ namespace SHADE // Create Default Viewport worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); + shadowMapViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(SHLightingSubSystem::SHADOW_MAP_WIDTH), static_cast(SHLightingSubSystem::SHADOW_MAP_HEIGHT), 0.0f, 1.0f)); + std::vector> renderContextCmdPools{ swapchain->GetNumImages() }; for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) { @@ -781,7 +783,7 @@ namespace SHADE auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map - auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, lightComp->GetRenderer()); + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer()); newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); // regenerate the node @@ -793,8 +795,11 @@ namespace SHADE SHPipelineLibrary tempLibrary{}; Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); + SHRasterizationState rasterState{}; + rasterState.cull_mode = vk::CullModeFlagBits::eBack; + tempLibrary.Init(device); - tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState()); + tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState(), rasterState); shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); } newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index b8c43c75..9e30e204 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -441,6 +441,7 @@ namespace SHADE #endif Handle worldViewport; // Whole screen + Handle shadowMapViewport; std::vector> viewports; // Additional viewports // Renderers diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 31f95921..2e3b21d9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -395,7 +395,7 @@ namespace SHADE switch (lightComp->GetLightData().type) { case SH_LIGHT_TYPE::DIRECTIONAL: - return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, lightComp->GetLightData().direction, SHVec3(0.0f, -1.0f, 0.0f))); + return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, SHVec3::Normalise (lightComp->GetLightData().direction), SHVec3(0.0f, -1.0f, 0.0f))); //return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); case SH_LIGHT_TYPE::POINT: return {}; @@ -518,7 +518,7 @@ namespace SHADE if (auto renderer = light.GetRenderer()) { //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() - renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(5.0f, 5.0f, 0.1f, 20.0f)); + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(30.0f, 30.0f, 1.0f, 50.0f)); } auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index a5dd929c..74795034 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -7,7 +7,7 @@ namespace SHADE { - Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept { std::vector> modules{}; if (vsFsPair.first) @@ -53,6 +53,8 @@ namespace SHADE } newPipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + newPipeline->GetPipelineState().SetRasterizationState(rasterState); // Actually construct the pipeline newPipeline->ConstructPipeline(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index b7485e50..ca46c71a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -34,7 +34,8 @@ namespace SHADE std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, - SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState() + SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(), + SHRasterizationState const& rasterState = SHRasterizationState{} ) noexcept; Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; From 13d562505533707e921a7f900717ed49a163bef7 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 13 Jan 2023 15:18:35 +0800 Subject: [PATCH 110/134] 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 From ef5016351b2e10e37a51361b32426b2855499006 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Fri, 13 Jan 2023 15:18:35 +0800 Subject: [PATCH 111/134] 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 From dab109bc771b950548087178194c1180cf739671 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 02:43:31 +0800 Subject: [PATCH 112/134] 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(); From 19bffc91247f92774083390d1e318179972cadb8 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 02:44:27 +0800 Subject: [PATCH 113/134] 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 From 85f0902c2d7282baae7e7e6935223c6cd626ea46 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 03:48:08 +0800 Subject: [PATCH 114/134] 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 From 5aa7bfe03e5b1937d43f570db51cef6786862e01 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 07:34:44 +0800 Subject: [PATCH 115/134] button fixed --- Assets/Editor/Editor.SHConfig | 4 ++++ Assets/Scenes/UI Test.shade.shmeta | 2 +- SHADE_Engine/src/UI/SHUISystem.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Assets/Editor/Editor.SHConfig diff --git a/Assets/Editor/Editor.SHConfig b/Assets/Editor/Editor.SHConfig new file mode 100644 index 00000000..51425027 --- /dev/null +++ b/Assets/Editor/Editor.SHConfig @@ -0,0 +1,4 @@ +Start Maximized: true +Working Scene ID: 97161771 +Window Size: {x: 1920, y: 1080} +Style: 0 \ No newline at end of file diff --git a/Assets/Scenes/UI Test.shade.shmeta b/Assets/Scenes/UI Test.shade.shmeta index ad821810..9b0a85f5 100644 --- a/Assets/Scenes/UI Test.shade.shmeta +++ b/Assets/Scenes/UI Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI Test -ID: 88543249 +ID: 92992815 Type: 5 diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 95663bc0..cd4ed79a 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -158,7 +158,7 @@ namespace SHADE SHVec2 mousePos; SHVec2 windowSize; #ifdef SHEDITOR - windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; //mousePos.y = windowSize.y - mousePos.y; SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) From 5190c490c9e3a6805cd9b27126c07d1e4852c6fb Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 11:36:12 +0800 Subject: [PATCH 116/134] added events --- Assets/Scenes/UI Test.shade | 4 +- Assets/Scenes/UI Test.shade.shmeta | 2 +- SHADE_Engine/src/Events/SHEventDefines.h | 1 + .../src/UI/Events/SHButtonClickEvent.h | 16 +++ SHADE_Engine/src/UI/SHSliderComponent.cpp | 39 ++++++++ SHADE_Engine/src/UI/SHSliderComponent.h | 41 ++++++++ SHADE_Engine/src/UI/SHUISystem.cpp | 98 ++++++++++++++++--- SHADE_Engine/src/UI/SHUISystem.h | 16 ++- 8 files changed, 196 insertions(+), 21 deletions(-) create mode 100644 SHADE_Engine/src/UI/Events/SHButtonClickEvent.h create mode 100644 SHADE_Engine/src/UI/SHSliderComponent.cpp create mode 100644 SHADE_Engine/src/UI/SHSliderComponent.h diff --git a/Assets/Scenes/UI Test.shade b/Assets/Scenes/UI Test.shade index 0aea6f72..d9ce5026 100644 --- a/Assets/Scenes/UI Test.shade +++ b/Assets/Scenes/UI Test.shade @@ -34,7 +34,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 153.399994, y: 0, z: 0} + Translate: {x: 0, y: -3.9000001, z: 0} Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} IsActive: true @@ -45,7 +45,7 @@ Toggle Button Component: Non Toggled Texture: 0 Toggled Texture: 0 - Value: false + Value: true IsActive: true Scripts: ~ - EID: 1 diff --git a/Assets/Scenes/UI Test.shade.shmeta b/Assets/Scenes/UI Test.shade.shmeta index 9b0a85f5..0ce3b040 100644 --- a/Assets/Scenes/UI Test.shade.shmeta +++ b/Assets/Scenes/UI Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI Test -ID: 92992815 +ID: 92642496 Type: 5 diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index d7bbf5f0..1ad458c4 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -18,4 +18,5 @@ 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_BUTTON_CLICK_EVENT { 13 }; diff --git a/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h b/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h new file mode 100644 index 00000000..35bcdc61 --- /dev/null +++ b/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h @@ -0,0 +1,16 @@ +#pragma once + + +#include "ECS_Base/SHECSMacros.h" + +namespace SHADE +{ + struct SHButtonClickEvent + { + EntityID EID; + // value of the toggle button, default to false if its a button and not a toggle button + bool value{false}; + }; + + +} diff --git a/SHADE_Engine/src/UI/SHSliderComponent.cpp b/SHADE_Engine/src/UI/SHSliderComponent.cpp new file mode 100644 index 00000000..56d1d89b --- /dev/null +++ b/SHADE_Engine/src/UI/SHSliderComponent.cpp @@ -0,0 +1,39 @@ +#include "SHpch.h" +#include "SHSliderComponent.h" + +namespace SHADE +{ + SHSliderComponent::SHSliderComponent() + :size(1.0f), isHovered(false), isClicked(false), value(0.0f) + { + + } + + + float SHSliderComponent::GetValue() const noexcept + { + return value; + } + + void SHSliderComponent::SetValue(float value) noexcept + { + this->value = value; + } + + + +} + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Slider Component") + .property("Slider Value", &SHSliderComponent::GetValue, &SHSliderComponent::SetValue) + + ; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHSliderComponent.h b/SHADE_Engine/src/UI/SHSliderComponent.h new file mode 100644 index 00000000..bdc57c7e --- /dev/null +++ b/SHADE_Engine/src/UI/SHSliderComponent.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "SH_API.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec2.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + + class SH_API SHSliderComponent final: public SHComponent + { + public: + SHSliderComponent(); + virtual ~SHSliderComponent() = default; + + SHVec2 size; + + + float GetValue() const noexcept; + + + void SetValue(float value) noexcept; + + + friend class SHUISystem; + private: + + bool isHovered; + bool isClicked; + + float value; + + RTTR_ENABLE() + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index cd4ed79a..bb98939b 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -10,6 +10,13 @@ #include "Editor/SHEditor.h" #include "Resource/SHResourceManager.h" #include "Input/SHInputManager.h" +#include "SHUIComponent.h" +#include "SHButtonComponent.h" +#include "SHToggleButtonComponent.h" +#include "SHSliderComponent.h" +#include "SHCanvasComponent.h" +#include "Events/SHEventManager.hpp" +#include "Events/SHButtonClickEvent.h" namespace SHADE { @@ -164,32 +171,60 @@ namespace SHADE SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) mousePos /= windowSize; SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + + + +#else + + int x, y; + SHInputManager::GetMouseScreenPosition(&x, &y); + mousePos.x = x; + mousePos.y = y; + auto ws = SHSystemManager::GetSystem()->GetWindow()->GetWindowSize(); + windowSize = { ws.first,ws.second }; + mousePos /= windowSize; #endif SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; //SHLOG_INFO("TopExtent: {}, {}", topExtent.x, topExtent.y) - topExtent = CanvasToScreenPoint(topExtent); - btmExtent = CanvasToScreenPoint(btmExtent); + topExtent = CanvasToScreenPoint(topExtent,true); + btmExtent = CanvasToScreenPoint(btmExtent,true); //SHLOG_INFO("TopExtent: {}, {} Btm Extent: {}, {}", topExtent.x, topExtent.y, btmExtent.x, btmExtent.y) - topExtent /= camSize; - btmExtent /= camSize; + comp.isClicked = false; if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) { comp.isHovered = true; +#ifdef SHEDITOR + if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + } +#else if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); } - SHLOG_INFO("HOVERED") +#endif + + //SHLOG_INFO("HOVERED") } else { comp.isHovered = false; - SHLOG_INFO("NOT HOVERED") + //SHLOG_INFO("NOT HOVERED") } @@ -222,9 +257,25 @@ namespace SHADE SHVec2 mousePos; SHVec2 windowSize; + #ifdef SHEDITOR - windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; + //mousePos.y = windowSize.y - mousePos.y; + SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + mousePos /= windowSize; + SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + + + +#else + + int x, y; + SHInputManager::GetMouseScreenPosition(&x, &y); + mousePos.x = x; + mousePos.y = y; + auto ws = SHSystemManager::GetSystem()->GetWindow()->GetWindowSize(); + windowSize = { ws.first,ws.second }; mousePos /= windowSize; #endif @@ -232,10 +283,9 @@ namespace SHADE - topExtent = CanvasToScreenPoint(topExtent); - btmExtent = CanvasToScreenPoint(btmExtent); - topExtent /= camSize; - btmExtent /= camSize; + topExtent = CanvasToScreenPoint(topExtent,true); + btmExtent = CanvasToScreenPoint(btmExtent, true); + comp.isClicked = false; @@ -243,11 +293,30 @@ namespace SHADE && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) { comp.isHovered = true; +#ifdef SHEDITOR + if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + comp.value = !comp.value; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + clickEvent.value = comp.value; + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + } +#else if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; comp.value = !comp.value; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + clickEvent.value = comp.value; + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); } +#endif } else { @@ -284,7 +353,7 @@ namespace SHADE } } - SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint) noexcept + SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept { SHVec2 result{canvasPoint}; @@ -296,7 +365,10 @@ namespace SHADE result.y *= -1.0f; result += camSize * 0.5f; - return result; + if (normalized) + return result / camSize; + else + return result; } diff --git a/SHADE_Engine/src/UI/SHUISystem.h b/SHADE_Engine/src/UI/SHUISystem.h index a5ba8c4f..ae1091ec 100644 --- a/SHADE_Engine/src/UI/SHUISystem.h +++ b/SHADE_Engine/src/UI/SHUISystem.h @@ -3,15 +3,20 @@ #include "SH_API.h" #include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystemRoutine.h" -#include "SHUIComponent.h" -#include "SHButtonComponent.h" -#include "SHToggleButtonComponent.h" -#include "SHCanvasComponent.h" + #include "Scene/SHSceneGraph.h" #include "Scene/SHSceneManager.h" +#include "Math/Vector/SHVec2.h" namespace SHADE { + + class SHButtonComponent; + class SHUIComponent; + class SHToggleButtonComponent; + class SHSliderComponent; + class SHCanvasComponent; + class SH_API SHUISystem final: public SHSystem { public: @@ -67,7 +72,8 @@ namespace SHADE void UpdateButtonComponent(SHButtonComponent& comp) noexcept; void UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept; void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept; - SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint) noexcept; + + SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept; From 02ba0c6dc91b8ca172659c3499617f4729a75a6d Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 11:44:34 +0800 Subject: [PATCH 117/134] merge --- Assets/Scenes/UI_Test.shade.shmeta | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Scenes/UI_Test.shade.shmeta b/Assets/Scenes/UI_Test.shade.shmeta index 0ce3b040..77355480 100644 --- a/Assets/Scenes/UI_Test.shade.shmeta +++ b/Assets/Scenes/UI_Test.shade.shmeta @@ -1,3 +1,3 @@ -Name: UI Test -ID: 92642496 +Name: UI_Test +ID: 87244611 Type: 5 From 34f22808eea325b514162d5e21f781270772364c Mon Sep 17 00:00:00 2001 From: SHAM-DP Date: Mon, 16 Jan 2023 14:07:44 +0800 Subject: [PATCH 118/134] transition scenescave prompt --- .../EditorPopups/SHEditorPopups.h | 3 +- .../src/Editor/EditorWindow/SHPopUpWindow.h | 6 ++- SHADE_Engine/src/Editor/SHEditor.cpp | 46 ++++--------------- SHADE_Engine/src/Editor/SHEditor.h | 6 --- 4 files changed, 16 insertions(+), 45 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h index f1ce4fb5..9e37a98a 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h +++ b/SHADE_Engine/src/Editor/EditorWindow/EditorPopups/SHEditorPopups.h @@ -1,10 +1,11 @@ #pragma once +#include "SH_API.h" #include "Editor/EditorWindow/SHPopUpWindow.h" namespace SHADE { - class SHSceneSavePrompt : SHPopUpWindow + class SHSceneSavePrompt : public SHPopUpWindow { public: SHSceneSavePrompt():SHPopUpWindow("Save Scene As", true, 0, 0){} diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h index 5d4e5117..b69b3e99 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHPopUpWindow.h @@ -5,6 +5,7 @@ //#==============================================================# #include #include +#include "SH_API.h" namespace SHADE { @@ -13,9 +14,11 @@ namespace SHADE { public: SHPopUpWindow(std::string_view const& name, bool modal, ImGuiPopupFlags inPopupFlags, ImGuiWindowFlags inWindowFlags); - + virtual ~SHPopUpWindow() = default; virtual void Draw(){}; + bool isOpen; + protected: virtual bool Begin(); @@ -23,7 +26,6 @@ namespace SHADE std::string_view windowName; ImGuiPopupFlags popupFlags; ImGuiWindowFlags windowFlags; - bool isOpen; bool isModal; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 4556ae36..fba1c591 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -32,6 +32,9 @@ #include "EditorWindow/SHEditorWindowManager.h" #include "EditorWindow/SHEditorWindowIncludes.h" +#include "EditorWindow/SHPopUpWindow.h" +#include "EditorWindow/EditorPopups/SHEditorPopups.h" + //#==============================================================# //|| Library Includes || //#==============================================================# @@ -107,6 +110,9 @@ namespace SHADE SHEditorWindowManager::CreateEditorWindow(); + //Add popup windows + SHEditorWindowManager::CreatePopupWindow(); + io = &ImGui::GetIO(); io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls @@ -163,7 +169,6 @@ namespace SHADE popupWindow->Draw(); } - RenderSceneNamePrompt(); RenderUnsavedChangesPrompt(); //PollPicking(); @@ -182,37 +187,6 @@ namespace SHADE } } - void SHEditor::RenderSceneNamePrompt() noexcept - { - if(isSceneNamePromptOpen) - { - ImGui::OpenPopup(sceneNamePromptName.data()); - } - - if(ImGui::BeginPopupModal(sceneNamePromptName.data(), &isSceneNamePromptOpen)) - { - static std::string newSceneName{}; - ImGui::Text("Enter new scene name"); - ImGui::InputText("##name", &newSceneName); - ImGui::BeginDisabled(newSceneName.empty()); - if(ImGui::Button("Save")) - { - SaveScene(newSceneName); - newSceneName.clear(); - isSceneNamePromptOpen = false; - ImGui::CloseCurrentPopup(); - } - ImGui::EndDisabled(); - ImGui::SameLine(); - if(ImGui::Button("Cancel")) - { - isSceneNamePromptOpen = false; - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - } - void SHEditor::RenderUnsavedChangesPrompt() noexcept { if(isUnsavedChangesPromptOpen) @@ -225,12 +199,12 @@ namespace SHADE ImGui::Text("You have unsaved changes!"); if(ImGui::Button("Save")) { - isSceneNamePromptOpen = true; + SHEditorWindowManager::GetPopupWindow()->isOpen = true; } ImGui::SameLine(); if(ImGui::Button("Cancel")) { - isUnsavedChangesPromptOpen = false; + SHEditorWindowManager::GetPopupWindow()->isOpen = true; ImGui::CloseCurrentPopup(); } } @@ -568,7 +542,7 @@ namespace SHADE if (newSceneName.empty()) { //Prompt for scene name - isSceneNamePromptOpen = true; + SHEditorWindowManager::GetPopupWindow()->isOpen = true; return false; } //Else We have a new name @@ -649,7 +623,7 @@ namespace SHADE editorState = SHEditor::State::STOP; SHCommandManager::SwapStacks(); SHEventManager::BroadcastEvent(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT); - LoadScene(SHSceneManager::GetCurrentSceneAssetID()); + LoadScene(editorConfig->workingSceneID); } void SHEditor::ProcessShortcuts() diff --git a/SHADE_Engine/src/Editor/SHEditor.h b/SHADE_Engine/src/Editor/SHEditor.h index 103f834f..d616c096 100644 --- a/SHADE_Engine/src/Editor/SHEditor.h +++ b/SHADE_Engine/src/Editor/SHEditor.h @@ -37,8 +37,6 @@ namespace SHADE class SHVkCommandBuffer; class SHVkCommandPool; - - /** * @brief SHEditor static class contains editor variables and implementation of editor functions. * @@ -144,8 +142,6 @@ namespace SHADE */ void Render(); - void RenderSceneNamePrompt() noexcept; - void RenderUnsavedChangesPrompt() noexcept; void InitLayout() noexcept; @@ -156,8 +152,6 @@ namespace SHADE SHEventHandle onEditorStateChanged(SHEventPtr eventPtr); - bool isSceneNamePromptOpen = false; - bool isUnsavedChangesPromptOpen = false; static constexpr std::string_view sceneNamePromptName = "Save scene as..."; From a41354f2cedf88697a94b3cb2e4668c693688712 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 14:35:16 +0800 Subject: [PATCH 119/134] Added changing texture of buttons --- Assets/Application.SHConfig | 2 +- Assets/Scenes/UI_Test.shade | 2 +- SHADE_Engine/src/UI/SHButtonComponent.h | 4 +- SHADE_Engine/src/UI/SHToggleButtonComponent.h | 3 + SHADE_Engine/src/UI/SHUISystem.cpp | 120 ++++++++++++------ 5 files changed, 89 insertions(+), 42 deletions(-) diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 5673556d..ee5e42a8 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97158628 +Starting Scene ID: 87244611 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Scenes/UI_Test.shade b/Assets/Scenes/UI_Test.shade index d9ce5026..0026a48b 100644 --- a/Assets/Scenes/UI_Test.shade +++ b/Assets/Scenes/UI_Test.shade @@ -14,7 +14,7 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: -3.5999999, y: 3.0999999, 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 diff --git a/SHADE_Engine/src/UI/SHButtonComponent.h b/SHADE_Engine/src/UI/SHButtonComponent.h index be6ada3e..3aac09e6 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.h +++ b/SHADE_Engine/src/UI/SHButtonComponent.h @@ -32,8 +32,10 @@ namespace SHADE friend class SHUISystem; private: - + //Set to true when mouse is hovering over the button. bool isHovered; + //This is set to true when the mouse clicks down, and set back to false when mouse releases. + //The event for the button click will be broadcasted when mouse release. bool isClicked; AssetID defaultTexture; AssetID hoveredTexture; diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.h b/SHADE_Engine/src/UI/SHToggleButtonComponent.h index 3217c892..2c77f3ba 100644 --- a/SHADE_Engine/src/UI/SHToggleButtonComponent.h +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.h @@ -33,7 +33,10 @@ namespace SHADE friend class SHUISystem; private: + //Set to true when mouse is hovering over the button. bool isHovered; + //This is set to true when the mouse clicks down, and set back to false when mouse releases. + //The event for the button click will be broadcasted when mouse release. bool isClicked; bool value; AssetID defaultTexture; diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index bb98939b..84f6a21c 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -9,6 +9,7 @@ #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/SHEditor.h" #include "Resource/SHResourceManager.h" +#include "Assets/SHAssetManager.h" #include "Input/SHInputManager.h" #include "SHUIComponent.h" #include "SHButtonComponent.h" @@ -168,9 +169,9 @@ namespace SHADE windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; //mousePos.y = windowSize.y - mousePos.y; - SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) mousePos /= windowSize; - SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) @@ -193,31 +194,25 @@ namespace SHADE //SHLOG_INFO("TopExtent: {}, {} Btm Extent: {}, {}", topExtent.x, topExtent.y, btmExtent.x, btmExtent.y) - comp.isClicked = false; + //comp.isClicked = false; if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) { comp.isHovered = true; -#ifdef SHEDITOR - if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) - { - if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + #ifdef SHEDITOR + //if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + } + #else + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; - SHButtonClickEvent clickEvent; - clickEvent.EID = comp.GetEID(); - SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); } - } -#else - if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) - { - comp.isClicked = true; - SHButtonClickEvent clickEvent; - clickEvent.EID = comp.GetEID(); - SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); - } -#endif + #endif //SHLOG_INFO("HOVERED") } @@ -226,15 +221,46 @@ namespace SHADE comp.isHovered = false; //SHLOG_INFO("NOT HOVERED") } - + if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = false; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } if (SHComponentManager::HasComponent(comp.GetEID())) { - /*auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); auto material = renderable->GetModifiableMaterial(); - material->SetProperty("texture", comp.GetDefaultTexture());*/ + if(!comp.isHovered && !comp.isClicked) + if (SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + + if (comp.isHovered) + { + if (SHAssetManager::GetType(comp.GetHoveredTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetHoveredTexture()); + //SHLOG_INFO("SETTING HOVERED TEXTURE") + } + } + else + { + if (SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetClickedTexture()); + SHLOG_INFO("SETTING CLICKED TEXTURE") + } + } + + + } } @@ -262,9 +288,9 @@ namespace SHADE windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; //mousePos.y = windowSize.y - mousePos.y; - SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) mousePos /= windowSize; - SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) @@ -296,25 +322,15 @@ namespace SHADE #ifdef SHEDITOR if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) { - if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; - comp.value = !comp.value; - SHButtonClickEvent clickEvent; - clickEvent.EID = comp.GetEID(); - clickEvent.value = comp.value; - SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); } } #else - if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; - comp.value = !comp.value; - SHButtonClickEvent clickEvent; - clickEvent.EID = comp.GetEID(); - clickEvent.value = comp.value; - SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); } #endif } @@ -324,13 +340,39 @@ namespace SHADE } + if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = false; + comp.value = !comp.value; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + clickEvent.value = comp.value; + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + if (SHComponentManager::HasComponent(comp.GetEID())) { - /*auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); auto material = renderable->GetModifiableMaterial(); - material->SetProperty("texture", comp.GetDefaultTexture());*/ + if (comp.GetValue() == false) + { + if (SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + } + else + { + if (SHAssetManager::GetType(comp.GetToggledTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetToggledTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + } + } } From b60304457977b9e874b3ff44606a25f5f0916966 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Mon, 16 Jan 2023 14:39:35 +0800 Subject: [PATCH 120/134] Fixed validation errors caused by debug draw and fixed SHDebugDraw::WireCapsule not being static --- .../Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp | 9 ++++++++- SHADE_Engine/src/Tools/SHDebugDraw.h | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index ae8c62b2..5a694516 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -104,6 +104,10 @@ namespace SHADE auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { + // Set line width first + cmdBuffer->SetLineWidth(LineWidth); + + // Draw const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); cmdBuffer->BeginLabeledSegment("SHDebugDraw (No Depth Test)"); { @@ -128,6 +132,10 @@ namespace SHADE auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { + // Set line width first + cmdBuffer->SetLineWidth(LineWidth); + + // Draw const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); cmdBuffer->BeginLabeledSegment("SHDebugDraw (Depth Tested)"); { @@ -506,7 +514,6 @@ namespace SHADE if (batch.NumPoints[frameIndex] > 0) { cmdBuffer->BindPipeline(batch.Pipeline); - cmdBuffer->SetLineWidth(LineWidth); cmdBuffer->BindVertexBuffer(0, batch.VertexBuffers[frameIndex], 0); cmdBuffer->DrawArrays(batch.NumPoints[frameIndex], 1, 0, 0); } diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.h b/SHADE_Engine/src/Tools/SHDebugDraw.h index 3d7bee2f..c775a514 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.h +++ b/SHADE_Engine/src/Tools/SHDebugDraw.h @@ -205,7 +205,7 @@ namespace SHADE /// /// Colour to draw with. /// Whether or not drawn object will be occluded. - void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Function Class "Folder" */ @@ -388,7 +388,7 @@ namespace SHADE /// /// Colour to draw with. /// Whether or not drawn object will be occluded. - void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /// /// Clears any persistent drawn debug primitives. /// From 1e351366afccf40c5723f087ad2b4fd4fd7be9ec Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 14:44:20 +0800 Subject: [PATCH 121/134] fix clicked texture to take priority over hovered texture --- SHADE_Engine/src/UI/SHUISystem.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 84f6a21c..11808038 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -232,7 +232,7 @@ namespace SHADE if (SHComponentManager::HasComponent(comp.GetEID())) { auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); - auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); + //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); auto material = renderable->GetModifiableMaterial(); if(!comp.isHovered && !comp.isClicked) @@ -240,9 +240,16 @@ namespace SHADE { material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + else if (comp.isClicked) + { + if (SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetClickedTexture()); + //SHLOG_INFO("SETTING CLICKED TEXTURE") + } } - - if (comp.isHovered) + else { if (SHAssetManager::GetType(comp.GetHoveredTexture()) == AssetType::TEXTURE) { @@ -250,14 +257,6 @@ namespace SHADE //SHLOG_INFO("SETTING HOVERED TEXTURE") } } - else - { - if (SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) - { - material->SetProperty("data.textureIndex", comp.GetClickedTexture()); - SHLOG_INFO("SETTING CLICKED TEXTURE") - } - } @@ -353,7 +352,7 @@ namespace SHADE if (SHComponentManager::HasComponent(comp.GetEID())) { auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); - auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); + //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); auto material = renderable->GetModifiableMaterial(); if (comp.GetValue() == false) From cdb5102630f84e10757bb2b01860cd880b067fd8 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 14:51:06 +0800 Subject: [PATCH 122/134] Added a 0 check for button textures. --- SHADE_Engine/src/UI/SHUISystem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 11808038..c75af66f 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -236,14 +236,14 @@ namespace SHADE auto material = renderable->GetModifiableMaterial(); if(!comp.isHovered && !comp.isClicked) - if (SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + if (comp.GetDefaultTexture() != 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) { material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); //SHLOG_INFO("SETTING DEFAULT TEXTURE") } else if (comp.isClicked) { - if (SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) + if (comp.GetClickedTexture() != 0 && SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) { material->SetProperty("data.textureIndex", comp.GetClickedTexture()); //SHLOG_INFO("SETTING CLICKED TEXTURE") @@ -251,7 +251,7 @@ namespace SHADE } else { - if (SHAssetManager::GetType(comp.GetHoveredTexture()) == AssetType::TEXTURE) + if (comp.GetHoveredTexture() != 0 && SHAssetManager::GetType(comp.GetHoveredTexture()) == AssetType::TEXTURE) { material->SetProperty("data.textureIndex", comp.GetHoveredTexture()); //SHLOG_INFO("SETTING HOVERED TEXTURE") @@ -357,7 +357,7 @@ namespace SHADE auto material = renderable->GetModifiableMaterial(); if (comp.GetValue() == false) { - if (SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + if (comp.GetDefaultTexture()!= 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) { material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); //SHLOG_INFO("SETTING DEFAULT TEXTURE") @@ -365,7 +365,7 @@ namespace SHADE } else { - if (SHAssetManager::GetType(comp.GetToggledTexture()) == AssetType::TEXTURE) + if (comp.GetToggledTexture() != 0 && SHAssetManager::GetType(comp.GetToggledTexture()) == AssetType::TEXTURE) { material->SetProperty("data.textureIndex", comp.GetToggledTexture()); //SHLOG_INFO("SETTING DEFAULT TEXTURE") From c077575a738eeab8b4a5b2e2ab7f845af81e8adf Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 16 Jan 2023 15:01:14 +0800 Subject: [PATCH 123/134] 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; } From 1526176c58c22c24b7deade29420a03b95714d55 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 16 Jan 2023 15:06:46 +0800 Subject: [PATCH 124/134] Shadows WIP --- Assets/Shaders/DeferredComposite_CS.glsl | 2 +- Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 8333 -> 8317 bytes .../src/Graphics/Images/SHVkSampler.cpp | 1 + .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 2 +- .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 2 +- 5 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index b31daf25..d28eaec0 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -60,7 +60,7 @@ float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f) { - return 0.3f; + return 0.0f; } else return 1.0f; diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index 31ea035c0a64e3e947bae4ceb483ce0661300999..ceca4e13568ca092b20096b7eec9b7c432767466 100644 GIT binary patch literal 8317 zcmZ{n33Odm6^3t`yrgt4V+(CbTZRHikVmW-R8jDtxMB}Re^X+D|5%8@1Rf{)w@=2>{`3FYxRj6dxnNKHkxPGDjRFn z!OF(o>Tso}S=~}GZhRrGI@nVi=`9A7h$z-Ck#}cmtSHxd)^9HN*3aBfu8mX{G!9?1 zbW7jjr2~D77ca$M;=ifLMjErGJd|=BX|HG2hikp-hsr&blZMOv>*|fv*OsoQR_)*1 zT(^PQ?a8k2eObinlwK=eO7?{BsSj?c3^yyi>D=~Y0kTmZ7^+ozS5}6an=#WIJ;?rA zeN(x1>gM4}*>L#r=|1+?Hg=`1RfAjVJ>_P#KDcUSK5qayR6VOwTUqVv8)>jp&TC6t zN4d7C(p%5+j~G{PRGoa9>q_G~k}YHTbiLV}Hx+yvs+BV_$z4je75HpVO38M(!TRt( zxt2xR!-b<y{>a{wd%x_OFM~;4{+)?5z zT?t=JV@k<2$n+zusE-Ub8_XJ?a?nYBoa%$+S{h>S?fmB)&-_rmI@ruT!Fx^{L-nAE z?nvW3{pEp8)yn9MtnX{#(>3PxOT>Q)Zh0YgeRFuEr)llXhdXk`a?`$?XJ3uxaAmMR zJ1h1jZ(r5M^89vW>yWpvo{<{Yr+-bkaR&R=k=zVdte@?2Hbnir|9?83|-t36KV2|{* zfuSvH%FW^GS*W8mO6b{niFJ)n?t>fKb8$cPJ9-N%_w3yd$GigTesm-cjmEw#J^j^l z(yN}H*GKeaJ+m#@C-nZ5Sp4WY<`8;Uc7hu!50|~q+7rjvyE&&(uJelF??`6k_6fC- z;o(Z}s)2HUg{fvwI`K8j!~KHqJW6b%K-0DrauLZOqd)=CCnb2X--+bBr4T_Wlc` zYuyUW75B*)hijE&sY_S>n4e=@p$`MJ!Tf^@!lovYuxGm!H3ZC=;oJo(+QXQw>>V;q#*bI>DxZ*=3$ zpv^?%RKu6xqx*K#5UHwig^d4JEG2^naS^@>^Eh^ElK&U$4A^UZ1*wjwdm%x z|88U_&~M!`vK#1ky_=BsFR#BB>6&AG6?EsyFU7CjmvhE%M(+m3`<(}ouFE;aVZAnB zO@3OX!&q}_dk-98`))eSxfS{Ua$3in=OG-`=#Z&AG^P9k$=e`0I0@dCcoOZC~#5^SN8oH(1{sX5Ngv2{`}L zNbAX2PuuraPXFz>ZqBH`1HC2p-lFVedbwVmhP&Ft3neKf{C?nC-sTIZKY zYs%S&wr`By!o|#TOBdK13S+4By?-r zyXR_mY}c4iLCc0QQ-L-1$eqSoL)-V*p;q6U(rV zWQE4tr^9pb1dQvp#wKJB@a$>(4h|G--%S4&D*F99r)Y04*xs*;3by(D+a%)6cX`3~ z++R7yzPn&M|Dl5IyZcDNHlM!*BmZP z`C1_72<{AYIZ`F-h$|y&z*v39v9s=@oOOKTUI&J9+xTH%%qHf0&i#AJ82PoFKF=n9 z=A^tnhxPn^=J&hkkNp0D>3gYd{+69rj^NHkmoqlF zH{_hXtz&mx&l`dBjn}^f*th3LpM7pco)5O=wtc@D6#Kpa+Zg%i`z`45!V!I&-}9(H z^1l_`H$V2}ZRo}PZ^t%9KJvc1H=q9oya!yI+xGun5c&PL;C;XtdH2hE z`hFnquxIaxoVxepvRuC$c}1>!FRlVlasobx^xi5TqmQeR9|jKnA3^F@+GjWNqre=V zb9?w$&Ml{>>(Orj*8=~2aE>uI0{NSXS%mxqaGv~A#AtsATn((J9&XV9&` zobzG5&w^WkYtmP&`#Eg=cjf!_d35v1-$S_FvJrgG>14?a03YW8^1skLCUj%)0;_42&`N zBS?MG`#;d5_uJ9`38Hs>*8yWEApZsQ$36RZ&dEEhHx3wY5B~wyi+l2D&dH0oCy$|< zOMk5Kar6NYF;AcyCm%6SqF)N)E(QS9u~vOg17l|+p9T8k zygZk4%aAv)?~9NwSbiDstsCbCFg!2%T7aDAMLqgxN6-2w@hgKPC4&&)-XD*DcOJ#*@hZ!-;Df53d6*XeNX zaeRlJvE_`9J(ly0h_x!Ul`W@DFujOLx zhof8PP!MZ>5xV@XtkE}aF_1Iwb@V591d#X5I|}LW&67V8$axObqt?;rV{07)Cx2UB zYbm{sMbMqe*Qx3;|+Zw>ocgLK%3F{^=`eW*W+G_SUN^tBG%`?40qew~6YANI@9J!{eD zdURvtt^Eq5!`k{z1#;F>k6IhhtyR36r(w%S?$gob;@d0&pH2d-gC}-?s?z&=)9~m z$yUqQIqgX@CK;bhN*0XCv1!RzkR*{WgilD?GQE4%x>XB?n!O7a9ecE%lam%%W}AXf zEAlv~Kdlak_d!#^#inJldhXxC-m%Dcl4u;+yH{=KUbCiq)oB}g1_w6`H7}}FHq@#E zl?}bsMy01&-BQu7qvTf|=&23&mK|F0DCch_?w;gWp4NKSZBBdZ7pzZf!8KCq?IXjXc&y=}={_)ywESgZ7|s0=nYqh>L*_tokf z)7n{^8N_}*ig3bO7yI6tI~@qjXcL&pM|YRn`xe72e>_5Ua!@0Wq(_;3qJCl3PUTibS-!_ z^Jz`4hi4yQd3|`GImE7x3;G|ipcFh{I7ZdRB3tZS&*s0{SwvtnK1 z)>R!^R@{#K9OBm1GhE~P^sP>Z&ZBSb$;ZLU`SUL4d$hUI?A+1+w&WHt_LNZ1*OJ@| zp7**V`6=>>{ECkB^qI4@Wp-Si={vIZyU%ltu3y}9mFu@h;-0HFAMt1PNZUAQaLekn z*{EKKIFiFRDW8`(S4Z-5u+cS_`=Q;{TROS3cOMx0N~ry4PaYiceL*(;)r+&Mp3UpS z+VYxdOa2MHKW!X-WR4j^@5*?v!L*U~vqyd6D1Be|45f8mG3@Qhj6y%PHr!}bdRO+R zeZ}2xO}el((?(yVnZw=0^F5vb&4ko_9}a@-Yv^6b_Fvu0Ubd@ix2M{-jk2q2cWL+T zm-nk{A5+-9_hq}fcI!EVEZ#}ioScnd?icf$ho3czb(ApUh)smLiE2Fktj#-W?x;oG z+%98!k6i9|1s1veI~G{v_HRI7k$XCr`EG`{L7k93apxkw^@+JpfA3zoK6UGhGduIH z*l$d+sLwM87WGBVahKfNnfZ;&_8Qx78~fDtIeHYv4~Fb-WB9p8zd^{_e+KugTOobo zK1HpbRjdWl-+NU)tGZ|PEZV&*+N~#a?Jjlif%b@}u08y_M%mT1Tci8uqkAuAKzlJE z_N$9%##7!GDZbr|WDjm$zL#y!TA?3+zjLTxC-L_vyu|iH9}hR4^=UV^zT(r-{dUS> zpM&QZ%jU4_5BI|Dq?ec>m)+zJQ zjB^Mi7G&Nd(Dk)fv2Q-IEAkwbtNc#Ne^Z9v;tbzuDt@c2XWp_$nF(if?d6@!1S*o8&7|~dmZjM-BVuXi*Mx} zaOrDIb>CT6=-H1bbYor$|9>&f<2hafcj;>k^=$&I(0yB7`dCx`y?8s^c%Cz6VJEWRIcOePo!e_5ziXMy@h&jyN+G|m{N0diHeI+L zZjLg!??YhLs@>YueXqqL&WDlXyY4P*#xd?qaO<+q&%|!Y-ehgF+3DMRGi1I`z>O_t zK6T$;G3~b(vN0q7UC3h!``v}ze6x88d~dxwk=uRV#c-b;O~!*|j5(>%X`n^Vj> z)bA^>$a{aG>;F(8n=9;3A^Seh#6FG!eS?-l`nOszOWgSCzO}B{-+>;pJqg)*tlhcV zPk-cM3sS!HnF5((dSTSp9O}N$E_LrmSNNdMLAEc(um(JN$4-H=e%@qrOS#{x%F(PpR*x&+;K?BxY^CS6I9&nqxk z5?HOk2$ihGZzH@P(pTHbbk;tKnWqkKK<5{_{`{29d^WP*Ip?1^nUDAyrq9_NE^uuw z^ZEUZ?|0E2@h?R7y;L{;MUXW_{ELzG5s&zh zZ7tpPJgo}?Mb}3>>V6%vxa5kujlUILd&GYO zvTuI$<&DVY_-{hjM?B)c8ChI%mE$|#+KuPmfVV-u{}KOcO z3v3xR?MA*4x&iXvrTXKv9=A>(h5U{ELwGn3FpSOxzW7ayd1c>r0UN?tmiSoyd{zZsadRkx$!Q zkiKp3uRz+@q8aa=0uz@a&sUMnrQN;yehu0IU0T%g^#ap3=1k0ai9X5IohADwkGj8s zY~5Rlm%_gZiCM4lw277H^SZ)zFWf$A`xe~Ta%cBD@b5w{?calImq+gJBO4=T_Xo&g zF}puRc6Q@i%|iYWBp$Q-V`TSnv9M1p zX6H}nW1!Oto8Rm~WO3uW=g*K>=zl@p4qeSRZ-f68(nowE_gL(2ka6ci^C5kV{V-fx z)c$wmsQq^2e?U>Ywz&V^vws%$xM%+=Fmadp#zMxnhDRXt#XWhnz{I7vCyyZ;OM9I0 zapVCge4aqoPdt2{MBV|#UHUh&n7(nB#Nw>~L5{QTMt&NKvub+^(svg8zmWEr7Y`@4 z6xvPSeRs!rU`Wiju0@^Yyl5K>i8(LIQAay+UPmjxLiu+vy1!dvPVDsr^eu4D;cq8( z=iJ}0lcA{FSpLQ}_C)-r6n6Ld8%zDfVkV{{?^)zCruO(Y(~z|X8PD0<6U-jRci0PE zO#kSym~TX!RjwX)MXv69VlU*;i@ou+7x8}WgDw{Dmo_o?`!>1Xx554XCf^_O_qh5- z@B@&0;qm)wX5k|qzl&xei@Q97zdgl_;oQzf7E`we2O`^pD~dO}6J1Qd=z*C2b^H!O z_TL2R74(CV``~N%4s(zXfy5-2%s15f4@J=)xer4&cho)?UCb5O;RPlf*bxOb7A$`I z9SP=s{k1Q~)ek>)KLlzgaW_uuJ zz7F`|kUdp*-j0OyabAvq&nqx-*BIy=Z1!UT*|KPtV{fKNX)vFqpmZMN7uCyOg#GaJY=!xSHzJ= zUC&20x3%hT4(nJAcUgx%s~|D!P<|S2Ty^oNYb~<(WepVlIultu^cNyKYf~+ X46+VodvI={i(); lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams { - // nothing for now + .addressMode = vk::SamplerAddressMode::eClampToBorder, }) ); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index 2e3b21d9..9acdfed0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -518,7 +518,7 @@ namespace SHADE if (auto renderer = light.GetRenderer()) { //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() - renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(30.0f, 30.0f, 1.0f, 50.0f)); + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(10.0f, 10.0f, 1.0f, 50.0f)); } auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); From fe39be0d61acbbe80d9426ff728a67e9e9d2e1aa Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Mon, 16 Jan 2023 15:17:06 +0800 Subject: [PATCH 125/134] Added asset browser tool tip that shows asset id --- .../Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp index bd39b38e..a1bb29ca 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp @@ -262,6 +262,13 @@ namespace SHADE } } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("AssetID: %zu | Path: %s", asset->id, asset->path.c_str()); + ImGui::EndTooltip(); + } + //TODO: Combine Draw asset and Draw Folder recursive drawing const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark); const float horizontalOffset = 0.0f; From e115d4b96588a8af86021d2bb0dcd0553488c2e5 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 16 Jan 2023 15:33:20 +0800 Subject: [PATCH 126/134] Reverted light properties back to main --- Assets/Scenes/MainGame.shade | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Assets/Scenes/MainGame.shade b/Assets/Scenes/MainGame.shade index 69bb9e7d..49602e78 100644 --- a/Assets/Scenes/MainGame.shade +++ b/Assets/Scenes/MainGame.shade @@ -8440,15 +8440,10 @@ IsActive: true NumberOfChildren: 0 Components: - Transform Component: - Translate: {x: 2.05652523, y: 1.65113854, z: -6.62914371} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 1, y: 1, z: 1} - IsActive: true Light Component: - Position: {x: 0, y: 1.5, z: -6.71799994} + Position: {x: 0, y: 0, z: 0} Type: Directional - Direction: {x: 0, y: 0, z: -1.11899996} + Direction: {x: 15, y: 90, z: 15} Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 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 127/134] 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: From 6b19a635e32aba915d111e32481fc863d0e4b27d Mon Sep 17 00:00:00 2001 From: SHAM-DP Date: Tue, 17 Jan 2023 20:52:22 +0800 Subject: [PATCH 128/134] All component view toggle headers open by default uint32_t fields now accept EID & Resource drag/drop --- .../Inspector/SHEditorComponentView.hpp | 12 ++++---- SHADE_Engine/src/Editor/SHEditorWidgets.hpp | 30 ++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 45964930..3e1fdc44 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -77,7 +77,7 @@ namespace SHADE ImGui::PushID(SHFamilyID::GetID()); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); ImGui::SameLine(); - if (ImGui::CollapsingHeader(componentType.get_name().data())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); auto const& properties = componentType.get_properties(); @@ -234,7 +234,7 @@ namespace SHADE const auto componentType = rttr::type::get(); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); ImGui::SameLine(); - if (ImGui::CollapsingHeader(componentType.get_name().data())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); @@ -328,7 +328,7 @@ namespace SHADE const auto componentType = rttr::type::get(*component); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); ImGui::SameLine(); - if (ImGui::CollapsingHeader(componentType.get_name().data())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); @@ -446,7 +446,7 @@ namespace SHADE const auto componentType = rttr::type::get(*component); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); ImGui::SameLine(); - if (ImGui::CollapsingHeader(componentType.get_name().data())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); @@ -478,7 +478,7 @@ namespace SHADE const auto componentType = rttr::type::get(*component); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); ImGui::SameLine(); - if (ImGui::CollapsingHeader(componentType.get_name().data())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); Handle const& mesh = component->GetMesh(); @@ -536,7 +536,7 @@ namespace SHADE const auto componentType = rttr::type::get(*component); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active"); ImGui::SameLine(); - if (ImGui::CollapsingHeader(componentType.get_name().data())) + if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen)) { DrawContextMenu(component); Handle const& font = component->GetFont(); diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index 441f95aa..f3dfe194 100644 --- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp +++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp @@ -13,6 +13,8 @@ #include "Command/SHCommandManager.h" #include "SHImGuiHelpers.hpp" #include "SH_API.h" +#include "Assets/SHAssetMacros.h" +#include "ECS_Base/SHECSMacros.h" //#==============================================================# //|| Library Includes || @@ -454,7 +456,33 @@ namespace SHADE ImGui::BeginGroup(); ImGui::PushID(label.data()); TextLabel(label); - const bool hasChange = ImGui::InputScalar("##dragScalar", data_type, &value); + bool hasChange = ImGui::DragScalar("##dragScalar", data_type, &value); + if constexpr(std::is_same_v) //EID or Resource + { + if (SHDragDrop::BeginTarget()) + { + if(AssetID * payload = SHDragDrop::AcceptPayload(SHDragDrop::DRAG_RESOURCE)) + { + value = *payload; + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + hasChange = true; + SHDragDrop::EndTarget(); + } + else if (std::vector* payload = SHDragDrop::AcceptPayload>(SHDragDrop::DRAG_EID)) + { + value = payload->back(); + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + hasChange = true; + SHDragDrop::EndTarget(); + } + if(hasChange) + { + ImGui::PopID(); + ImGui::EndGroup(); + return true; + } + } + } static bool startRecording = false; if (hasChange) { From 3cb1e5c7fc64641fe754234c0383f4dd9d591b8c Mon Sep 17 00:00:00 2001 From: SHAM-DP Date: Tue, 17 Jan 2023 21:02:01 +0800 Subject: [PATCH 129/134] Merge branch 'main' into SP3-4-Editor --- Assets/Application.SHConfig | 2 +- Assets/Bindings.SHConfig | 1 + Assets/Editor/Editor.SHConfig | 4 + Assets/Scenes/Scene2.shade | 31 +- Assets/Scenes/UI_Test.shade | 22 +- Assets/Scenes/UI_Test.shade.shmeta | 2 +- Assets/Shaders/DeferredComposite_CS.glsl | 64 ++- Assets/Shaders/DeferredComposite_CS.shshaderb | Bin 5501 -> 8317 bytes Assets/Shaders/ShadowMap_VS.glsl | 22 ++ Assets/Shaders/ShadowMap_VS.shshaderb | Bin 0 -> 1537 bytes Assets/Shaders/ShadowMap_VS.shshaderb.shmeta | 3 + Assets/Shaders/TestCube_FS.glsl | 5 +- Assets/Shaders/TestCube_FS.shshaderb | Bin 2401 -> 2557 bytes Assets/Shaders/TestCube_VS.glsl | 5 +- Assets/Shaders/TestCube_VS.shshaderb | Bin 3689 -> 3905 bytes SHADE_Engine/src/Camera/SHCameraSystem.cpp | 12 +- SHADE_Engine/src/Common/SHAllComponents.h | 2 + .../ECS_Base/Managers/SHComponentManager.h | 28 +- .../AssetBrowser/SHAssetBrowser.cpp | 7 + .../Inspector/SHEditorInspector.cpp | 6 + SHADE_Engine/src/Editor/SHEditor.cpp | 4 +- SHADE_Engine/src/Events/SHEventDefines.h | 1 + .../Descriptors/SHVkDescriptorSetGroup.cpp | 43 ++ .../Descriptors/SHVkDescriptorSetGroup.h | 2 + .../Graphics/Devices/SHVkLogicalDevice.cpp | 38 +- .../src/Graphics/Events/SHGraphicsEvents.h | 3 + .../src/Graphics/Images/SHVkSampler.cpp | 1 + .../Graphics/MiddleEnd/Batching/SHBatch.cpp | 7 +- .../src/Graphics/MiddleEnd/Batching/SHBatch.h | 2 +- .../MiddleEnd/Batching/SHSuperBatch.cpp | 4 +- .../MiddleEnd/Batching/SHSuperBatch.h | 2 +- .../GlobalData/SHGraphicsPredefinedData.cpp | 28 +- .../GlobalData/SHGraphicsPredefinedData.h | 7 +- .../GlobalData/SHPredefinedDescriptorTypes.h | 2 +- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 71 +++- .../MiddleEnd/Interface/SHDebugDrawSystem.h | 23 ++ .../MiddleEnd/Interface/SHGraphicsConstants.h | 155 +++++--- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 153 ++++++-- .../MiddleEnd/Interface/SHGraphicsSystem.h | 14 +- .../MiddleEnd/Interface/SHRenderer.cpp | 5 + .../Graphics/MiddleEnd/Interface/SHRenderer.h | 3 +- .../MiddleEnd/Lights/SHLightComponent.cpp | 18 + .../MiddleEnd/Lights/SHLightComponent.h | 8 + .../MiddleEnd/Lights/SHLightingSubSystem.cpp | 164 +++++++- .../MiddleEnd/Lights/SHLightingSubSystem.h | 106 +++-- .../MiddleEnd/Meshes/SHPrimitiveGenerator.cpp | 59 +++ .../MiddleEnd/Meshes/SHPrimitiveGenerator.h | 41 ++ .../MiddleEnd/Pipeline/SHPipelineLibrary.cpp | 16 +- .../MiddleEnd/Pipeline/SHPipelineLibrary.h | 5 +- .../src/Graphics/Pipeline/SHPipelineState.cpp | 11 +- .../src/Graphics/Pipeline/SHPipelineState.h | 2 +- .../Graphics/Pipeline/SHVkPipelineLayout.cpp | 116 +++--- .../Graphics/RenderGraph/SHRenderGraph.cpp | 160 ++++---- .../src/Graphics/RenderGraph/SHRenderGraph.h | 18 +- .../RenderGraph/SHRenderGraphNode.cpp | 370 +++++++++++++----- .../Graphics/RenderGraph/SHRenderGraphNode.h | 22 +- .../RenderGraph/SHRenderGraphNodeCompute.cpp | 105 +++-- .../RenderGraph/SHRenderGraphNodeCompute.h | 23 +- .../RenderGraph/SHRenderGraphResource.cpp | 7 +- .../RenderGraph/SHRenderGraphResource.h | 5 +- .../src/Graphics/RenderGraph/SHSubpass.cpp | 81 ++-- .../src/Graphics/RenderGraph/SHSubpass.h | 42 +- SHADE_Engine/src/Input/SHInputManager.cpp | 156 ++++++++ SHADE_Engine/src/Input/SHInputManager.h | 12 + .../src/Math/Transform/SHTransform.cpp | 12 +- .../src/Serialization/SHSerialization.cpp | 3 + SHADE_Engine/src/Tools/SHDebugDraw.cpp | 8 + SHADE_Engine/src/Tools/SHDebugDraw.h | 24 ++ .../src/UI/Events/SHButtonClickEvent.h | 16 + SHADE_Engine/src/UI/SHButtonComponent.cpp | 2 +- SHADE_Engine/src/UI/SHButtonComponent.h | 5 +- SHADE_Engine/src/UI/SHSliderComponent.cpp | 39 ++ SHADE_Engine/src/UI/SHSliderComponent.h | 41 ++ .../src/UI/SHToggleButtonComponent.cpp | 59 +++ SHADE_Engine/src/UI/SHToggleButtonComponent.h | 51 +++ SHADE_Engine/src/UI/SHUISystem.cpp | 262 +++++++++++-- SHADE_Engine/src/UI/SHUISystem.h | 16 +- SHADE_Managed/src/Components/Transform.cxx | 3 +- SHADE_Managed/src/Math/Vector3.cxx | 4 + SHADE_Managed/src/Math/Vector3.hxx | 17 +- 80 files changed, 2339 insertions(+), 554 deletions(-) create mode 100644 Assets/Bindings.SHConfig create mode 100644 Assets/Editor/Editor.SHConfig create mode 100644 Assets/Shaders/ShadowMap_VS.glsl create mode 100644 Assets/Shaders/ShadowMap_VS.shshaderb create mode 100644 Assets/Shaders/ShadowMap_VS.shshaderb.shmeta create mode 100644 SHADE_Engine/src/UI/Events/SHButtonClickEvent.h create mode 100644 SHADE_Engine/src/UI/SHSliderComponent.cpp create mode 100644 SHADE_Engine/src/UI/SHSliderComponent.h create mode 100644 SHADE_Engine/src/UI/SHToggleButtonComponent.cpp create mode 100644 SHADE_Engine/src/UI/SHToggleButtonComponent.h diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index 5673556d..ee5e42a8 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97158628 +Starting Scene ID: 87244611 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Bindings.SHConfig b/Assets/Bindings.SHConfig new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/Assets/Bindings.SHConfig @@ -0,0 +1 @@ +0 diff --git a/Assets/Editor/Editor.SHConfig b/Assets/Editor/Editor.SHConfig new file mode 100644 index 00000000..51425027 --- /dev/null +++ b/Assets/Editor/Editor.SHConfig @@ -0,0 +1,4 @@ +Start Maximized: true +Working Scene ID: 97161771 +Window Size: {x: 1920, y: 1080} +Style: 0 \ No newline at end of file diff --git a/Assets/Scenes/Scene2.shade b/Assets/Scenes/Scene2.shade index 2f38a933..de902c55 100644 --- a/Assets/Scenes/Scene2.shade +++ b/Assets/Scenes/Scene2.shade @@ -7,6 +7,7 @@ Translate: {x: 0, y: 0.304069757, z: 1.73034382} Rotate: {x: 0, y: 0, z: 0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Camera Component: Position: {x: 0, y: 0.304069757, z: 1.73034382} Pitch: 0 @@ -17,6 +18,7 @@ Near: 0.00999999978 Far: 10000 Perspective: true + IsActive: true Scripts: ~ - EID: 1 Name: Raccoon @@ -24,12 +26,14 @@ NumberOfChildren: 1 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: -1.86388135, y: 0.0544953719, z: 0} + Rotate: {x: -0, y: 0, z: -0} Scale: {x: 1, y: 1, z: 1} + IsActive: true Renderable Component: Mesh: 149697411 Material: 126974645 + IsActive: true Scripts: ~ - EID: 3 Name: Bag @@ -40,9 +44,11 @@ Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Rotate: {x: -0, y: 2.79945588, z: 0} Scale: {x: 1.0000881, y: 1, z: 1.0000881} + IsActive: true Renderable Component: Mesh: 144838771 Material: 123745521 + IsActive: true Scripts: ~ - EID: 2 Name: DirectionalLight @@ -50,12 +56,13 @@ NumberOfChildren: 0 Components: Light Component: - Position: {x: 0, y: 0, z: 0} + Position: {x: 3, y: 4.5, z: 7} Type: Directional - Direction: {x: 0, y: 0, z: 1} + Direction: {x: -0.298000008, y: 0.522498012, z: 0.798600018} Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0 + IsActive: true Scripts: ~ - EID: 4 Name: AmbientLight @@ -69,4 +76,20 @@ Color: {x: 1, y: 1, z: 1, w: 1} Layer: 4294967295 Strength: 0.600000024 + IsActive: true + Scripts: ~ +- EID: 5 + Name: Floor + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0.0810000002, z: 0} + Rotate: {x: -1.57079637, y: 0, z: 0} + Scale: {x: 50, y: 50, z: 50} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 124370424 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Scenes/UI_Test.shade b/Assets/Scenes/UI_Test.shade index e8ee4df2..0026a48b 100644 --- a/Assets/Scenes/UI_Test.shade +++ b/Assets/Scenes/UI_Test.shade @@ -1,7 +1,7 @@ - EID: 0 Name: Canvas IsActive: true - NumberOfChildren: 1 + NumberOfChildren: 2 Components: Canvas Component: Canvas Width: 10 @@ -28,6 +28,26 @@ Clicked Texture: 0 IsActive: true Scripts: ~ +- EID: 5 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: -3.9000001, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + Renderable Component: + Mesh: 141771688 + Material: 129340704 + IsActive: true + Toggle Button Component: + Non Toggled Texture: 0 + Toggled Texture: 0 + Value: true + IsActive: true + Scripts: ~ - EID: 1 Name: Camera IsActive: true diff --git a/Assets/Scenes/UI_Test.shade.shmeta b/Assets/Scenes/UI_Test.shade.shmeta index 8b8d6f22..77355480 100644 --- a/Assets/Scenes/UI_Test.shade.shmeta +++ b/Assets/Scenes/UI_Test.shade.shmeta @@ -1,3 +1,3 @@ Name: UI_Test -ID: 87707373 +ID: 87244611 Type: 5 diff --git a/Assets/Shaders/DeferredComposite_CS.glsl b/Assets/Shaders/DeferredComposite_CS.glsl index 0a8085b1..d28eaec0 100644 --- a/Assets/Shaders/DeferredComposite_CS.glsl +++ b/Assets/Shaders/DeferredComposite_CS.glsl @@ -6,6 +6,8 @@ struct DirectionalLightStruct uint isActive; uint cullingMask; vec4 diffuseColor; + mat4 pvMatrix; + uint shadowData; }; struct AmbientLightStruct @@ -22,7 +24,10 @@ layout(set = 3, binding = 1, rgba32f) uniform image2D normals; layout(set = 3, binding = 2, rgba8) uniform image2D albedo; layout(set = 3, binding = 3, r32ui) uniform uimage2D lightLayerData; layout(set = 3, binding = 4, r8) uniform image2D ssaoBlurredImage; -layout(set = 3, binding = 5, rgba8) uniform image2D targetImage; +layout(set = 3, binding = 5, rgba8) uniform image2D positionWorldSpace; +layout(set = 3, binding = 6, rgba8) uniform image2D targetImage; + +layout (set = 4, binding = 0) uniform sampler2D shadowMaps[]; // for textures (global) layout(set = 1, binding = 0) uniform LightCounts { @@ -43,6 +48,25 @@ layout(std430, set = 1, binding = 4) buffer AmbientLightData AmbientLightStruct aLightData[]; } AmbLightData; +float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV) +{ + vec4 fragPosLightPOV = lightPV * worldSpaceFragPos; + vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f); + + float sampledDepth = texture(shadowMap, converted.xy).r; + + if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f) + return 1.0f; + + if (fragPosLightPOV.z > sampledDepth && fragPosLightPOV.w > 0.0f) + { + return 0.0f; + } + else + return 1.0f; + // return step (fragPosLightPOV.z, ); +} + void main() { // convenient variables @@ -52,6 +76,9 @@ void main() vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb; // Get position of fragment in world space + vec4 positionWorld = vec4 (imageLoad (positionWorldSpace, globalThread).rgb, 1.0f); + + // Get position of fragment in view spacee vec3 positionView = imageLoad (positions, globalThread).rgb; // normal of fragment @@ -62,6 +89,18 @@ void main() vec3 fragColor = vec3 (0.0f); + vec4 shadowMapColor = vec4 (1.0f); + + for (int i = 0; i < lightCounts.ambientLights; ++i) + { + if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) + { + // Just do some add + //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); + fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + } + } + for (int i = 0; i < lightCounts.directionalLights; ++i) { if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0) @@ -74,16 +113,13 @@ void main() // Calculate the fragment color fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse; - } - } - for (int i = 0; i < lightCounts.ambientLights; ++i) - { - if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) - { - // Just do some add - //fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f); - fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); + // If the shadow map is enabled (test the bit) + if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) + { + // calculate shadow map here + fragColor *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix).xxx; + } } } @@ -92,6 +128,12 @@ void main() // store result into result image imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); - //imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f)); + + // vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f); + // vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords); + // if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f) + // shadowMapVal = vec4(0.0f); + + // imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx); } \ No newline at end of file diff --git a/Assets/Shaders/DeferredComposite_CS.shshaderb b/Assets/Shaders/DeferredComposite_CS.shshaderb index cabce080c7257a3946de1cbe9f94d151884ade21..ceca4e13568ca092b20096b7eec9b7c432767466 100644 GIT binary patch literal 8317 zcmZ{n33Odm6^3t`yrgt4V+(CbTZRHikVmW-R8jDtxMB}Re^X+D|5%8@1Rf{)w@=2>{`3FYxRj6dxnNKHkxPGDjRFn z!OF(o>Tso}S=~}GZhRrGI@nVi=`9A7h$z-Ck#}cmtSHxd)^9HN*3aBfu8mX{G!9?1 zbW7jjr2~D77ca$M;=ifLMjErGJd|=BX|HG2hikp-hsr&blZMOv>*|fv*OsoQR_)*1 zT(^PQ?a8k2eObinlwK=eO7?{BsSj?c3^yyi>D=~Y0kTmZ7^+ozS5}6an=#WIJ;?rA zeN(x1>gM4}*>L#r=|1+?Hg=`1RfAjVJ>_P#KDcUSK5qayR6VOwTUqVv8)>jp&TC6t zN4d7C(p%5+j~G{PRGoa9>q_G~k}YHTbiLV}Hx+yvs+BV_$z4je75HpVO38M(!TRt( zxt2xR!-b<y{>a{wd%x_OFM~;4{+)?5z zT?t=JV@k<2$n+zusE-Ub8_XJ?a?nYBoa%$+S{h>S?fmB)&-_rmI@ruT!Fx^{L-nAE z?nvW3{pEp8)yn9MtnX{#(>3PxOT>Q)Zh0YgeRFuEr)llXhdXk`a?`$?XJ3uxaAmMR zJ1h1jZ(r5M^89vW>yWpvo{<{Yr+-bkaR&R=k=zVdte@?2Hbnir|9?83|-t36KV2|{* zfuSvH%FW^GS*W8mO6b{niFJ)n?t>fKb8$cPJ9-N%_w3yd$GigTesm-cjmEw#J^j^l z(yN}H*GKeaJ+m#@C-nZ5Sp4WY<`8;Uc7hu!50|~q+7rjvyE&&(uJelF??`6k_6fC- z;o(Z}s)2HUg{fvwI`K8j!~KHqJW6b%K-0DrauLZOqd)=CCnb2X--+bBr4T_Wlc` zYuyUW75B*)hijE&sY_S>n4e=@p$`MJ!Tf^@!lovYuxGm!H3ZC=;oJo(+QXQw>>V;q#*bI>DxZ*=3$ zpv^?%RKu6xqx*K#5UHwig^d4JEG2^naS^@>^Eh^ElK&U$4A^UZ1*wjwdm%x z|88U_&~M!`vK#1ky_=BsFR#BB>6&AG6?EsyFU7CjmvhE%M(+m3`<(}ouFE;aVZAnB zO@3OX!&q}_dk-98`))eSxfS{Ua$3in=OG-`=#Z&AG^P9k$=e`0I0@dCcoOZC~#5^SN8oH(1{sX5Ngv2{`}L zNbAX2PuuraPXFz>ZqBH`1HC2p-lFVedbwVmhP&Ft3neKf{C?nC-sTIZKY zYs%S&wr`By!o|#TOBdK13S+4By?-r zyXR_mY}c4iLCc0QQ-L-1$eqSoL)-V*p;q6U(rV zWQE4tr^9pb1dQvp#wKJB@a$>(4h|G--%S4&D*F99r)Y04*xs*;3by(D+a%)6cX`3~ z++R7yzPn&M|Dl5IyZcDNHlM!*BmZP z`C1_72<{AYIZ`F-h$|y&z*v39v9s=@oOOKTUI&J9+xTH%%qHf0&i#AJ82PoFKF=n9 z=A^tnhxPn^=J&hkkNp0D>3gYd{+69rj^NHkmoqlF zH{_hXtz&mx&l`dBjn}^f*th3LpM7pco)5O=wtc@D6#Kpa+Zg%i`z`45!V!I&-}9(H z^1l_`H$V2}ZRo}PZ^t%9KJvc1H=q9oya!yI+xGun5c&PL;C;XtdH2hE z`hFnquxIaxoVxepvRuC$c}1>!FRlVlasobx^xi5TqmQeR9|jKnA3^F@+GjWNqre=V zb9?w$&Ml{>>(Orj*8=~2aE>uI0{NSXS%mxqaGv~A#AtsATn((J9&XV9&` zobzG5&w^WkYtmP&`#Eg=cjf!_d35v1-$S_FvJrgG>14?a03YW8^1skLCUj%)0;_42&`N zBS?MG`#;d5_uJ9`38Hs>*8yWEApZsQ$36RZ&dEEhHx3wY5B~wyi+l2D&dH0oCy$|< zOMk5Kar6NYF;AcyCm%6SqF)N)E(QS9u~vOg17l|+p9T8k zygZk4%aAv)?~9NwSbiDstsCbCFg!2%T7aDAMLqgxN6-2w@hgKPC4&&)-XD*DcOJ#*@hZ!-;Df53d6*XeNX zaeRlJvE_`9J(ly0h_x!Ul`W@DFujOLx zhof8PP!MZ>5xV@XtkE}aF_1Iwb@V591d#X5I|}LW&67V8$axObqt?;rV{07)Cx2UB zYbm{sMbMqe*Qx3;|+Zw>ocgLK%3F{^=`eW*W+G_SUN^tBG%`?40qew~6YANI@9J!{eD zdURvtt^Eq5!`k{z1#;F>k6IhhtyR36r(w%S?$gob;@dV0q82dvDV9;%rD(+AhIo1bG-*$%~Ho zR_Ic2v2CTSUilBPcO&v&Ni>^7g|=d(C_ql{&}E+FI?!nbI`dIo@sLgQDA+ zoi6R8*$((>aiZCtE{+^o>yzDm!`YkQd3&k3+*KdVCeT;A{ld+Mi{|5~;3L^&4euxH zT6m}1Tgls%r}3^^$NJ^I8`0ZE>*!!EKiTY6Id1tMY&sw0RgQh&M|yedK)2n+mHk86 zUGSomN3#3ibH+N*UF!_`R6AZ`z*%Z*x0AO^7i%2lpL@Lf)o#%lBun7lSAVq|Fy3RO zzf+K}EEUc59aVh?!OOFx{PukwY`VJA_1uRBy|u=m%CFtEULUgg#jUI8Po-%%k6Tw` zt zS74Fbn1MxZzpsHs?g=pSEx<=1Ki>MpoJV}?6LX*b&U?K+b?Y;~`<*9O><=vJi(2%H z`nDs7U(|OcnE9T8Ti*nv&uO?T;#;3s)aMM=>r=Nr@5Fd#lRf;^>vreQ{b5(vJ_5P_ zb-1(mM(8q5;2Cz~t-tc+_(Z)M(08EoV_IU`C(y^?Vv_zBl{kM``Ws)&nEHFC#uC3X z>As1Ge+jZV^}m9@_HzOnF10MXfezctI};`@ndd!lYx54=C*KdbcA?z|H+G%eHv?w9 z+O1FB_b#S=Hp%YW4mt-np5Fj#iFo#ZCpWwR*R~7UH>+-(_rr}TW*&9ltyt9ifu!sI zNRrK=z6AGt_9OfY09o(T$>#p^H4l|mn##BF>Fm-3zx9)N_UV&SyF+7v;UxTvj)ZOaZ z{sdhLh5lz`Yj9S4tFJ@)NZM}WD`Gt7&1L`o3F5cK8vHJ7g6y@rZ*|87`osnLwKd&0 za$`+*|Gt{;oce#kdVK$%68aKyqo(VBqNZyO`7L@9-Co-dv4=R-D12MO zVC&c$5@xR!@H78qkiOdX(;539W*)ygZ-)HlsOx_fq|Xxjox5F-KH~Fq(%F3rBrdtk zXa9|FU$q-=H~boCGU>*DD^!pFHgtW&BmUcw#U)og{sg-Ai2n}c>ymE#>!Eu58_@L; zkNEFI7MEQ0_};sAFAhPzqr5=3<*?8jT zQY{}w7QY?(2mSdd++|(bJ_3nZmvYqc@lvkpcm#P7iaNB#`JLTIA?;h}pn48@|MuWf z$b0eaiW^^_Wk@XaCbDz#Jaun}AA$4{-$F0MT99$|^Y=_2V>jU1qV}VuT-AOI`7tPJ z*H)DF>i+`mWRE#sK^K!;=JOpI+ZsBM`4-Yyy9pDQo}qrvw+b0cdz|qT$iC(9=^^VU z9zK0!=lQ7=XMilGZ_K)w^BeajS9i9(M|t#Ot(3Fu6!Dzz$04!fP`nqh`g@s5wi6|< zY$uV8E%z;b68_v z()JuAW?jm0r(Z+%-lH#HM~=FVA%6pky0pdH+KK$lWRLlLK4Idnn9rE07r@M?U*vlc zIr6=P{4FT*X>%6z-46dYq&?>QI|&n)BF}e`&80og`90))P|WW4k;U|l*%fnMqEB*l zXUV?FqwXIdTX)Rv50S-UcD0GQ|0LY~&V~D5hW{8kn{An6ESxmn;vzY!@!hZ#wOZsN`uc58bJm0ui;J-a JAEMj={TD+43N`=$ diff --git a/Assets/Shaders/ShadowMap_VS.glsl b/Assets/Shaders/ShadowMap_VS.glsl new file mode 100644 index 00000000..e078679e --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.glsl @@ -0,0 +1,22 @@ +#version 450 +#extension GL_KHR_vulkan_glsl : enable + +//#include "ShaderDescriptorDefinitions.glsl" + + +layout(location = 0) in vec3 aVertexPos; +layout(location = 4) in mat4 worldTransform; + +layout(set = 1, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 projMat; +} cameraData; + +void main() +{ + // clip space for rendering + gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); +} \ No newline at end of file diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb b/Assets/Shaders/ShadowMap_VS.shshaderb new file mode 100644 index 0000000000000000000000000000000000000000..3a8734c9daf1a50b7a6993c299eb04bab307964a GIT binary patch literal 1537 zcmZ9LTW`}q5QVq7wY0RQlwN>Rl7^dvRPg`^2?0Vaavy>kRK%-gB?c{W9LsT2;Hf{M z@RRseeL>=Uwl}i6)nshUe|`(gSeOtbKZLZJoDp4@n1 zGdqrj&gXpe=eUit6Z=b@sVQ=3R_-9O$)TNOK|Ba&Ic`txG>T@qrtZnTSxx<|$sYux zFbxiaEGV>qu@Wal`&P+C%QX2IWEBhzQyZRvIv%}~bo?ERKI@7Hl|IaZ*`JNmX!tn| z;>p)>Iw~~rJ%VC9nuRe(s%LI2=N*O~FucRi1BM2Nu?OROc*?McN8a7HtC)2p78qyp z{2YfE&W$UW9%hLZb(~wRBc`q|b7z5FtwUqAj+nX&nX3bHb=(7;oaIR~Gv1S-)5RU_ zS;X$G7c*$&@19w+)^!T!baW;?*l%jrl5fklR8L=G>NoVue^gt>dRoTUw5R`$;zfD* zV7uBeb9V+gtS#Pkd3ut6UB>w`H75AL3ORYg;kjgLBbEA7hH;u1BXw{yus+_W^2s(JNS=; zQ;YVOdI{*_PAu?CA-s?G`bFEO4E<<+BPP1GWZ*8oqdgk`sD}Jq860ppXuB^%*C%n% z)G0B!8MaqqXm`ABiJ`ME)#!d8qaHr_w(PggCHGK9e>mKM`#zTOt@)mBbxUG+|1_mn Fvi~Asj5 literal 0 HcmV?d00001 diff --git a/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta new file mode 100644 index 00000000..837cec19 --- /dev/null +++ b/Assets/Shaders/ShadowMap_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: ShadowMap_VS +ID: 44646107 +Type: 2 diff --git a/Assets/Shaders/TestCube_FS.glsl b/Assets/Shaders/TestCube_FS.glsl index b6a1eab6..cb7bfefd 100644 --- a/Assets/Shaders/TestCube_FS.glsl +++ b/Assets/Shaders/TestCube_FS.glsl @@ -16,11 +16,12 @@ layout(location = 0) in struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } In; // material stuff -layout(location = 3) flat in struct +layout(location = 4) flat in struct { int materialIndex; uint eid; @@ -38,12 +39,14 @@ layout(location = 1) out uint outEntityID; layout(location = 2) out uint lightLayerIndices; layout(location = 3) out vec4 normals; layout(location = 4) out vec4 albedo; +layout(location = 5) out vec4 worldSpacePosition; void main() { position = In.vertPos; normals = In.normal; albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) * MatProp.data[In2.materialIndex].color; + worldSpacePosition = In.worldPos; outEntityID = In2.eid; lightLayerIndices = In2.lightLayerIndex; diff --git a/Assets/Shaders/TestCube_FS.shshaderb b/Assets/Shaders/TestCube_FS.shshaderb index abd90cf744ad1b20429e7740fe4354edc390101c..2974523d7405e05bdcf30d419f0663694bcc271b 100644 GIT binary patch delta 444 zcmYjLu}T9`5Zv|d@=WA3sJT*L!*Ke zWC_dzo|F6A>p}7$;y!ht4I}hs>iON})eTy48Yd%>06%vmkEtD{ar$!BfnvnEuD7e| zPoDhx7Kb;00O*OI4UlWj?c~EBuKb-xPQ(;3t`>aj#Xjtdpj^RZb?{}>X3jUkkMegF zm40$&qM!X^RG#|Zx2|uTzLp`kfDquyChSab2vBcf2~U%^k)NwhfE}O)(9g9UfI9s= bO+NQ`@uq(rnEQKpL$7257KFkKDffV1b_6lJ delta 288 zcmYk0ISRr+6o%h38G=#4jo67GT4-TmqqvR>Vq@(AY%J6!3N}_=Amko`4tO6c?;r&H zpC~x+G4n6;W}@69>!p`*`YbC}c8HiU%f*Ro&r9T4F&x2oo{Pm@;aTXon(H3|Ey#FFQ diff --git a/Assets/Shaders/TestCube_VS.glsl b/Assets/Shaders/TestCube_VS.glsl index 554ce379..041c552f 100644 --- a/Assets/Shaders/TestCube_VS.glsl +++ b/Assets/Shaders/TestCube_VS.glsl @@ -17,11 +17,12 @@ layout(location = 0) out struct vec4 vertPos; // location 0 vec2 uv; // location = 1 vec4 normal; // location = 2 + vec4 worldPos; // location = 3 } Out; // material stuff -layout(location = 3) out struct +layout(location = 4) out struct { int materialIndex; uint eid; @@ -49,6 +50,8 @@ void main() // gBuffer position will be in view space Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f); + Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f); + // uvs for texturing in fragment shader Out.uv = aUV; diff --git a/Assets/Shaders/TestCube_VS.shshaderb b/Assets/Shaders/TestCube_VS.shshaderb index a1138f75c885a67d6cb7ac2abb1928fe9de3a08e..0467a41d3c9dffd337d9ea55d160e5a79bb1d13c 100644 GIT binary patch literal 3905 zcmZ9NX?GM=5QaP3fGh&CDu^?H21OASFp6vf1~8ByA?^-srU{LcnK+q*#V!5=@hADK z{Ng!2Pfu6q!_9fmt$J&@b?a77h9>_~=Tl4NsIEB48$ z+f&Dv`>o?APo2=^#bl)L)Mp!iu2Ha<<{jltU@O=K-Ujc3)8IPz4)nnq7~yZ2{T~vI z5;Zy1oSdGXoVwDSUs`G|_aC>jW;^d>%~sya=KJ|-rr*YjU*4H-ue7QTV|Y|+8RLwN zoZ+e^8`kB;w4e3zw0*79${rOqGuw$I$@12^ul2R_h5P-f^l{c3czcF-oL=dBwPcLE z-glwhyw+Lnr=9sM(qbDc`jB_}*+SO4oc2?gT5<&c#cnHW&*j;}8>uZRd|zk3lrCny zv~b0`~#N-I+=6%wer1Gst~QqY-qN)66ki%v5@FaF~8Qc-~?r>kX3WXASZ$ zZP7|+Lf-ldo`<@fKVj008Q8oFwoC1N>2f}J-*uaJ(zeoWuiLDDln1RFSuB*hv`;Qg+vw6^G`*R#0dC3jpyi+w! z-8g$3=gB=E=Y6Yj>c;&AB2F&iCh3KBn#+4ScZY!e4!wcwQg;TceQ`e2UE2K}sp`&$ zdgSx>McwnPC*IuNx`NYR&OJC|i+dKsJZAGsLL-dn0$O%o+Eoqi=yXzj^dmcb??5`wMNX_K4qs ztbH%`m)Jeqn)Tnwu1(&2>dvE_@%rutF8%kgYm53{M)o}QIB!3)`6K=SvN3z`tg{Pi zX_T`4-iLmOT~6Jz4zrtA{vbDUwzR7U^m_w+7-;tn>fU{23H!QKG!?!r9pv3qyz=23Ts<;-)EyWbM5E z=a9_R0MXkEC8zxwva!}>K6SqlIqg&I#%s5~H`zT~PWv>w{gsb;{H7wli9GOq_LeO; z`*MKzpV{k$Jm{0(U!&x-4eX-wyny{Ep6%QC%PH&huWd3pnTIFxNgHua7hS3NXhG zU=DSCBFC%9=5W>{hrbu{k>fRFbNGFjLtP*3&gh$99B4O(^Z6E#5B(ivXZ3Glv>ylh z$eYvN$c6t0$a3nw{fEGryG4AR{Uadf3hrZMIo~6=GbQKS%+Mj<`4eEg{@R`0r{vXk z7I?Nk-p^S+5Bxsj9n|%US}!7dx2W|~p*|Mvl~GFm=AS*;%>K)eTOYf=pptmfHf;?n=Rk_ zHnKMF*C_ZTk#kM+U&1%M17=IG6?wdC#LOWZWB!Qw5?Nljv{hriLN`V(V!lR}7p{nz z;SM*^zX8@_Zhh^O-=e(t*5_Lw7jODKvcECTiFf${=p%oTyiNAIz+UbLev|RmDYE`9 z&$`Pl7jZu#N1Web#LXicXZ^TWeBkmruarVSG{p4as7LX&(`!&$-1NrD- zUUKp-YcQX4;Qb$zoHMC!)btZ_e-pIpRsD{<8x zER}K51O4Re!BO@VFb#^drAabax_sqBD92qnWx_e3KUPID^nwWeh~${$70D&Z$C9g(mSkPBBiWOb^;gpV zuM$-h)$a7#YisS!?OuO8?oE&xH~8ks$vvtsp^cw zI)hbnhxYZMm-unug{#rP=iaq6Go5hG4+i^O>I;MI$4SR~=EoVEGq~g0Zo<`ERe8DZ zcGz2uCW#mIeM>7}HSI$XCH}S_uXu?kq~IIEGfJ|xO(38<186G`UTFyXD#FH!KpLF^&soPADSp) zG9NX|w;TrJl^}b^eINb9w;P80K6=9}v*;-^?QM9`wjZVM+0N%=PB`({%*m`|F}L|f z@H3-#l!G^AEo7Up%Kkf7g&Bu?z&UvU)5n}+SsZsN#$glJl~^vYgK^YbjKe1GFNwv0 zSzKE;q;_&~&!+Zy33Zy?kj}zp*0?v{DmL?h&BA6zigqivEg!!l_&JYy?9J&d%P{z0 z?1m8oM*W7NgJt!U(|mRp-j%c9oYslp4O!UeXB1V_UYBqVHhsZn&8a@#7Y=yltGJh> zlLOy%#bEQh0=AgvwENU$9~Dl1^1#Ptp1|<)OH3?&i$5hD|2g?z*3Q|~4F9xteBk86 zW*)(ahkHiCf`3*!KCAy#>70jc=e;hS{1$&fIx%O(tZPT8rIG9O`@HOV?O@oPwV<86 z;B&eWvxOhq1m4@SOA`Ft0lS%F_}|HOVz3vr&q%Q0V>63j)b)Y(x`dp(8^3oA2{=1B zKGM#;@sR_Y`2{1#W$pFchJQu+j07A$HuDWepX%DLNu2xh7W|vi$kmWwf2kcVH4u;8 zl7Qh~)(#&(y}YfRv%v6wt({(i+xdJy7QZPyNQibTDk*{!fg$X?}mi4;c!1@_m+h3!QKHI z9;KDunxwo2_uF)7Sm02>}**~S9jn$yf2{^a>M0KnQw6J z4d*)vn7!$SbiP}9&s`o!;DEQ3m+$y{3B6>tm~-w`*ZzY9K8v&9fmz&-(k+hJwz!|9 z6G#2T!2`3npQT&eL+KXxi*(}X332eiY({>SZgJeNA-g95w;pcg7&yy%$Q*EgFURQB zmc(lMO}gbS_Mk7E7#20b1GBh+bc-wYz!z?35eE;<;vN;^iaprQELEZ(l1HucVHwP4!F(5SbFhW|6Mj1%ibfF4n_|Ro8%bv*|(lZCmufj;agI_a9^e_#I #include namespace SHADE @@ -151,6 +151,32 @@ namespace SHADE return (componentSet.GetSparseSet()->GetElement_s(EntityHandleGenerator::GetIndex(entityID))); } + /*!************************************************************************* + * \brief + * Gets the Component of the entity with the specified entityID + * + * This is the safe version of GetComponent_s which does a HasComponent to make + * sure that the entity has such a component and returns nullptr if it doesn't + * + * This safe version also checks if the sparse set of this component type + * has been created in SHComponentManager and creates one if it doesn't + * + * @tparam T... + * Pack of Types for all the Components to get. + * \param entityID + * EntityID of the entity that we are trying to get the component of. + * \return + * A tuple of pointers to all the components specified. + * Returns nullptr if the entity does not contain such a component. + ***************************************************************************/ + + template + static std::enable_if_t<(... && std::is_base_of_v), std::tuple> GetComponents(EntityID entityID) noexcept + { + return std::make_tuple(GetComponent_s(entityID)...); + } + + /*!************************************************************************* * \brief * Gets the Component of the entity with the specified entityID diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp index 6e982045..a7ba7dc0 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp @@ -259,6 +259,13 @@ namespace SHADE } } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("AssetID: %zu | Path: %s", asset->id, asset->path.c_str()); + ImGui::EndTooltip(); + } + //TODO: Combine Draw asset and Draw Folder recursive drawing const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark); const float horizontalOffset = 0.0f; diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 64691cc5..55de44cc 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -21,6 +21,7 @@ #include "UI/SHUIComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" +#include "UI/SHToggleButtonComponent.h" #include "SHEditorComponentView.h" #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" @@ -153,6 +154,10 @@ namespace SHADE { DrawComponent(buttonComponent); } + if (auto toggleButton = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(toggleButton); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -166,6 +171,7 @@ namespace SHADE DrawAddComponentButton(eid); DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); // Components that require Transforms diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index fba1c591..2dc417e7 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -468,7 +468,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass(); + auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) { @@ -487,7 +487,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index 8077fcc1..c090cd69 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -23,4 +23,5 @@ constexpr SHEventIdentifier SH_SCENE_INIT_POST { 14 }; constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 }; constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 }; +constexpr SHEventIdentifier SH_BUTTON_CLICK_EVENT { 18 }; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index e77234ca..8143ec0e 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -175,6 +175,27 @@ namespace SHADE writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].imageLayout = layout; } + + // Rest is not used, so it doesn't matter what's in them, we just want to pacify Vulkan + for (uint32_t i = imageViewsAndSamplers.size(); i < writeInfo.descImageInfos.size(); ++i) + { + writeInfo.descImageInfos[i].sampler = std::get>(imageViewsAndSamplers.back())->GetVkSampler(); + } + } + + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept + { + // Find the target writeDescSet + BindingAndSetHash writeHash = binding; + writeHash |= static_cast(set) << 32; + auto& writeInfo = updater.writeInfos[updater.writeHashMap.at(writeHash)]; + + // write sampler and image view + auto& [view, sampler, layout] = imageViewAndSampler; + writeInfo.descImageInfos[descIndex].imageView = view->GetImageView(); + writeInfo.descImageInfos[descIndex].sampler = sampler ? sampler->GetVkSampler() : nullptr; + writeInfo.descImageInfos[descIndex].imageLayout = layout; + } void SHVkDescriptorSetGroup::ModifyWriteDescBuffer(uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept @@ -200,6 +221,28 @@ namespace SHADE } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImage(uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept + { + vk::WriteDescriptorSet writeDescSet{}; + + // Get binding + set hash + BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); + + // to index a write for a binding + uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; + + // Initialize info for write + writeDescSet.descriptorType = layoutsUsed[set]->GetBindings()[binding].Type; + writeDescSet.dstArrayElement = descArrayIndex; + writeDescSet.dstSet = descSets[set]; + writeDescSet.dstBinding = binding; + + writeDescSet.pImageInfo = updater.writeInfos[writeInfoIndex].descImageInfos.data() + descArrayIndex; + writeDescSet.descriptorCount = 1u; + + device->UpdateDescriptorSet(writeDescSet); + } + void SHVkDescriptorSetGroup::UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept { vk::WriteDescriptorSet writeDescSet{}; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index a228bc66..5b65174a 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -63,10 +63,12 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Public member functions */ /*-----------------------------------------------------------------------------*/ + void UpdateDescriptorSetImage (uint32_t set, uint32_t binding, uint32_t descArrayIndex) noexcept; void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept; void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept; void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::tuple, Handle, vk::ImageLayout> const& imageViewAndSampler, uint32_t descIndex) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 6a6e385f..5653bbe7 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -183,33 +183,43 @@ namespace SHADE /*if (!extensionsSupported) SHUtil::ReportWarning("Some of the required extensions cannot be found on the physical device. ");*/ - vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED + vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature + { + .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .descriptorBindingPartiallyBound = VK_TRUE, + .descriptorBindingVariableDescriptorCount = VK_TRUE, + .runtimeDescriptorArray = VK_TRUE, + }; + + vk::PhysicalDeviceRobustness2FeaturesEXT robustFeatures + { + .nullDescriptor = VK_TRUE, + }; + + robustFeatures.pNext = &descIndexingFeature; + + vk::PhysicalDeviceFeatures2 features{}; // ADD MORE FEATURES HERE IF NEEDED // point and lines fill mode - features.fillModeNonSolid = VK_TRUE; - features.samplerAnisotropy = VK_TRUE; - features.multiDrawIndirect = VK_TRUE; - features.independentBlend = VK_TRUE; + features.features.fillModeNonSolid = VK_TRUE; + features.features.samplerAnisotropy = VK_TRUE; + features.features.multiDrawIndirect = VK_TRUE; + features.features.independentBlend = VK_TRUE; + features.features.wideLines = VK_TRUE; - // for wide lines - features.wideLines = true; - - vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{}; - descIndexingFeature.descriptorBindingVariableDescriptorCount = true; - descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true; - descIndexingFeature.runtimeDescriptorArray = true; + features.pNext = &robustFeatures; // Prepare to create the device vk::DeviceCreateInfo deviceCreateInfo { - .pNext = &descIndexingFeature, + .pNext = &features, .queueCreateInfoCount = static_cast(queueCreateInfos.size()), .pQueueCreateInfos = queueCreateInfos.data(), .enabledLayerCount = 0, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored .enabledExtensionCount = !extensionsSupported ? 0 : static_cast(requiredExtensions.size()), .ppEnabledExtensionNames = !extensionsSupported ? nullptr : requiredExtensions.data(), - .pEnabledFeatures = &features + //.pEnabledFeatures = &features }; // Actually create the device diff --git a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h index ab120a1f..06c480ef 100644 --- a/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h +++ b/SHADE_Engine/src/Graphics/Events/SHGraphicsEvents.h @@ -10,5 +10,8 @@ namespace SHADE { //! We need to get the light component and initialize the relevant variables. EntityID lightEntity; + + //! Generate a renderer for the light component + bool generateRenderer; }; } diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index 7443b6e2..255fa5e4 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -33,6 +33,7 @@ namespace SHADE .maxAnisotropy = 1.0f, .minLod = params.minLod, .maxLod = params.maxLod, + .borderColor = vk::BorderColor::eFloatOpaqueWhite }; // Create the sampler diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 7e4069f6..fd2ccd3b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -551,7 +551,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* SHBatch - Usage Functions */ /*---------------------------------------------------------------------------------*/ - void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) + void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -566,7 +566,10 @@ namespace SHADE // Bind all required objects before drawing static std::array dynamicOffset{ 0 }; cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); - cmdBuffer->BindPipeline(pipeline); + + if (bindBatchPipeline) + cmdBuffer->BindPipeline(pipeline); + cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); if (matPropsDescSet[frameIndex]) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d4ce068e..6d1f775f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -87,7 +87,7 @@ namespace SHADE void UpdateTransformBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex); void Build(Handle device, Handle descPool, uint32_t frameIndex) ; - void Draw(Handle cmdBuffer, uint32_t frameIndex); + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index 58993026..8006d0be 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -107,12 +107,12 @@ namespace SHADE } } - void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept + void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline /*= true*/) noexcept { // Build all batches for (auto& batch : batches) { - batch.Draw(cmdBuffer, frameIndex); + batch.Draw(cmdBuffer, frameIndex, bindBatchPipeline); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index 75bd1829..4d831b9c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -57,7 +57,7 @@ namespace SHADE void Clear() noexcept; void UpdateBuffers(uint32_t frameIndex, Handle descPool); void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; - void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Draw(Handle cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true) noexcept; /*-----------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index ffe29b36..d5f744fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -13,6 +13,8 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ std::vector> SHGraphicsPredefinedData::predefinedLayouts; SHVertexInputState SHGraphicsPredefinedData::defaultVertexInputState; + SHVertexInputState SHGraphicsPredefinedData::shadowMapVertexInputState; + std::vector SHGraphicsPredefinedData::perSystemData; //SHGraphicsPredefinedData::PerSystem SHGraphicsPredefinedData::batchingSystemData; @@ -150,12 +152,26 @@ namespace SHADE Handle fontDataDescSetLayout = logicalDevice->CreateDescriptorSetLayout({ fontBitmapBinding, fontMatrixBinding }); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, fontDataDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Font Data"); + // descriptor binding for storing shadow maps + SHVkDescriptorSetLayout::Binding shadowMapBinding + { + .Type = vk::DescriptorType::eCombinedImageSampler, + .Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + .DescriptorCount = 200, // we can have up to 200 textures for now + .flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount, + }; + + // For global data (generic data and textures) + Handle shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding }); + SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps"); predefinedLayouts.push_back(staticGlobalLayout); predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(cameraDataGlobalLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(fontDataDescSetLayout); + predefinedLayouts.push_back(shadowMapDescLayout); perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts ( @@ -179,7 +195,7 @@ namespace SHADE ); } - void SHGraphicsPredefinedData::InitDefaultVertexInputState(void) noexcept + void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept { defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 @@ -187,13 +203,16 @@ namespace SHADE defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3 defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots) defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 + + shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)}); + shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots) } void SHGraphicsPredefinedData::Init(Handle logicalDevice) noexcept { perSystemData.resize(SHUtilities::ConvertEnum(SystemType::NUM_TYPES)); InitDescSetLayouts(logicalDevice); - InitDefaultVertexInputState(); + InitPredefinedVertexInputState(); InitDescMappings(); InitDummyPipelineLayouts (logicalDevice); } @@ -217,6 +236,11 @@ namespace SHADE } + SHVertexInputState const& SHGraphicsPredefinedData::GetShadowMapViState(void) noexcept + { + return shadowMapVertexInputState; + } + SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetSystemData(SystemType systemType) noexcept { return perSystemData[static_cast(systemType)]; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h index 11bfc469..9331ed01 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h @@ -28,6 +28,7 @@ namespace SHADE CAMERA = 0x04, MATERIALS = 0x08, FONT = 0x10, + SHADOW = 0x20, }; enum class SystemType @@ -57,6 +58,9 @@ namespace SHADE //! Default vertex input state (used by everything). static SHVertexInputState defaultVertexInputState; + //! vertex input state for shadow mapping + static SHVertexInputState shadowMapVertexInputState; + //! Predefined data for each type of system static std::vector perSystemData; @@ -72,7 +76,7 @@ namespace SHADE static void InitDescMappings (void) noexcept; static void InitDummyPipelineLayouts (Handle logicalDevice) noexcept; static void InitDescSetLayouts (Handle logicalDevice) noexcept; - static void InitDefaultVertexInputState (void) noexcept; + static void InitPredefinedVertexInputState (void) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -90,6 +94,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ static std::vector> GetPredefinedDescSetLayouts (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes types) noexcept; static SHVertexInputState const& GetDefaultViState (void) noexcept; + static SHVertexInputState const& GetShadowMapViState (void) noexcept; static PerSystem const& GetSystemData (SystemType systemType) noexcept; static SHDescriptorMappings::MapType const& GetMappings (SystemType systemType) noexcept; //static PerSystem const& GetBatchingSystemData(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h index 931101f4..fc7f6a1b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h @@ -13,7 +13,7 @@ namespace SHADE CAMERA, MATERIALS, FONT, - RENDER_GRAPH_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE, + RENDER_GRAPH_RESOURCE, }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index b57249de..e8868eba 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,9 +101,13 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); auto renderGraph = gfxSystem->GetRenderGraph(); - auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); + auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw"); subPass->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { + // Set line width first + cmdBuffer->SetLineWidth(LineWidth); + + // Draw const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); cmdBuffer->BeginLabeledSegment("SHDebugDraw (No Depth Test)"); { @@ -125,9 +129,13 @@ namespace SHADE } cmdBuffer->EndLabeledSegment(); }); - auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); + auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth"); subPassWithDepth->AddExteriorDrawCalls([this](Handle cmdBuffer, Handle renderer, uint32_t frameIndex) { + // Set line width first + cmdBuffer->SetLineWidth(LineWidth); + + // Draw const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); cmdBuffer->BeginLabeledSegment("SHDebugDraw (Depth Tested)"); { @@ -207,6 +215,11 @@ namespace SHADE drawSphere(getMeshBatch(true, depthTested), matrix, color); } + void SHDebugDrawSystem::DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + drawWireCapsule(getLineBatch(depthTested), getMeshBatch(false, depthTested), position, rotation, height, radius, color); + } + /*-----------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ /*-----------------------------------------------------------------------------------*/ @@ -264,6 +277,12 @@ namespace SHADE markPersistentDrawsDirty(); } + void SHDebugDrawSystem::DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + drawWireCapsule(getPersistentLineBatch(depthTested), getPersistentMeshBatch(false, depthTested), position, rotation, height, radius, color); + markPersistentDrawsDirty(); + } + void SHDebugDrawSystem::ClearPersistentDraws() { for (auto& batch : persistentLineBatches) @@ -348,6 +367,53 @@ namespace SHADE ); } + void SHDebugDrawSystem::drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color) + { + // Get local axis vectors + const SHVec3 LOCAL_UP = SHVec3::Rotate(SHVec3::Up, rotation); + const SHVec3 LOCAL_RIGHT = SHVec3::Rotate(SHVec3::Right, rotation); + const SHVec3 LOCAL_FORWARD = SHVec3::Rotate(SHVec3::Forward, rotation); + + // Rotate the circle + SHQuaternion circleOrientation = SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(90.0), 0.0f, 0.0f)) * rotation; + + // Compute top and bottom of the cylinder + const SHVec3 HALF_UP = LOCAL_UP * (height * 0.5f - radius); + const SHVec3 TOP_POS = position + HALF_UP; + const SHVec3 BOT_POS = position - HALF_UP; + + // Render circles + const SHVec3 CIRCLE_SCALE = SHVec3(radius * 2.0f, radius * 2.0, radius * 2.0); + drawCircle(meshBatch, SHMatrix::Transform(TOP_POS, circleOrientation, CIRCLE_SCALE), color); + drawCircle(meshBatch, SHMatrix::Transform(BOT_POS, circleOrientation, CIRCLE_SCALE), color); + + // Render connecting lines + drawLine(lineBatch, TOP_POS + LOCAL_RIGHT * radius, BOT_POS + LOCAL_RIGHT * radius, color); + drawLine(lineBatch, TOP_POS - LOCAL_RIGHT * radius, BOT_POS - LOCAL_RIGHT * radius, color); + drawLine(lineBatch, TOP_POS + LOCAL_FORWARD * radius, BOT_POS + LOCAL_FORWARD * radius, color); + drawLine(lineBatch, TOP_POS - LOCAL_FORWARD * radius, BOT_POS - LOCAL_FORWARD * radius, color); + + // Render caps + const SHVec3 RADIUS_SCALE = SHVec3(radius * 2.0, radius * 2.0f, radius * 2.0); + const SHMatrix TOP_CAP_MAT = SHMatrix::Transform(TOP_POS, rotation, RADIUS_SCALE); + drawMesh + ( + gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap), + meshBatch, TOP_CAP_MAT, color + ); + const SHMatrix BOT_CAP_MAT = SHMatrix::Transform + ( + BOT_POS, + SHQuaternion::FromEuler(SHVec3(SHMath::DegreesToRadians(180.0), 0.0f, 0.0f)) * rotation, + RADIUS_SCALE + ); + drawMesh + ( + gfxSystem->GetMeshPrimitive(PrimitiveType::LineCapsuleCap), + meshBatch, BOT_CAP_MAT, color + ); + } + /*-----------------------------------------------------------------------------------*/ /* Helper Batch Functions - Lines */ /*-----------------------------------------------------------------------------------*/ @@ -448,7 +514,6 @@ namespace SHADE if (batch.NumPoints[frameIndex] > 0) { cmdBuffer->BindPipeline(batch.Pipeline); - cmdBuffer->SetLineWidth(LineWidth); cmdBuffer->BindVertexBuffer(0, batch.VertexBuffers[frameIndex], 0); cmdBuffer->DrawArrays(batch.NumPoints[frameIndex], 1, 0, 0); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h index 2978d68e..3997b6df 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h @@ -163,6 +163,17 @@ namespace SHADE /// Colour to draw with. /// Whether or not drawn object will be occluded. void DrawSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// + /// Draws the outline of a capsule. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void DrawWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ @@ -269,6 +280,17 @@ namespace SHADE /// Whether or not drawn object will be occluded. void DrawPersistentSphere(const SHMatrix& matrix, const SHColour& color = SHColour::WHITE, bool depthTested = false); /// + /// Draws a persistent outline of a capsule. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + void DrawPersistentWireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// /// Clears any persistent drawn debug primitives. /// void ClearPersistentDraws(); @@ -386,6 +408,7 @@ namespace SHADE void drawCube(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); void drawSphere(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); void drawCircle(MeshBatch& batch, const SHMatrix& transformMatrix, const SHColour& color); + void drawWireCapsule(LinesBatch& lineBatch, MeshBatch& meshBatch, const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color); /*---------------------------------------------------------------------------------*/ /* Helper Batch Functions - Lines */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index c889a321..b3945689 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,68 +31,91 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - //struct DescriptorSetIndex - //{ - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for static global values like generic data, and - // texture samplers - // */ - // /***************************************************************************/ - // static constexpr uint32_t STATIC_GLOBALS = 0; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for dynamic global values like lights. - // */ - // /***************************************************************************/ - // static constexpr uint32_t DYNAMIC_GLOBALS = 1; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for high frequency changing global values like - // camera matrices. - // */ - // /***************************************************************************/ - // static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for per-instance/material changing values. - // */ - // /***************************************************************************/ - // static constexpr uint32_t PER_INSTANCE = 3; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph resources. Unlike the sets from - // 1 to 3 and 6, this set index does not have hard coded bindings and is - // NOT part of the layouts included in the global data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; - // /***************************************************************************/ - // /*! - // \brief - // DescriptorSet Index for render graph node compute resources. For data - // that we wish to pass to compute shaders in the render graph, this is - // the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have - // hard coded bindings and is NOT part of the layouts included in the global - // data. - // */ - // /***************************************************************************/ - // static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5; + struct RenderGraphEntityNames + { + /***************************************************************************/ + /*! + + \brief + Name of G-Buffer render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view GBUFFER_PASS = "G-Buffer"; - // /***************************************************************************/ - // /*! - // \brief - // To store font data. - // - // */ - // /***************************************************************************/ - // static constexpr uint32_t FONT_DATA = 4; - //}; + /***************************************************************************/ + /*! + + \brief + Name of shadow map render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw with Depth render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of Debug Draw render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of screen space pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of ImGui pass render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view IMGUI_PASS = "ImGui Pass"; + + /***************************************************************************/ + /*! + + \brief + Name of deferred composite compute. + + */ + /***************************************************************************/ + static constexpr std::string_view DEFERRED_COMPOSITE_COMPUTE = "Deferred Composite"; + + + + }; struct DescriptorSetBindings { @@ -158,6 +181,16 @@ namespace SHADE /***************************************************************************/ static constexpr uint32_t FONT_MATRIX_DATA = 1; + /***************************************************************************/ + /*! + \brief + Descriptor set binding for shadow map images. + + */ + /***************************************************************************/ + static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; + + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index b1256921..c4990153 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -44,6 +44,9 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" +#include "Events/SHEvent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" +#include "Input/SHInputManager.h" namespace SHADE { @@ -124,6 +127,13 @@ namespace SHADE SHFreetypeInstance::Init(); + SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false); + SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false); + // Load Built In Shaders static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet(VS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet(FS_DEFAULT); @@ -137,6 +147,8 @@ namespace SHADE static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet(TEXT_FS); static constexpr AssetID RENDER_SC_VS = 48082949; renderToSwapchainVS = SHResourceManager::LoadOrGet(RENDER_SC_VS); static constexpr AssetID RENDER_SC_FS = 36869006; renderToSwapchainFS = SHResourceManager::LoadOrGet(RENDER_SC_FS); + static constexpr AssetID SHADOW_MAP_VS = 44646107; shadowMapVS = SHResourceManager::LoadOrGet(SHADOW_MAP_VS); + } void SHGraphicsSystem::InitRenderGraph(void) noexcept @@ -169,6 +181,8 @@ namespace SHADE // Create Default Viewport worldViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); + shadowMapViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(SHLightingSubSystem::SHADOW_MAP_WIDTH), static_cast(SHLightingSubSystem::SHADOW_MAP_HEIGHT), 0.0f, 1.0f)); + std::vector> renderContextCmdPools{ swapchain->GetNumImages() }; for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) { @@ -183,22 +197,24 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Initialize world render graph renderGraph->Init("World Render Graph", device, swapchain, &resourceManager, renderContextCmdPools); - renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Position World Space", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); + renderGraph->AddResource("Normals", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); //worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat); - renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second); - renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); - renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, windowDims.first, windowDims.second); - renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); - renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + renderGraph->AddResource("Albedo", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("Depth Buffer", { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL }, true, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); + renderGraph->AddResource("Entity ID", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Light Layer Indices", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + renderGraph->AddResource("Scene", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE, SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED }, true, windowDims.first, windowDims.second); + renderGraph->AddResource("SSAO", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, true, windowDims.first, windowDims.second, vk::Format::eR8Unorm); + renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, true, windowDims.first, windowDims.second); /*-----------------------------------------------------------------------*/ /* MAIN NODE */ /*-----------------------------------------------------------------------*/ - auto gBufferNode = renderGraph->AddNode("G-Buffer", + auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), + //auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data() { "Position", "Entity ID", @@ -207,7 +223,8 @@ namespace SHADE "Albedo", "Depth Buffer", "SSAO", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, {}); // no predecessors @@ -220,6 +237,7 @@ namespace SHADE gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Normals"); gBufferSubpass->AddColorOutput("Albedo"); + gBufferSubpass->AddColorOutput("Position World Space"); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL); @@ -254,53 +272,52 @@ namespace SHADE // Add another pass to blur SSAO Handle ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); - /*-----------------------------------------------------------------------*/ - /* SHADOW MAP PASS */ - /*-----------------------------------------------------------------------*/ - // Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. - // It will initially also not have any subpasses since they will be added for each light that casts shadows. - //auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {}); - - /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE NODE */ /*-----------------------------------------------------------------------*/ // This pass will facilitate both lighting and shadows in 1 single pass. - auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass", + auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), { "Position", "Light Layer Indices", "Normals", "Albedo", "Scene", - "SSAO Blur" + "SSAO Blur", + "Position World Space" }, - {"G-Buffer"}); + { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS .data()}); + /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ /*-----------------------------------------------------------------------*/ - deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); + auto deferredCompositeCompute = deferredCompositeNode->AddNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data(), deferredCompositeShader, {"Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Position World Space", "Scene"}, {}, SHLightingSubSystem::MAX_SHADOWS); + deferredCompositeCompute->AddPreComputeFunction([=](Handle cmdBuffer, uint32_t frameIndex) + { + lightingSubSystem->PrepareShadowMapsForRead(cmdBuffer); + }); + /*-----------------------------------------------------------------------*/ /* DEBUG DRAW PASS INIT */ /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - Depth Tested - auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"}); + auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data()}); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - No Depth Test - auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" }); + auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW_DEPTH_PASS.data()}); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* SCREEN SPACE PASS */ /*-----------------------------------------------------------------------*/ - auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" }); + auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEBUG_DRAW.data()}); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -315,16 +332,16 @@ namespace SHADE #ifdef SHEDITOR { // Dummy Node to transition scene render graph resource - auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" }); + auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); dummySubpass->AddInput("Scene"); - auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {}); + auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::IMGUI_PASS.data(), {"Present"}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -393,12 +410,16 @@ namespace SHADE postOffscreenRenderSubSystem->Init(device, renderGraph->GetRenderGraphResource("Scene"), descPool); lightingSubSystem = resourceManager.Create(); - lightingSubSystem->Init(device, descPool); + lightingSubSystem->Init(device, descPool, &resourceManager, samplerCache.GetSampler (device, SHVkSamplerParams + { + .addressMode = vk::SamplerAddressMode::eClampToBorder, + }) + ); textRenderingSubSystem = resourceManager.Create(); // initialize the text renderer - auto uiNode = renderGraph->GetNode("Screen Space Pass"); + auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SCREEN_SPACE_PASS.data()); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -419,13 +440,14 @@ namespace SHADE primitiveMeshes[static_cast(PrimitiveType::Sphere)] = SHPrimitiveGenerator::Sphere(meshLibrary); primitiveMeshes[static_cast(PrimitiveType::LineCube)] = SHPrimitiveGenerator::LineCube(meshLibrary); primitiveMeshes[static_cast(PrimitiveType::LineCircle)] = SHPrimitiveGenerator::LineCircle(meshLibrary); + primitiveMeshes[static_cast(PrimitiveType::LineCapsuleCap)] = SHPrimitiveGenerator::LineCapsuleCap(meshLibrary); BuildMeshBuffers(); // Create default materials defaultMaterial = AddMaterial ( defaultVertShader, defaultFragShader, - renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write") + renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") ); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); } @@ -450,6 +472,7 @@ namespace SHADE InitMiddleEnd(); InitSubsystems(); InitBuiltInResources(); + InitEvents(); } void SHGraphicsSystem::Exit(void) @@ -545,6 +568,15 @@ namespace SHADE #endif } + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B)) + { + auto& lightComps = SHComponentManager::GetDense(); + for (auto& comp : lightComps) + { + comp.SetEnableShadow(true); + } + } + renderGraph->Begin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); @@ -725,16 +757,61 @@ namespace SHADE renderers.erase(iter); } - SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept + SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept { + // we need to wait for the device to finish using the graph first + device->WaitIdle(); + + auto const& EVENT_DATA = reinterpret_cast*>(eventPtr.get())->data; + auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); + std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + Handle companionSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write"); + + if (EVENT_DATA->generateRenderer) + { + // Create new renderer for the light component and give it to the light component + Handle newRenderer = resourceManager.Create(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); + lightComp->SetRenderer (newRenderer); + + // assign shadow map index to light component + lightComp->SetShadowMapIndex (lightingSubSystem->GetNumShadowMaps()); + } + // Add the shadow map resource to the graph + renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT}, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. + auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + resourceName, {resourceName.c_str()}, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); // Add a subpass to render to that shadow map + auto newSubpass = shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", shadowMapViewport, lightComp->GetRenderer()); + newSubpass->AddDepthOutput(resourceName, SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH); + + // regenerate the node + shadowMapNode->RuntimeStandaloneRegenerate(); + + // Create pipeline from new renderpass and subpass if it's not created yet + if (!shadowMapPipeline) + { + SHPipelineLibrary tempLibrary{}; + Handle rgNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data()); + + SHRasterizationState rasterState{}; + rasterState.cull_mode = vk::CullModeFlagBits::eBack; + + tempLibrary.Init(device); + tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState(), rasterState); + shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); + } + newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline - //renderGraph->GetNode (); - return event->handle; + // add the shadow map to the lighting system + uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(resourceName), EVENT_DATA->lightEntity); + + auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); + nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); + + return eventPtr->handle; } Handle SHGraphicsSystem::AddMaterial(Handle vertShader, Handle fragShader, Handle subpass) @@ -819,6 +896,7 @@ namespace SHADE case PrimitiveType::Sphere: case PrimitiveType::LineCube: case PrimitiveType::LineCircle: + case PrimitiveType::LineCapsuleCap: return primitiveMeshes[static_cast(type)]; default: return {}; @@ -1045,6 +1123,7 @@ namespace SHADE mousePickSubSystem->HandleResize(); postOffscreenRenderSubSystem->HandleResize(); + //lightingSubSystem->HandleResize(renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data())); worldViewport->SetWidth(static_cast(resizeWidth)); worldViewport->SetHeight(static_cast(resizeHeight)); @@ -1077,7 +1156,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 40148e05..c736599f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -72,9 +72,10 @@ namespace SHADE Cube, Sphere, LineCube, - LineCircle + LineCircle, + LineCapsuleCap }; - static constexpr int MAX_PRIMITIVE_TYPES = 4; + static constexpr int MAX_PRIMITIVE_TYPES = 5; enum class DebugDrawPipelineType { LineNoDepthTest, @@ -177,7 +178,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* Light functions */ /*-----------------------------------------------------------------------*/ - SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; + SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept; /*-----------------------------------------------------------------------------*/ /* Material Functions */ @@ -405,10 +406,6 @@ namespace SHADE SHWindow* GetWindow() noexcept { return window; } private: - /*-----------------------------------------------------------------------------*/ - /* Constants */ - /*-----------------------------------------------------------------------------*/ - static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer"; /*-----------------------------------------------------------------------------*/ /* Data Members */ @@ -445,6 +442,7 @@ namespace SHADE #endif Handle worldViewport; // Whole screen + Handle shadowMapViewport; std::vector> viewports; // Additional viewports // Renderers @@ -468,6 +466,7 @@ namespace SHADE Handle textFS; Handle renderToSwapchainVS; Handle renderToSwapchainFS; + Handle shadowMapVS; // Fonts Handle testFont; @@ -482,6 +481,7 @@ namespace SHADE Handle debugDrawWireMeshDepthPipeline; Handle debugDrawFilledPipeline; Handle debugDrawFilledDepthPipeline; + Handle shadowMapPipeline; // initialized only when a shadow map is needed // Built-In Textures Handle defaultTexture; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index f1d4dc7f..731489fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -122,4 +122,9 @@ namespace SHADE return cameraDirector; } + SHShaderCameraData SHRenderer::GetCPUCameraData(void) const noexcept + { + return cpuCameraData; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index baf76187..867851ee 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -18,9 +18,9 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "SHCamera.h" #include "Resource/SHHandle.h" -#include "Graphics/RenderGraph/SHRenderGraph.h" #include "Math/SHMath.h" #include +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -93,6 +93,7 @@ namespace SHADE /* Setters and Getters */ /*-----------------------------------------------------------------------------*/ Handle GetCameraDirector (void) const noexcept; + SHShaderCameraData GetCPUCameraData (void) const noexcept; private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp index 362b0e8f..6943ec09 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp @@ -2,6 +2,7 @@ #include "SHLightComponent.h" #include "Graphics/Events/SHGraphicsEvents.h" #include "Events/SHEventManager.hpp" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" namespace SHADE { @@ -14,6 +15,7 @@ namespace SHADE //indexInBuffer = std::numeric_limits::max(); isActive = true; //Unbind(); + renderer = {}; } @@ -116,11 +118,22 @@ namespace SHADE // Create new event and broadcast it SHLightEnableShadowEvent newEvent; newEvent.lightEntity = GetEID(); + newEvent.generateRenderer = static_cast(!renderer); SHEventManager::BroadcastEvent(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); } } + void SHLightComponent::SetRenderer(Handle newRenderer) noexcept + { + renderer = newRenderer; + } + + void SHLightComponent::SetShadowMapIndex(uint32_t index) noexcept + { + lightData.shadowMapIndex = index; + } + SHLightData const& SHLightComponent::GetLightData(void) const noexcept { return lightData; @@ -172,6 +185,11 @@ namespace SHADE return lightData.strength; } + Handle SHLightComponent::GetRenderer(void) const noexcept + { + return renderer; + } + } RTTR_REGISTRATION diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h index 1d636595..4974f3f5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h @@ -3,9 +3,11 @@ #include #include "ECS_Base/Components/SHComponent.h" #include "SHLightData.h" +#include "Resource/SHHandle.h" namespace SHADE { + class SHRenderer; class SH_API SHLightComponent final : public SHComponent { @@ -14,6 +16,9 @@ namespace SHADE //! GPU depends on the type of the light. SHLightData lightData; + //! Renderer to calculate light world to projection matrix + Handle renderer; + //! Since the lighting system is gonna be self contained and light weight, we store this //! so that we only write this to the CPU buffer when this light component change, we don't //! rewrite everything. However we still write to the GPU buffer when everything changes. @@ -49,6 +54,8 @@ namespace SHADE //void SetBound (uint32_t inIndexInBuffer) noexcept; void SetStrength (float value) noexcept; // serialized void SetEnableShadow (bool flag) noexcept; + void SetRenderer (Handle newRenderer) noexcept; + void SetShadowMapIndex (uint32_t index) noexcept; SHLightData const& GetLightData (void) const noexcept; @@ -61,6 +68,7 @@ namespace SHADE //bool GetBound (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept; float GetStrength (void) const noexcept; + Handle GetRenderer (void) const noexcept; RTTR_ENABLE() }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp index ddacf3a7..9acdfed0 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp @@ -10,6 +10,13 @@ #include "SHLightComponent.h" #include "Math/Vector/SHVec4.h" #include "Math/SHMatrix.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/MiddleEnd/Textures/SHVkSamplerCache.h" +#include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Events/SHGraphicsEvents.h" +#include "Graphics/MiddleEnd/Interface/SHRenderer.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" namespace SHADE { @@ -50,6 +57,19 @@ namespace SHADE //lightPtr->direction = lightData.direction; lightPtr->diffuseColor = lightData.color; lightPtr->active = lightComp->isActive; + + // write view projection matrix if renderer is available + auto lightRenderer = lightComp->GetRenderer(); + if (lightRenderer) + { + lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix; + + // Boolean to cast shadows in first 8 bits (1 byte) + lightPtr->shadowData = lightData.castShadows; + + // Next 24 bits for shadow map index + lightPtr->shadowData |= (lightData.shadowMapIndex << 8); + } break; } case SH_LIGHT_TYPE::POINT: @@ -365,6 +385,32 @@ namespace SHADE } } + void SHLightingSubSystem::UpdateShadowMapDesc(void) noexcept + { + + } + + SHMatrix SHLightingSubSystem::GetViewMatrix(SHLightComponent* lightComp) noexcept + { + switch (lightComp->GetLightData().type) + { + case SH_LIGHT_TYPE::DIRECTIONAL: + return SHMatrix::Transpose(SHMatrix::LookAtLH(lightComp->GetLightData().position, SHVec3::Normalise (lightComp->GetLightData().direction), SHVec3(0.0f, -1.0f, 0.0f))); + //return SHMatrix::Transpose(SHMatrix::LookAtLH(/*lightComp->GetLightData().position*/SHVec3(1.27862f, 4.78952f, 4.12811f), SHVec3(-0.280564f, -0.66262f, -0.69422f), SHVec3(0.0f, -1.0f, 0.0f))); + case SH_LIGHT_TYPE::POINT: + return {}; + case SH_LIGHT_TYPE::SPOT: + return {}; + case SH_LIGHT_TYPE::AMBIENT: + return {}; + case SH_LIGHT_TYPE::NUM_TYPES: + return {}; + default: + return {}; + + } + } + /***************************************************************************/ /*! @@ -375,13 +421,15 @@ namespace SHADE */ /***************************************************************************/ - void SHLightingSubSystem::Init(Handle device, Handle descPool) noexcept + void SHLightingSubSystem::Init(Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept { SHComponentManager::CreateComponentSparseSet(); logicalDevice = device; + resourceHub = rh; uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); +#pragma region LIGHTING std::vector variableSizes{ NUM_LIGHT_TYPES }; std::fill (variableSizes.begin(), variableSizes.end(), 1); @@ -418,7 +466,22 @@ namespace SHADE dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count } +#pragma endregion + +#pragma region SHADOWS + //std::vector shadowDescVariableSizes{ MAX_SHADOWS }; + //shadowMapDescriptorSet = descPool->Allocate({SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::SHADOW)}, shadowDescVariableSizes); + +//#ifdef _DEBUG +// const auto& SHADOW_MAP_DESC_SETS = shadowMapDescriptorSet->GetVkHandle(); +// for (int i = 0; i < static_cast(SHADOW_MAP_DESC_SETS.size()); ++i) +// SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSet, SHADOW_MAP_DESC_SETS[i], "[Descriptor Set] Shadow Map Data Frame #" + std::to_string(i)); +//#endif + + shadowMapSampler = inShadowMapSampler; + shadowMaps.clear(); //numLightComponents = 0; +#pragma endregion } /***************************************************************************/ @@ -452,6 +515,12 @@ namespace SHADE for (auto& light : lightComps) { + if (auto renderer = light.GetRenderer()) + { + //SHMatrix orthoMatrix = SHMatrix::OrthographicRH() + renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(10.0f, 10.0f, 1.0f, 50.0f)); + } + auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); // First we want to make sure the light is already bound to the system. if it @@ -503,7 +572,6 @@ namespace SHADE // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing. ComputeDynamicOffsets(); - } /***************************************************************************/ @@ -526,9 +594,101 @@ namespace SHADE } + uint32_t SHLightingSubSystem::AddShadowMap(Handle newShadowMap, EntityID lightEntity) noexcept + { + // Add to container of shadow maps + shadowMapIndexing.emplace(lightEntity, static_cast (shadowMaps.size())); + shadowMaps.emplace_back(newShadowMap); + + // Just use the image view stored in the resource + Handle const NEW_IMAGE_VIEW = newShadowMap->GetImageView(); + + // Prepare to write to descriptor + shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); + + // Update descriptor set + //static constexpr uint32_t SHADOW_MAP_DESC_SET_INDEX = 0; + //uint32_t const SHADOW_MAP_DESC_ARRAY_INDEX = static_cast(shadowMapImageSamplers.size()) - 1u; + //shadowMapDescriptorSet->ModifyWriteDescImage + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, + // shadowMapImageSamplers[SHADOW_MAP_DESC_ARRAY_INDEX], + // SHADOW_MAP_DESC_ARRAY_INDEX + //); + + //// TODO: Definitely can be optimized by writing a function that modifies a specific descriptor in the array + //shadowMapDescriptorSet->UpdateDescriptorSetImages + //( + // SHADOW_MAP_DESC_SET_INDEX, + // SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA + //); + + // add to barriers + shadowMapMemoryBarriers.push_back (vk::ImageMemoryBarrier + { + .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .oldLayout = vk::ImageLayout::eDepthAttachmentOptimal, + .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = newShadowMap->GetImage()->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + + // return new index of shadow map + return static_cast(shadowMapImageSamplers.size()) - 1u; + } + + void SHLightingSubSystem::PrepareShadowMapsForRead(Handle cmdBuffer) noexcept + { + // Issue barrier to transition shadow maps for reading in compute shader + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, shadowMapMemoryBarriers); + } + + //void SHLightingSubSystem::HandleResize(Handle compute) noexcept + //{ + // uint32_t const NUM_SHADOW_MAPS = static_cast(shadowMaps.size()); + // for (uint32_t i = 0; i < NUM_SHADOW_MAPS; ++i) + // { + // // Just use the image view stored in the resource + // Handle const NEW_IMAGE_VIEW = shadowMaps[i]->GetImageView(); + + // // set new image view + // std::get>(shadowMapImageSamplers[i]) = NEW_IMAGE_VIEW; + + // // Set image for barrier + // shadowMapMemoryBarriers[i].image = shadowMaps[i]->GetImage()->GetVkImage(); + // } + + // if (NUM_SHADOW_MAPS > 0) + // { + // // modify descriptors in render graph node compute + // compute->ModifyWriteDescImageComputeResource (SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, shadowMapImageSamplers); + // } + //} + Handle SHLightingSubSystem::GetLightDataDescriptorSet(void) const noexcept { return lightingDataDescSet; } + std::tuple, Handle, vk::ImageLayout> const& SHLightingSubSystem::GetViewSamplerLayout(uint32_t index) const noexcept + { + return shadowMapImageSamplers[index]; + } + + uint32_t SHLightingSubSystem::GetNumShadowMaps(void) const noexcept + { + return static_cast(shadowMaps.size()); + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h index fa103136..7794a2fb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h @@ -3,9 +3,13 @@ #include "Resource/SHHandle.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" +#include "Math/SHMatrix.h" #include "SHLightData.h" #include #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/RenderGraph/SHRenderGraphResource.h" +#include "ECS_Base/SHECSMacros.h" + namespace SHADE { @@ -16,6 +20,10 @@ namespace SHADE class SHVkBuffer; class SHLightComponent; class SHVkCommandBuffer; + class SHSamplerCache; + class SHVkImageView; + class SHVkSampler; + class SHRenderGraphNodeCompute; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. struct SHDirectionalLightData @@ -34,6 +42,12 @@ namespace SHADE //! Diffuse color emitted by the light alignas (16) SHVec4 diffuseColor; + //! Matrix for world to projection from light's perspective + SHMatrix pvMatrix; + + //! Represents boolean for casting shadows in first byte and shadow map index in the other 3. + uint32_t shadowData; + }; // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. @@ -52,24 +66,27 @@ namespace SHADE //! when a fragment is being evaluated, the shader will use the fragment's //! layer value to AND with the light's. If result is 1, do lighting calculations. uint32_t cullingMask; - - }; class SH_API SHLightingSubSystem { public: using DynamicOffsetArray = std::array, static_cast(SHGraphicsConstants::NUM_FRAME_BUFFERS)>; - + static constexpr uint32_t MAX_SHADOWS = 200; + static constexpr uint32_t SHADOW_MAP_WIDTH = 1024; + static constexpr uint32_t SHADOW_MAP_HEIGHT = 1024; private: class PerTypeData { + public: + + private: /*-----------------------------------------------------------------------*/ /* STATIC MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - static constexpr uint32_t STARTING_NUM_LIGHTS = 50; + static constexpr uint32_t STARTING_NUM_LIGHTS = 50; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -123,51 +140,90 @@ namespace SHADE }; private: + /*-----------------------------------------------------------------------*/ + /* STATIC MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + //! logical device used for creation - Handle logicalDevice; + Handle logicalDevice; //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required. - Handle lightingDataDescSet; - - //! Each type will have some data associated with it for processing - std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; - - //! Container to store dynamic offsets for binding descriptor sets - DynamicOffsetArray dynamicOffsets; - - //! holds the data that represents how many lights are in the scene - std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; - - //! GPU buffer to hold lightCountData - Handle lightCountsBuffer; - - //! For padding in the buffer - uint32_t lightCountsAlignedSize; + Handle lightingDataDescSet; + + //! Each type will have some data associated with it for processing + std::array(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData; + + //! Container to store dynamic offsets for binding descriptor sets + DynamicOffsetArray dynamicOffsets; + + //! holds the data that represents how many lights are in the scene + std::array(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData; + + //! GPU buffer to hold lightCountData + Handle lightCountsBuffer; + + //! For padding in the buffer + uint32_t lightCountsAlignedSize; //! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense //! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more, //! don't do anything. //uint32_t numLightComponents; + //! Handle to sampler that all shadow map descriptors will use + Handle shadowMapSampler; + + //! For indexing shadow maps + std::unordered_map shadowMapIndexing; + + //! Shadow maps for every light that casts a shadow Order here doesn't matter. We just want to store it + std::vector> shadowMaps; + + //! Descriptor sets required to be given to the compute shader for shadow calculation. This will be a descriptor array. + //! It will also be preallocated. + //Handle shadowMapDescriptorSet; + + //! Combined image samplers for the texture descriptors + std::vector, Handle, vk::ImageLayout>> shadowMapImageSamplers; + + //! Barriers required to transition the resources from whatever layout they are in (probably from VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + //! to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + std::vector shadowMapMemoryBarriers; + + //! Resource hub from Graphics System + SHResourceHub* resourceHub; + + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ void UpdateDescSet (uint32_t binding) noexcept; void ComputeDynamicOffsets (void) noexcept; void ResetNumLights (void) noexcept; + void UpdateShadowMapDesc (void) noexcept; + SHMatrix GetViewMatrix (SHLightComponent* lightComp) noexcept; public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle device, Handle descPool) noexcept; - void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; - void Exit (void) noexcept; + void Init (Handle device, Handle descPool, SHResourceHub* rh, Handle inShadowMapSampler) noexcept; + void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept; + void Exit (void) noexcept; + void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + uint32_t AddShadowMap (Handle newShadowMap, EntityID lightEntity) noexcept; + void PrepareShadowMapsForRead (Handle cmdBuffer) noexcept; + //void HandleResize (Handle compute) noexcept; + //void RemoveShadowMap (uint32_t index) noexcept; - void BindDescSet (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) noexcept; + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ Handle GetLightDataDescriptorSet (void) const noexcept; + std::tuple, Handle, vk::ImageLayout> const& GetViewSamplerLayout (uint32_t index) const noexcept; + uint32_t GetNumShadowMaps (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp index 444a6630..d5a0073f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp @@ -29,6 +29,7 @@ namespace SHADE SHMeshData SHPrimitiveGenerator::sphereMesh; SHMeshData SHPrimitiveGenerator::lineCubeMesh; SHMeshData SHPrimitiveGenerator::lineCircleMesh; + SHMeshData SHPrimitiveGenerator::lineCapsuleCapMesh; /*-----------------------------------------------------------------------------------*/ /* Primitive Generation Functions */ @@ -392,6 +393,64 @@ namespace SHADE return addMeshDataTo(lineCircleMesh, gfxSystem); } + SHADE::SHMeshData SHPrimitiveGenerator::LineCapsuleCap() noexcept + { + SHMeshData mesh; + + // Have multiple semi-circles for the cap + static constexpr int SPLITS = 36; + static constexpr float ANGLE_INCREMENTS = (std::numbers::pi_v * 2.0f) / static_cast(SPLITS); + + /* X-Axis */ + // Generate points of the circle + for (int i = 0; i <= SPLITS / 2; ++i) + { + const float ANGLE = ANGLE_INCREMENTS * i; + mesh.VertexPositions.emplace_back(cos(ANGLE) * 0.5f, sin(ANGLE) * 0.5f, 0.0f); + } + + // Generate lines of the circle + for (int i = 1; i <= SPLITS / 2; ++i) + { + mesh.Indices.emplace_back(static_cast(i - 1)); + mesh.Indices.emplace_back(static_cast(i)); + } + + /* Z-Axis */ + // Generate points of the circle + for (int i = 0; i <= SPLITS / 2; ++i) + { + const float ANGLE = ANGLE_INCREMENTS * i; + mesh.VertexPositions.emplace_back(0.0f, sin(ANGLE) * 0.5f, cos(ANGLE) * 0.5f); + } + + // Generate lines of the circle + for (int i = 2 + SPLITS / 2; i <= SPLITS + 1; ++i) + { + mesh.Indices.emplace_back(static_cast(i - 1)); + mesh.Indices.emplace_back(static_cast(i)); + } + + mesh.VertexNormals.resize(mesh.VertexPositions.size()); + mesh.VertexTangents.resize(mesh.VertexPositions.size()); + mesh.VertexTexCoords.resize(mesh.VertexPositions.size()); + + return mesh; + } + Handle SHPrimitiveGenerator::LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept + { + if (lineCapsuleCapMesh.VertexPositions.empty()) + lineCapsuleCapMesh = LineCapsuleCap(); + + return addMeshDataTo(lineCapsuleCapMesh, meshLibrary); + } + Handle SHPrimitiveGenerator::LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept + { + if (lineCapsuleCapMesh.VertexPositions.empty()) + lineCapsuleCapMesh = LineCapsuleCap(); + + return addMeshDataTo(lineCapsuleCapMesh, gfxSystem); + } /*-----------------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h index 9bcd2f3c..839d0ef6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h @@ -194,6 +194,46 @@ namespace SHADE */ /***********************************************************************************/ [[nodiscard]] static Handle LineCircle(SHGraphicsSystem& gfxSystem) noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a cap of a wireframe capsule that is comprised only of lines and + store the data in a SHMeshData object. + + \return + SHMeshData object containing vertex data for the line circle. + */ + /***********************************************************************************/ + [[nodiscard]] static SHMeshData LineCapsuleCap() noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a cap of a wireframe capsule that is comprised only of lines and + constructs a SHMesh using the SHGraphicsSystem provided. + + \param meshLibrary + Reference to the SHMeshLibrary to produce and store a line circle mesh in. + + \return + SHMesh object that points to the generated line circle mesh in the SHMeshLibrary. + */ + /***********************************************************************************/ + [[nodiscard]] static Handle LineCapsuleCap(SHMeshLibrary& meshLibrary) noexcept; + /***********************************************************************************/ + /*! + \brief + Produces a cap of a wireframe capsule that is comprised only of lines and + constructs a SHMesh using the SHGraphicsSystem provided. + + \param gfxSystem + Reference to the SHGraphicsSystem to produce and store a line circle mesh in. + + \return + SHMesh object that points to the generated line circle mesh in the + SHGraphicsSystem. + */ + /***********************************************************************************/ + [[nodiscard]] static Handle LineCapsuleCap(SHGraphicsSystem& gfxSystem) noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -209,5 +249,6 @@ namespace SHADE static SHMeshData sphereMesh; static SHMeshData lineCubeMesh; static SHMeshData lineCircleMesh; + static SHMeshData lineCapsuleCapMesh; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index baf09a2d..74795034 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -1,18 +1,23 @@ #include "SHpch.h" #include "SHPipelineLibrary.h" #include "Graphics/Devices/SHVkLogicalDevice.h" -#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" #include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/SHVkUtil.h" namespace SHADE { - Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept { + std::vector> modules{}; + if (vsFsPair.first) + modules.push_back(vsFsPair.first); + if (vsFsPair.second) + modules.push_back(vsFsPair.second); + SHPipelineLayoutParams params { - .shaderModules = {vsFsPair.first, vsFsPair.second}, + .shaderModules = std::move(modules), .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts }; @@ -21,7 +26,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsPredefinedData::GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(viState); SHColorBlendState colorBlendState{}; colorBlendState.logic_op_enable = VK_FALSE; @@ -30,6 +35,7 @@ namespace SHADE auto const& subpassColorReferences = subpass->GetColorAttachmentReferences(); colorBlendState.attachments.reserve(subpassColorReferences.size()); + for (auto& att : subpassColorReferences) { colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState @@ -47,6 +53,8 @@ namespace SHADE } newPipeline->GetPipelineState().SetColorBlenState(colorBlendState); + + newPipeline->GetPipelineState().SetRasterizationState(rasterState); // Actually construct the pipeline newPipeline->ConstructPipeline(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index 5085f21f..ca46c71a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -3,6 +3,7 @@ #include #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" namespace SHADE { @@ -32,7 +33,9 @@ namespace SHADE Handle CreateGraphicsPipelines ( std::pair, Handle> const& vsFsPair, Handle renderpass, - Handle subpass + Handle subpass, + SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(), + SHRasterizationState const& rasterState = SHRasterizationState{} ) noexcept; Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp index c7ada11f..30d81d89 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp @@ -195,7 +195,7 @@ namespace SHADE return *this; } - void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept + void SHVertexInputState::AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding /*= static_cast(-1)*/, uint32_t fixedAttributeLocation/* = static_cast(-1)*/) noexcept { // add a binding and get ref to it bindings.emplace_back(); @@ -210,7 +210,7 @@ namespace SHADE // Offset is 0 at first (for first element) uint32_t offset = 0; - binding.binding = static_cast(bindings.size() - 1); + binding.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); // for every attribute passed in for (auto const& attrib : inAttribs) @@ -226,10 +226,11 @@ namespace SHADE auto& vertexAttrib = attributes.back(); // The binding for that attribute description is index of the new binding created earlier in this function - vertexAttrib.binding = static_cast(bindings.size() - 1); + vertexAttrib.binding = (fixedBinding != static_cast(-1)) ? fixedBinding : static_cast(bindings.size() - 1); - // Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously - vertexAttrib.location = static_cast(attributes.size () - 1); + //Attribute location. New index is simply + 1 of the previous. Starts from 0 obviously + vertexAttrib.location = (fixedAttributeLocation != static_cast(-1)) ? fixedAttributeLocation + i : static_cast(attributes.size () - 1); + //vertexAttrib.location = static_cast(attributes.size() - 1); // Get the vkFormat associated with the SHAttribFormat vertexAttrib.format = format; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h index 4c8d679a..73eb1ef5 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.h @@ -34,7 +34,7 @@ namespace SHADE SHVertexInputState& operator= (SHVertexInputState const& rhs) noexcept; SHVertexInputState& operator= (SHVertexInputState&& rhs) noexcept; - void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs) noexcept; + void AddBinding(bool instanced, bool calcOffset, std::initializer_list inAttribs, uint32_t fixedBinding = static_cast(-1), uint32_t fixedAttributeLocation = static_cast(-1)) noexcept; friend class SHVkPipelineState; friend class SHVkPipeline; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index c2d83052..6a6ef879 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -19,69 +19,71 @@ namespace SHADE for (auto& shaderModule : shaderModules) { - // References for convenience - auto const& reflectedData = shaderModule->GetReflectedData(); - auto const& pcInfo = reflectedData.GetPushConstantInfo(); - - // If a push constant block exists for the shader module - if (pcInfo.memberCount != 0) + if (shaderModule) { - bool exists = false; + // References for convenience + auto const& reflectedData = shaderModule->GetReflectedData(); + auto const& pcInfo = reflectedData.GetPushConstantInfo(); - // Check if push constant block already exists - for (uint32_t i = 0; i < pcInfos.size(); ++i) + // If a push constant block exists for the shader module + if (pcInfo.memberCount != 0) { - // If there is a block with the same name, member count and size - if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + bool exists = false; + + // Check if push constant block already exists + for (uint32_t i = 0; i < pcInfos.size(); ++i) { - // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages - vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); + // If there is a block with the same name, member count and size + if (std::strcmp(pcInfos[i]->name, pcInfo.name) == 0 && pcInfos[i]->memberCount == pcInfo.memberCount && pcInfos[i]->size == pcInfo.size) + { + // We just take the existing pc range we built earlier, and allow it to be accessed in potentially other shader stages + vkPcRanges[i].stageFlags |= shaderModule->GetShaderStageFlagBits(); - // Set flag and stop checking - exists = true; - break; - } - } - - // If the block doesn't exist yet - if (!exists) - { - // Loop through all member variables of the new push constant block - for (uint32_t i = 0; i < pcInfo.memberCount; ++i) - { - std::string variableName; - variableName.reserve(50); - variableName += pcInfo.name; - variableName += "."; - variableName += pcInfo.members[i].name; - - // Add the variable's offset info to the interface - pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + // Set flag and stop checking + exists = true; + break; + } } - // New push constant range - vk::PushConstantRange newRange; + // If the block doesn't exist yet + if (!exists) + { + // Loop through all member variables of the new push constant block + for (uint32_t i = 0; i < pcInfo.memberCount; ++i) + { + std::string variableName; + variableName.reserve(50); + variableName += pcInfo.name; + variableName += "."; + variableName += pcInfo.members[i].name; - // set offset and size - newRange.offset = startOffset; - newRange.size = pcInfo.size; + // Add the variable's offset info to the interface + pushConstantInterface.AddOffset(std::move(variableName), startOffset + pcInfo.members[i].offset); + } - // Stage flags will be whatever shader stage of the shader that contains the push constant block - newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); + // New push constant range + vk::PushConstantRange newRange; - // Add to the list foe checking later - pcInfos.push_back(&pcInfo); + // set offset and size + newRange.offset = startOffset; + newRange.size = pcInfo.size; - // For pipeline layout to consume - vkPcRanges.push_back(newRange); + // Stage flags will be whatever shader stage of the shader that contains the push constant block + newRange.stageFlags = shaderModule->GetShaderStageFlagBits(); - // Next push constant block will start next to the previous push constant block - startOffset += pcInfo.size; + // Add to the list foe checking later + pcInfos.push_back(&pcInfo); + + // For pipeline layout to consume + vkPcRanges.push_back(newRange); + + // Next push constant block will start next to the previous push constant block + startOffset += pcInfo.size; + } + + stageFlags |= shaderModule->GetShaderStageFlagBits(); } - - stageFlags |= shaderModule->GetShaderStageFlagBits(); } - } // After all the sizes of the push constant blocks have been added, record the size in the interface @@ -132,6 +134,9 @@ namespace SHADE //! Now we take descriptor set info from all shaders and prepare some bindings for the descriptor set for (auto& shaderModule : shaderModules) { + if (!shaderModule) + continue; + auto const& descBindingInfo = shaderModule->GetReflectedData().GetDescriptorBindingInfo(); auto const& reflectedSets = descBindingInfo.GetReflectedSets(); @@ -200,10 +205,12 @@ namespace SHADE newBinding.DescriptorCount = SHVkDescriptorSetLayout::Binding::VARIABLE_DESCRIPTOR_UPPER_BOUND; // Set the flags for variable bindings - newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount; + newBinding.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound; } else + { SHLOG_ERROR("Variable size binding is detected, but the binding is not the last binding of the set and is therefore invalid. "); + } } setsWithBindings[CURRENT_SET].emplace_back(newBinding); @@ -326,11 +333,10 @@ namespace SHADE { for (auto& mod : shaderModules) { - mod->AddCallback([this]() - { - RecreateIfNeeded(); - } - ); + if (mod) + { + mod->AddCallback([this]() { RecreateIfNeeded(); }); + } } RecreateIfNeeded (); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 74371a64..74ea951a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -54,7 +54,7 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) + void SHRenderGraph::AddResource(std::string resourceName, std::initializer_list typeFlags, bool resizeWithWindow, uint32_t w /*= static_cast(-1)*/, uint32_t h /*= static_cast(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageUsageFlagBits usageFlags/* = {}*/, vk::ImageCreateFlagBits createFlags /*= {}*/) { // If we set to if (w == static_cast(-1) && h == static_cast(-1)) @@ -64,7 +64,7 @@ namespace SHADE format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags); + auto resource = renderGraphStorage->resourceHub->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags, resizeWithWindow); renderGraphStorage->graphResources->try_emplace(resourceName, resource); } @@ -106,6 +106,9 @@ namespace SHADE for (auto& affectedNode : affectedNodes) nodes[affectedNode]->CreateFramebuffer(); + + renderGraphStorage->graphResources->at(resourceName).Free(); + renderGraphStorage->graphResources->erase (resourceName); /* * IMPORTANT NOTES * @@ -166,68 +169,7 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is final layout. - std::unordered_map resourceAttFinalLayouts; - if (node->subpasses.empty()) - { - SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); - return; - } - - // We first want to take all resources track their layout as undefined at the start of the node/renderpass - auto const resources = node->GetResources(); - for (auto& resource : resources) - { - resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined); - } - - // attempt to get all final layouts for all resources - for (auto& subpass : node->subpasses) - { - for (auto& color : subpass->colorReferences) - { - // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass - if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) - resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; - else - resourceAttFinalLayouts[color.attachment] = color.layout; - - node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout); - } - - for (auto& depth : subpass->depthReferences) - { - resourceAttFinalLayouts[depth.attachment] = depth.layout; - node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout); - } - - for (auto& input : subpass->inputReferences) - { - resourceAttFinalLayouts[input.attachment] = input.layout; - node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout); - } - } - - for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) - { - auto& att = node->attachmentDescriptions[j]; - auto& resource = node->attResources[j]; - - // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. - // We also want to load the attachment, not "don't care". - if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && - renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) - { - att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at (resource.GetId().Raw); - att.loadOp = vk::AttachmentLoadOp::eLoad; - att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; - } - else - att.initialLayout = vk::ImageLayout::eUndefined; - - att.finalLayout = resourceAttFinalLayouts[j]; - resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout); - } + node->StandaloneConfigureAttDesc(i == nodes.size() - 1); ++i; } @@ -333,6 +275,17 @@ namespace SHADE } } + void SHRenderGraph::ReindexNodes(void) noexcept + { + nodeIndexing.clear(); + uint32_t i = 0; + for (auto& node : nodes) + { + nodeIndexing.emplace (node->name, i); + ++i; + } + } + /***************************************************************************/ /*! @@ -473,6 +426,65 @@ namespace SHADE return node; } + /***************************************************************************/ + /*! + + \brief + This function is purely used for dynamic nodes (if such a thing were to + exist in our architecture). In other words, don't use this function unless + the new node is fully standalone and does not rely or is a prereq of + other nodes. + + \param nodeName + Name of new node + + \param resourceInstruction + Resources for the node + + \param nodeToAddAfter + The node to add the new node after. + + \return + + */ + /***************************************************************************/ + Handle SHRenderGraph::AddNodeAfter(std::string nodeName, std::initializer_list resourceInstruction, std::string nodeToAddAfter) noexcept + { + if (nodeIndexing.contains(nodeName)) + { + SHLOG_ERROR("Node already exists, cannot add node. "); + return {}; + } + + std::vector descInitParams; + for (auto const& instruction : resourceInstruction) + { + // If the resource that the new node is requesting for exists, allow the graph to reference it + if (renderGraphStorage->graphResources->contains(instruction.resourceName)) + { + descInitParams.push_back( + { + .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName), + .dontClearOnLoad = instruction.dontClearOnLoad, + } + ); + } + else + { + SHLOG_ERROR("Resource doesn't exist in graph yet. Cannot create new node."); + return{}; + } + } + + // get target node + auto targetNode = nodes.begin() + nodeIndexing.at(nodeToAddAfter); + + auto node = nodes.insert(targetNode, renderGraphStorage->resourceHub->Create(nodeName, renderGraphStorage, std::move(descInitParams), std::vector>())); + ReindexNodes (); + return *node; + + } + void SHRenderGraph::AddRenderToSwapchainNode(std::string toSwapchainResource, std::string swapchainResource, std::initializer_list predecessorNodes, std::pair, Handle> shaderModules) noexcept { for (auto& node : predecessorNodes) @@ -532,10 +544,6 @@ namespace SHADE ConfigureSubSystems(); } - void SHRenderGraph::Regenerate(void) noexcept - { - - } /***************************************************************************/ /*! @@ -572,10 +580,13 @@ namespace SHADE for (auto& node : nodes) { - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + if (node->renderpass) + { + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(cmdBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - node->Execute(cmdBuffer, descPool, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); + } } cmdBuffer->EndLabeledSegment(); @@ -605,8 +616,11 @@ namespace SHADE // resize resources for (auto& [name, resource] : *renderGraphStorage->graphResources) { - if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) - resource->HandleResize(newWidth, newHeight); + if (resource->resizeWithWindow) + { + if (!renderGraphStorage->nonOwningResourceInitialLayouts.contains (resource.GetId().Raw)) + resource->HandleResize(newWidth, newHeight); + } } for (auto& node : nodes) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index c7fe221b..5abcd6b6 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -55,6 +55,7 @@ namespace SHADE void ConfigureRenderpasses (void) noexcept; void ConfigureSubSystems (void) noexcept; void ConfigureFramebuffers (void) noexcept; + void ReindexNodes (void) noexcept; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -101,6 +102,7 @@ namespace SHADE ( std::string resourceName, std::initializer_list typeFlags, + bool resizeWithWindow = true, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, @@ -123,6 +125,12 @@ namespace SHADE std::initializer_list resourceInstruction, std::initializer_list predecessorNodes ) noexcept; + Handle AddNodeAfter + ( + std::string nodeName, + std::initializer_list resourceInstruction, + std::string nodeToAddAfter + ) noexcept; void AddRenderToSwapchainNode ( @@ -134,7 +142,6 @@ namespace SHADE ) noexcept; void Generate (void) noexcept; - void Regenerate (void) noexcept; void CheckForNodeComputes (void) noexcept; void Execute (uint32_t frameIndex, Handle descPool) noexcept; void Begin (uint32_t frameIndex) noexcept; @@ -165,7 +172,14 @@ namespace SHADE * that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph, * but different matrices (SHRenderer) can be used in different nodes. * - There are also way too many hash maps created for ease of access. This definitely can be cut down. - * - + * - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted + * for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses + * while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other + * than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as + * whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later + * be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as + * if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any + * other node. * */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 3c412645..ff540ce1 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -32,8 +32,11 @@ namespace SHADE renderpass.Free(); } - renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + if (!spDescs.empty()) + { + renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); + } } /***************************************************************************/ @@ -46,91 +49,105 @@ namespace SHADE /***************************************************************************/ void SHRenderGraphNode::CreateFramebuffer(void) noexcept { - if (!framebuffers.empty()) + if (renderpass) { - for (auto fbo : framebuffers) + if (!framebuffers.empty()) { - if (fbo) - fbo.Free(); - } - } - - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (auto fbo : framebuffers) + { + if (fbo) + fbo.Free(); + } } + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eFramebuffer, framebuffers[i]->GetVkFramebuffer(), "[Framebuffer] " + name + std::to_string(i)); + } } } void SHRenderGraphNode::HandleResize(void) noexcept { - renderpass->HandleResize(); - - for (uint32_t i = 0; i < framebuffers.size(); ++i) + if (renderpass) { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); + renderpass->HandleResize(); - for (uint32_t j = 0; j < attResources.size(); ++j) + for (uint32_t i = 0; i < framebuffers.size(); ++i) { - uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } - framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); - } + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } - for (auto& subpass : subpasses) - { - subpass->HandleResize(); - } - - for (auto& nodeCompute : nodeComputes) - { - nodeCompute->HandleResize(); + for (auto& nodeCompute : nodeComputes) + { + nodeCompute->HandleResize(); + } } } void SHRenderGraphNode::ConfigureSubpasses(void) noexcept { + if (subpasses.empty()) + return; + + uint32_t numValidSubpasses = std::count_if(subpasses.begin(), subpasses.end(), [](Handle subpass) {return !subpass->HasNoAttachments();}); + // Create subpass description and dependencies based on number of subpasses - spDescs.resize(subpasses.size()); - spDeps.resize(subpasses.size()); + spDescs.resize(numValidSubpasses); + spDeps.resize(numValidSubpasses); // Now we want to loop through all attachments in all subpasses in the node and query // the resources being used. For each resource we want to query the type and record it // in bit fields (1 bit for each subpass). uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0; - uint32_t i = 0; // For all subpasses (see above description about bit field for this). - for (auto& subpass : subpasses) + for (uint32_t i = 0; auto& subpass : subpasses) { + // skip if subpass is not valid + if (subpass->HasNoAttachments()) + continue; + // Configure subpass description auto& desc = spDescs[i]; desc.pColorAttachments = subpass->colorReferences.data(); @@ -186,8 +203,11 @@ namespace SHADE // Loop through all subpasses again but this time we use the bit field to initialize // the dependencies. - for (i = 0; i < subpasses.size(); ++i) + for (uint32_t i = 0; auto & subpass : subpasses) { + if (subpass->HasNoAttachments()) + continue; + vk::PipelineStageFlags srcStage; vk::PipelineStageFlags dstStage; vk::AccessFlags srcAccess; @@ -245,6 +265,8 @@ namespace SHADE // initialize input descriptors subpasses[i]->CreateInputDescriptors(); + + ++i; } } @@ -343,6 +365,7 @@ namespace SHADE , spDeps{ std::move(rhs.spDeps) } , nodeComputes{ std::move(rhs.nodeComputes) } , name { std::move(rhs.name) } + , ISelfHandle{std::move(rhs)} { rhs.renderpass = {}; @@ -419,7 +442,7 @@ namespace SHADE return subpass; } - Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept + Handle SHRenderGraphNode::AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings, uint32_t variableDescCount/* = 0*/, float numWorkGroupScale/* = 1.0f*/) noexcept { // Look for the required resources in the graph std::vector> nodeComputeResources{}; @@ -435,7 +458,7 @@ namespace SHADE std::vector> temp (nodeComputeResources); // Create the subpass compute with the resources - auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty()); + auto nodeCompute = graphStorage->resourceHub->Create(std::move(nodeName), graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty(), variableDescCount); nodeComputes.push_back(nodeCompute); for (auto& resource : temp) @@ -483,6 +506,68 @@ namespace SHADE } } + void SHRenderGraphNode::StandaloneConfigureAttDesc(bool isLastNode) noexcept + { + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; + if (!subpasses.empty()) + { + // We first want to take all resources track their layout as undefined at the start of the node/renderpass + for (auto& resource : attResources) + { + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, vk::ImageLayout::eUndefined); + } + + // attempt to get all final layouts for all resources + for (auto& subpass : subpasses) + { + for (auto& color : subpass->colorReferences) + { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass + if (isLastNode && (attResources[color.attachment]->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))) + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + else + resourceAttFinalLayouts[color.attachment] = color.layout; + + attResources[color.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, color.layout); + } + + for (auto& depth : subpass->depthReferences) + { + resourceAttFinalLayouts[depth.attachment] = depth.layout; + attResources[depth.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, depth.layout); + } + + for (auto& input : subpass->inputReferences) + { + resourceAttFinalLayouts[input.attachment] = input.layout; + attResources[input.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, input.layout); + } + } + + for (uint32_t j = 0; j < attachmentDescriptions.size(); ++j) + { + auto& att = attachmentDescriptions[j]; + auto& resource = attResources[j]; + + // If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource. + // We also want to load the attachment, not "don't care". + if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) && + graphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw)) + { + att.initialLayout = graphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw); + att.loadOp = vk::AttachmentLoadOp::eLoad; + att.stencilLoadOp = vk::AttachmentLoadOp::eLoad; + } + else + att.initialLayout = vk::ImageLayout::eUndefined; + + att.finalLayout = resourceAttFinalLayouts[j]; + resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, att.finalLayout); + } + } + } + /***************************************************************************/ /*! @@ -509,14 +594,14 @@ namespace SHADE // remove attachment reference attachmentDescriptions.erase (attachmentDescriptions.begin() + index); + // erase from mapping as well + resourceAttachmentMapping->erase(resourceHandleID); + // Remove footprint of attachment from all subpasses as well for (auto it = subpasses.begin(); it != subpasses.end(); ++it) { - // attempt to detach resource from subpass - (*it)->DetachResource(resourceName, index); - - // If the subpass ends up having no attachments after, erase it from the node - if ((*it)->HasNoAttachments()) + // If the subpass uses the resource, just remove the subpass since the subpass will be invalid + if ((*it)->UsesResource(index)) { // erase from indexing subpassIndexing.erase((*it)->GetName()); @@ -530,6 +615,24 @@ namespace SHADE for (uint32_t i = 0; i < subpasses.size(); ++i) subpasses[i]->SetIndex(i); + // remove node computes using the resource + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if ((*it)->UsesResource(resourceHandleID)) + { + it = nodeComputes.erase(it); + } + } + + // recompute the barriers for the other computes + for (auto it = nodeComputes.begin(); it != nodeComputes.end(); ++it) + { + if (it == nodeComputes.begin()) + (*it)->SetFollowingEndRenderpass(true); + + (*it)->InitializeBarriers(); + } + return true; } return false; @@ -537,37 +640,40 @@ namespace SHADE void SHRenderGraphNode::Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { - uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) + if (renderpass) { - subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); - // Go to next subpass if not last subpass - if (i != static_cast(subpasses.size()) - 1u) - commandBuffer->NextSubpass(); + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + + // Go to next subpass if not last subpass + if (i != static_cast(subpasses.size()) - 1u && !subpasses[i]->HasNoAttachments()) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); + + // We bind these 2 descriptor sets here because they apply to all node computes + if (!nodeComputes.empty()) + { + commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); + + // bind static global data + SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); + + // bind lighting data + SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); + } + + // Execute all subpass computes + for (auto& sbCompute : nodeComputes) + sbCompute->Execute(commandBuffer, frameIndex); } - - commandBuffer->EndRenderpass(); - - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE); - - // We bind these 2 descriptor sets here because they apply to all node computes - if (!nodeComputes.empty()) - { - commandBuffer->ForceSetPipelineLayout(SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::RENDER_GRAPH_NODE_COMPUTE).dummyPipelineLayout, SH_PIPELINE_TYPE::COMPUTE); - - // bind static global data - SHGlobalDescriptorSets::BindStaticGlobalData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::STATIC_DATA)); - - // bind lighting data - SHGlobalDescriptorSets::BindLightingData(commandBuffer, SH_PIPELINE_TYPE::COMPUTE, descMappings.at(SHPredefinedDescriptorTypes::LIGHTS), frameIndex); - } - - // Execute all subpass computes - for (auto& sbCompute : nodeComputes) - sbCompute->Execute(commandBuffer, frameIndex); } Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept @@ -599,6 +705,77 @@ namespace SHADE batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); } + /***************************************************************************/ + /*! + + \brief + This function simply appends to the container of VkAttachmentDescription + and attResources. It will assume the resource is used standalone in the + node and will not account for its usage in other nodes. As such its + initialLayout will always be UNDEFINED and its finalLayout will be + whatever is calculated if the node is regenerated using + StandaloneRegnerate. This function also does not affect the render graph + while its running since the 2 containers above have already been copied + to the GPU. + + \param resourceName + The name of the resource for getting the resource. + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeLinkResource(std::string resourceName) noexcept + { + // Get new resource + Handle newResource = graphStorage->graphResources->at(resourceName); + + // append new resource to container + attResources.push_back(newResource); + + attachmentDescriptions.push_back(vk::AttachmentDescription + { + .format = newResource->GetResourceFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eClear, + .stencilStoreOp = vk::AttachmentStoreOp::eStore, + }); + + resourceAttachmentMapping->try_emplace(newResource.GetId().Raw, attachmentDescriptions.size() - 1); + } + + Handle SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept + { + return AddSubpass(std::move (subpassName), viewport, renderer); + } + + /***************************************************************************/ + /*! + + \brief + USE WITH CAUTION because the function does not reevaluate resource + layouts in attachment descriptions. All resources here will start at + UNDEFINED and end at whatever the last subpass using the attachment + specifies. It will also not support render graph node computes given its + complexity if it has to be accounted for. + + IN SHORT, IT GENERATES A RENDERPASS AS IF ITS THE ONLY NODE + IN THE RENDER GRAPH. SEE NOTES IN SHRenderGraph.h + + This function is mainly meant for nodes that are dynamic (in hindsight, + there really should have been a distinction between static and dynamic + nodes). + + */ + /***************************************************************************/ + void SHRenderGraphNode::RuntimeStandaloneRegenerate(void) noexcept + { + StandaloneConfigureAttDesc(false); + ConfigureSubpasses(); + CreateRenderpass(); + CreateFramebuffer(); + } + /***************************************************************************/ /*! @@ -633,4 +810,15 @@ namespace SHADE return attResources; } + Handle SHRenderGraphNode::GetNodeCompute(std::string nodeComputeName) const noexcept + { + for (auto nc : nodeComputes) + { + if (nc->name == nodeComputeName) + return nc; + } + + return {}; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index a581d21c..b070b8fa 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -93,6 +93,9 @@ namespace SHADE void CreateFramebuffer(void) noexcept; void HandleResize (void) noexcept; void ConfigureSubpasses (void) noexcept; + bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept; + void AddDummySubpassIfNeeded(void) noexcept; + void StandaloneConfigureAttDesc (bool isLastNode) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -105,15 +108,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; - Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; - void AddDummySubpassIfNeeded (void) noexcept; - bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept; + Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; + + void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); - // TODO: RemoveSubpass() - void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex, Handle descPool); + // Runtime functions that don't affect the renderpass + void RuntimeLinkResource(std::string resourceName) noexcept; + Handle RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + void RuntimeStandaloneRegenerate (void) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ @@ -122,6 +127,7 @@ namespace SHADE Handle GetSubpass(std::string_view subpassName) const noexcept; Handle GetResource (uint32_t resourceIndex) const noexcept; std::vector> const& GetResources (void) const noexcept; + Handle GetNodeCompute (std::string nodeComputeName) const noexcept; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp index cfc8443c..ef1b6b03 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -14,7 +14,56 @@ namespace SHADE { - SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept + + bool SHRenderGraphNodeCompute::UsesResource(uint64_t resourceHandleID) const noexcept + { + for (auto& resource : resources) + { + if (resource.GetId().Raw == resourceHandleID) + return true; + } + return false; + } + + void SHRenderGraphNodeCompute::InitializeBarriers(void) noexcept + { + for (uint32_t i = 0; auto & barriers : memoryBarriers) + { + barriers.clear(); + + for (auto& resource : resources) + { + vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); + barriers.push_back(vk::ImageMemoryBarrier + { + .srcAccessMask = srcAccessMask, + .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, + .oldLayout = vk::ImageLayout::eGeneral, + .newLayout = vk::ImageLayout::eGeneral, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), + .subresourceRange = vk::ImageSubresourceRange + { + .aspectMask = resource->imageAspectFlags, + .baseMipLevel = 0, + .levelCount = resource->mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + } + }); + } + ++i; + } + } + + void SHRenderGraphNodeCompute::SetFollowingEndRenderpass(uint32_t flag) noexcept + { + followingEndRenderpass = flag; + } + + + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale/* = 1.0f*/) noexcept : computePipeline{} , pipelineLayout{} , resources{} @@ -68,10 +117,12 @@ namespace SHADE // check if all layouts are there if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) { + Handle computeResourceLayout = {}; + computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; + // create compute resources computeResource = graphStorage->resourceHub->Create(); - auto computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; - computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 }); + computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, {variableDescCount}); #ifdef _DEBUG for (auto set : computeResource->descSet->GetVkHandle()) SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eDescriptorSet, set, "[Descriptor Set] " + name + " Resources"); @@ -91,6 +142,11 @@ namespace SHADE void SHRenderGraphNodeCompute::Execute(Handle cmdBuffer, uint32_t frameIndex) noexcept { + for (auto& fn : preComputeFunctions) + { + fn (cmdBuffer, frameIndex); + } + // bind the compute pipeline cmdBuffer->BindPipeline(computePipeline); @@ -157,35 +213,7 @@ namespace SHADE groupSizeX = maxWidth / workGroupSizeX; groupSizeY = maxHeight / workGroupSizeY; - for (uint32_t i = 0; auto& barriers : memoryBarriers) - { - barriers.clear(); - - for (auto& resource : resources) - { - vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite); - barriers.push_back(vk::ImageMemoryBarrier - { - .srcAccessMask = srcAccessMask, - .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, - .oldLayout = vk::ImageLayout::eGeneral, - .newLayout = vk::ImageLayout::eGeneral, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = resource->GetImage((resource->resourceTypeFlags & static_cast(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(), - .subresourceRange = vk::ImageSubresourceRange - { - .aspectMask = resource->imageAspectFlags, - .baseMipLevel = 0, - .levelCount = resource->mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - } - }); - } - - ++i; - } + InitializeBarriers(); } void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span perFrameSizes) noexcept @@ -219,4 +247,17 @@ namespace SHADE } + void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept + { + static constexpr uint32_t COMPUTE_RESOURCE_SET_INDEX = 0; + computeResource->descSet->ModifyWriteDescImage(COMPUTE_RESOURCE_SET_INDEX, binding, viewSamplerLayout, descArrayIndex); + computeResource->descSet->UpdateDescriptorSetImage(COMPUTE_RESOURCE_SET_INDEX, binding, descArrayIndex); + + } + + void SHRenderGraphNodeCompute::AddPreComputeFunction(PreComputeFunction const& fn) noexcept + { + preComputeFunctions.push_back(fn); + } + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h index dc3ca886..83bc5d33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -25,6 +25,10 @@ namespace SHADE class SHRenderGraphNodeCompute { + public: + using PreComputeFunction = std::function, uint32_t)>; + + private: // Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE struct ComputeResource @@ -73,8 +77,23 @@ namespace SHADE //! Name of this node std::string name; + std::vector preComputeFunctions; + + + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource (uint64_t resourceHandleID) const noexcept; + void InitializeBarriers (void) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetFollowingEndRenderpass (uint32_t flag) noexcept; + public: - SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept; + SHRenderGraphNodeCompute(std::string nodeName, Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, std::unordered_set&& dynamicBufferBindings, bool followingEndRP, uint32_t variableDescCount, float inNumWorkGroupScale = 1.0f) noexcept; void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; @@ -84,7 +103,9 @@ namespace SHADE void ModifyWriteDescBufferComputeResource (uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; void ModifyWriteDescImageComputeResource(uint32_t binding, std::span const& viewSamplerLayouts) noexcept; + void ModifyWriteDescImageComputeResource(uint32_t binding, SHVkDescriptorSetGroup::viewSamplerLayout const& viewSamplerLayout, uint32_t descArrayIndex) noexcept; + void AddPreComputeFunction (PreComputeFunction const& fn) noexcept; friend class SHRenderGraph; friend class SHRenderGraphNode; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index 5a34fa04..d0a88e86 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -78,7 +78,7 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } @@ -88,6 +88,7 @@ namespace SHADE , height{ h } , mipLevels{ levels } , resourceName{ name } + , resizeWithWindow { inResizeWithWindow } { // If the resource type is an arbitrary image and not swapchain image if (typeFlags.size() == 1 && *typeFlags.begin() == SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT) @@ -210,6 +211,7 @@ namespace SHADE , imageAspectFlags{ rhs.imageAspectFlags } , graphStorage{rhs.graphStorage} , infoTracker {std::move (rhs.infoTracker)} + , resizeWithWindow{rhs.resizeWithWindow} { } @@ -242,7 +244,8 @@ namespace SHADE mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; graphStorage = rhs.graphStorage; - infoTracker = std::move(infoTracker); + infoTracker = std::move(rhs.infoTracker); + resizeWithWindow = rhs.resizeWithWindow; return *this; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index 7ac2b824..b9fe219e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -96,11 +96,14 @@ namespace SHADE //! For tracking resource states in stages of the render graphs Handle infoTracker; + //! Whether or not to resize (recreate vulkan image) when window resizes + bool resizeWithWindow; + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags, bool inResizeWithWindow) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 3d2b1699..5205b44d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -77,6 +77,7 @@ namespace SHADE , name { rhs.name } , viewport {rhs.viewport} , renderer {rhs.renderer} + , companionSubpass {rhs.companionSubpass} { } @@ -113,6 +114,7 @@ namespace SHADE name = std::move(rhs.name); renderer = rhs.renderer; viewport = rhs.viewport; + companionSubpass = rhs.companionSubpass; return *this; @@ -162,7 +164,7 @@ namespace SHADE switch (attachmentDescriptionType) { case SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; break; case SH_RENDER_GRAPH_RESOURCE_FLAGS::STENCIL: imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; @@ -211,25 +213,38 @@ namespace SHADE { commandBuffer->BeginLabeledSegment(name); - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex, descPool); - - if (viewport) + if (!HasNoAttachments()) { - // set viewport and scissor - uint32_t w = static_cast(viewport->GetWidth()); - uint32_t h = static_cast(viewport->GetHeight()); - commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + if (viewport) + { + // set viewport and scissor + uint32_t w = static_cast(viewport->GetWidth()); + uint32_t h = static_cast(viewport->GetHeight()); + commandBuffer->SetViewportScissor(static_cast(w), static_cast(h), w, h); + } + + auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); + + if (renderer) + renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); + + // If companion subpass is not a valid handle, render super batch normally + if (!companionSubpass.companion) + { + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + } + else + { + // if not bind pipeline for companion and and execute draw command + commandBuffer->BindPipeline(companionSubpass.pipeline); + companionSubpass.companion->superBatch->Draw(commandBuffer, frameIndex, false); + } } - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); - - if (renderer) - renderer->BindDescriptorSet(commandBuffer, SH_PIPELINE_TYPE::GRAPHICS, descMappings.at(SHPredefinedDescriptorTypes::CAMERA), frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - // Draw all the exterior draw calls for (auto& drawCall : exteriorDrawCalls) { @@ -265,43 +280,27 @@ namespace SHADE */ /***************************************************************************/ - void SHSubpass::DetachResource(std::string const& resourceName, uint32_t attachmentIndex) noexcept + bool SHSubpass::UsesResource(uint32_t attachmentIndex) noexcept { for (uint32_t i = 0; i < colorReferences.size(); ++i) { if (colorReferences[i].attachment == attachmentIndex) - { - colorReferences.erase (colorReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < depthReferences.size(); ++i) { if (depthReferences[i].attachment == attachmentIndex) - { - depthReferences.erase(depthReferences.begin() + i); - break; - } + return true; } for (uint32_t i = 0; i < inputReferences.size(); ++i) { if (inputReferences[i].attachment == attachmentIndex) - { - inputReferences.erase(inputReferences.begin() + i); - break; - } + return true; } - for (uint32_t i = 0; i < inputNames.size(); ++i) - { - if (inputNames[i] == resourceName) - { - inputNames.erase(inputNames.begin() + i); - break; - } - } + return false; } bool SHSubpass::HasNoAttachments(void) const noexcept @@ -458,6 +457,12 @@ namespace SHADE subpassIndex = index; } + void SHSubpass::SetCompanionSubpass(Handle companion, Handle pipeline) noexcept + { + companionSubpass.companion = companion; + companionSubpass.pipeline = pipeline; + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 6c582aa6..f84d4dee 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -21,12 +21,23 @@ namespace SHADE class SHVkSampler; class SHRenderer; class SHViewport; + class SHVkPipeline; class SH_API SHSubpass : public ISelfHandle { public: using ExteriorDrawCallFunction = std::function, Handle, uint32_t)>; + // Allows for subpasses to run using a companions data + struct CompanionSubpass + { + // subpass whose data will be borrowed to draw + Handle companion; + + // Pipeline that will be used for all the draw calls from all batches of the companion subpass + Handle pipeline; + }; + private: /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ @@ -94,6 +105,15 @@ namespace SHADE // For identifying subpasses std::string name; + //! Optional component to a companion subpass. If the subpass handle of this object + //! is valid, the subpass will be drawn using this companion's data. + CompanionSubpass companionSubpass; + + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + bool UsesResource(uint32_t attachmentIndex) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -119,7 +139,6 @@ namespace SHADE void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; void HandleResize (void) noexcept; void BindInputDescriptorSets (Handle cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; - void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept; bool HasNoAttachments (void) const noexcept; void Init(SHResourceHub& resourceManager) noexcept; @@ -128,19 +147,24 @@ namespace SHADE void CreateInputDescriptors (void) noexcept; void UpdateWriteDescriptors (void) noexcept; - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ void SetIndex (uint32_t index) noexcept; public: - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch(void) const noexcept; + /*-----------------------------------------------------------------------*/ + /* PUBLIC SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + void SetCompanionSubpass (Handle companion, Handle pipeline) noexcept; + + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; std::vector const& GetColorAttachmentReferences (void) const noexcept; - vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; - const std::string& GetName() const; + vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; + const std::string& GetName() const; friend class SHRenderGraphNode; friend class SHRenderGraph; diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index cec78648..b8f329b9 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -11,6 +11,7 @@ #pragma once #include +#include #include "SHInputManager.h" #include "../Tools/SHException.h" @@ -99,6 +100,161 @@ namespace SHADE } } + //The Binding File format presently goes as such: + /* + * Binding count + * (For each binding:) + * Name + Binding Type Enum + Inverted Bool + Gravity Double + Dead Double + Sensitivity Double + Snap Bool + PositiveKeyCode count + PositiveKeyCodes + NegativeKeyCode count + NegativeKeyCodes + PositiveControllerCode Count + PositiveControllerCodes + NegativeControllerCode Count + NegativeControllerCodes + */ + void SHInputManager::SaveBindings(std::string const& targetFile) noexcept + { + std::ofstream file; + file.open(targetFile); + + //File cannot be written to + if (!file) return; + + //First write the number of bindings + file << bindings.size() << std::endl; + + for (auto& b : bindings) + { + //Name + file << b.first << std::endl; + + //Data + auto& lbd = b.second; + + file << static_cast(lbd.bindingType) << std::endl; + file << static_cast(lbd.inverted) << std::endl; + file << lbd.gravity << std::endl; + file << lbd.dead << std::endl; + file << lbd.sensitivity << std::endl; + file << static_cast(lbd.snap) << std::endl; + + //Bindings + file << lbd.positiveKeyCodes.size() << std::endl; + for (auto kc : lbd.positiveKeyCodes) + file << static_cast(kc) << std::endl; + file << lbd.negativeKeyCodes.size() << std::endl; + for (auto kc : lbd.negativeKeyCodes) + file << static_cast(kc) << std::endl; + file << lbd.positiveControllerCodes.size() << std::endl; + for (auto cc : lbd.positiveControllerCodes) + file << static_cast(cc) << std::endl; + file << lbd.negativeControllerCodes.size() << std::endl; + for (auto cc : lbd.negativeControllerCodes) + file << static_cast(cc) << std::endl; + } + + file.close(); + } + + void SHInputManager::LoadBindings(std::string const& sourceFile) noexcept + { + std::ifstream file; + file.open(sourceFile); + + //Check + if (!file) return; + + //Erase + ClearBindings(); + + //Read + std::string read; + + int count = 0; + std::getline(file, read); + count = std::stoi(read); + + std::string bindingName; + for (int b = 0; b < count; ++b) + { + //Name + std::getline(file, read); + bindingName = read; + AddBinding(bindingName); + + //Type + std::getline(file, read); + SetBindingType(bindingName, static_cast(std::stoi(read))); + + //Inversion + std::getline(file, read); + SetBindingInverted(bindingName, static_cast(std::stoi(read))); + + //Gravity + std::getline(file, read); + SetBindingGravity(bindingName, std::stod(read)); + + //Dead + std::getline(file, read); + SetBindingDead(bindingName, std::stod(read)); + + //Sensitivity + std::getline(file, read); + SetBindingSensitivity(bindingName, std::stod(read)); + + //Snap + std::getline(file, read); + SetBindingSnap(bindingName, static_cast(std::stoi(read))); + + int count = 0; + //Positive Key Codes + std::getline(file, read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + AddBindingPositiveKeyCode(bindingName, static_cast(std::stoi(read))); + } + + //Negative Key Codes + std::getline(file, read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + AddBindingNegativeKeyCode(bindingName, static_cast(std::stoi(read))); + } + + //Positive Controller Codes + std::getline(file, read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + AddBindingPositiveControllerCode(bindingName, static_cast(std::stoi(read))); + } + + //Negative Controller Codes + std::getline(file, read); + count = std::stoi(read); + for (int i = 0; i < count; ++i) + { + std::getline(file, read); + AddBindingNegativeControllerCode(bindingName, static_cast(std::stoi(read))); + } + } + + file.close(); + } + void SHInputManager::UpdateInput(double dt) noexcept { //Keyboard and Mouse Buttons//////////////////////////////////////////////// diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 3f708124..680035c3 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -14,6 +14,7 @@ #include #include #include "../../SHADE_Managed/src/SHpch.h" +#include "../../SHADE_Engine/src/Assets/SHAssetMacros.h" #include "SH_API.h" #pragma comment(lib, "xinput.lib") @@ -681,6 +682,17 @@ namespace SHADE return controllersReleasedTime[controllerNum][static_cast(code)]; } + /*------------------------------------------------------------------------*/ + /* Binding I/O */ + /*------------------------------------------------------------------------*/ + + //Save bindings registered into a file + static void SaveBindings(std::string const& targetFile = std::string(ASSET_ROOT) + "/Bindings.SHConfig") noexcept; + + //Load and register bindings from a file + //If specified file exists, the current list of bindings will be overwritten, so save them somewhere else before loading + static void LoadBindings(std::string const& sourceFile = std::string(ASSET_ROOT) + "/Bindings.SHConfig") noexcept; + /*------------------------------------------------------------------------*/ /* Binding Functions */ /*------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.cpp b/SHADE_Engine/src/Math/Transform/SHTransform.cpp index ef7c5fda..7be2a60c 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransform.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransform.cpp @@ -35,7 +35,17 @@ namespace SHADE : position { pos } , orientation { SHQuaternion::FromEuler(rot) } , scale { scl } - {} + { + ComputeTRS(); + } + + SHTransform::SHTransform(const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl) noexcept + : position { pos } + , orientation { quat } + , scale { scl } + { + ComputeTRS(); + } /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 6cb03195..6af13b17 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -201,6 +201,7 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); @@ -258,6 +259,7 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); return componentIDList; @@ -339,6 +341,7 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.cpp b/SHADE_Engine/src/Tools/SHDebugDraw.cpp index 02eca592..ee040d8b 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.cpp +++ b/SHADE_Engine/src/Tools/SHDebugDraw.cpp @@ -128,6 +128,10 @@ namespace SHADE dbgDrawSys->DrawWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested); } + void SHDebugDraw::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + dbgDrawSys->DrawWireCapsule(position, rotation, height, radius, color, depthTested); + } /*-----------------------------------------------------------------------------------*/ /* Persistent Draw Functions */ /*-----------------------------------------------------------------------------------*/ @@ -216,6 +220,10 @@ namespace SHADE dbgDrawSys->DrawPersistentWireSphere(SHMatrix::Transform(center, SHQuaternion(), scale), color, depthTested); } + void SHDebugDraw::Persistent::WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color, bool depthTested) + { + dbgDrawSys->DrawPersistentWireCapsule(position, rotation, height, radius, color, depthTested); + } void SHDebugDraw::Persistent::ClearDraws() { dbgDrawSys->ClearPersistentDraws(); diff --git a/SHADE_Engine/src/Tools/SHDebugDraw.h b/SHADE_Engine/src/Tools/SHDebugDraw.h index c28b93e6..c775a514 100644 --- a/SHADE_Engine/src/Tools/SHDebugDraw.h +++ b/SHADE_Engine/src/Tools/SHDebugDraw.h @@ -194,6 +194,18 @@ namespace SHADE /// Colour to draw with. /// Whether or not drawn object will be occluded. static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false); + /// + /// Draws the outline of a capsule. + /// This will remain drawn until ClearDraws() is called. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); /*---------------------------------------------------------------------------------*/ /* Persistent Draw Function Class "Folder" */ @@ -366,6 +378,18 @@ namespace SHADE /// Whether or not drawn object will be occluded. static void WireSphere(const SHVec3& center, const SHVec3& scale, const SHVec4& color = SHColour::WHITE, bool depthTested = false); /// + /// Draws the outline of a capsule. + /// This will remain drawn until ClearDraws() is called. + /// + /// Position of the wireframe capsule. + /// Rotation of the capsule. + /// Height of the overall capsule. + /// Radius of the capsule. + /// + /// Colour to draw with. + /// Whether or not drawn object will be occluded. + static void WireCapsule(const SHVec3& position, const SHQuaternion& rotation, float height, float radius, const SHColour& color = SHColour::WHITE, bool depthTested = false); + /// /// Clears any persistent drawn debug primitives. /// static void ClearDraws(); diff --git a/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h b/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h new file mode 100644 index 00000000..35bcdc61 --- /dev/null +++ b/SHADE_Engine/src/UI/Events/SHButtonClickEvent.h @@ -0,0 +1,16 @@ +#pragma once + + +#include "ECS_Base/SHECSMacros.h" + +namespace SHADE +{ + struct SHButtonClickEvent + { + EntityID EID; + // value of the toggle button, default to false if its a button and not a toggle button + bool value{false}; + }; + + +} diff --git a/SHADE_Engine/src/UI/SHButtonComponent.cpp b/SHADE_Engine/src/UI/SHButtonComponent.cpp index 7b275128..8e87b10e 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.cpp +++ b/SHADE_Engine/src/UI/SHButtonComponent.cpp @@ -5,7 +5,7 @@ namespace SHADE { SHButtonComponent::SHButtonComponent() - :size(1.0f), offset(0.0f), isHovered(false), isClicked(false), + :size(1.0f), isHovered(false), isClicked(false), defaultTexture(0), hoveredTexture(0), clickedTexture(0) { } diff --git a/SHADE_Engine/src/UI/SHButtonComponent.h b/SHADE_Engine/src/UI/SHButtonComponent.h index 39790b6a..3aac09e6 100644 --- a/SHADE_Engine/src/UI/SHButtonComponent.h +++ b/SHADE_Engine/src/UI/SHButtonComponent.h @@ -18,7 +18,6 @@ namespace SHADE virtual ~SHButtonComponent() = default; SHVec2 size; - SHVec2 offset; AssetID GetClickedTexture() const noexcept; AssetID GetDefaultTexture() const noexcept; @@ -33,8 +32,10 @@ namespace SHADE friend class SHUISystem; private: - + //Set to true when mouse is hovering over the button. bool isHovered; + //This is set to true when the mouse clicks down, and set back to false when mouse releases. + //The event for the button click will be broadcasted when mouse release. bool isClicked; AssetID defaultTexture; AssetID hoveredTexture; diff --git a/SHADE_Engine/src/UI/SHSliderComponent.cpp b/SHADE_Engine/src/UI/SHSliderComponent.cpp new file mode 100644 index 00000000..56d1d89b --- /dev/null +++ b/SHADE_Engine/src/UI/SHSliderComponent.cpp @@ -0,0 +1,39 @@ +#include "SHpch.h" +#include "SHSliderComponent.h" + +namespace SHADE +{ + SHSliderComponent::SHSliderComponent() + :size(1.0f), isHovered(false), isClicked(false), value(0.0f) + { + + } + + + float SHSliderComponent::GetValue() const noexcept + { + return value; + } + + void SHSliderComponent::SetValue(float value) noexcept + { + this->value = value; + } + + + +} + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Slider Component") + .property("Slider Value", &SHSliderComponent::GetValue, &SHSliderComponent::SetValue) + + ; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHSliderComponent.h b/SHADE_Engine/src/UI/SHSliderComponent.h new file mode 100644 index 00000000..bdc57c7e --- /dev/null +++ b/SHADE_Engine/src/UI/SHSliderComponent.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "SH_API.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec2.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + + class SH_API SHSliderComponent final: public SHComponent + { + public: + SHSliderComponent(); + virtual ~SHSliderComponent() = default; + + SHVec2 size; + + + float GetValue() const noexcept; + + + void SetValue(float value) noexcept; + + + friend class SHUISystem; + private: + + bool isHovered; + bool isClicked; + + float value; + + RTTR_ENABLE() + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp b/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp new file mode 100644 index 00000000..527323ea --- /dev/null +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.cpp @@ -0,0 +1,59 @@ +#include "SHpch.h" +#include "SHToggleButtonComponent.h" + + +namespace SHADE +{ + SHToggleButtonComponent::SHToggleButtonComponent() + :size(1.0f), isHovered(false), isClicked(false), value(false), + defaultTexture(0), toggledTexture(0) + { + } + + AssetID SHToggleButtonComponent::GetDefaultTexture() const noexcept + { + return defaultTexture; + } + + AssetID SHToggleButtonComponent::GetToggledTexture() const noexcept + { + return toggledTexture; + } + + bool SHToggleButtonComponent::GetValue() const noexcept + { + return value; + } + + + void SHToggleButtonComponent::SetDefaultTexture(AssetID texture) noexcept + { + defaultTexture = texture; + } + + void SHToggleButtonComponent::SetToggledTexture(AssetID texture) noexcept + { + toggledTexture = texture; + } + + void SHToggleButtonComponent::SetValue(bool value) noexcept + { + this->value = value; + } + +} + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Toggle Button Component") + .property("Non Toggled Texture", &SHToggleButtonComponent::GetDefaultTexture, &SHToggleButtonComponent::SetDefaultTexture) + .property("Toggled Texture", &SHToggleButtonComponent::GetToggledTexture, &SHToggleButtonComponent::SetToggledTexture) + .property("Value", &SHToggleButtonComponent::GetValue, &SHToggleButtonComponent::SetValue) + ; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHToggleButtonComponent.h b/SHADE_Engine/src/UI/SHToggleButtonComponent.h new file mode 100644 index 00000000..2c77f3ba --- /dev/null +++ b/SHADE_Engine/src/UI/SHToggleButtonComponent.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "SH_API.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec2.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + + class SH_API SHToggleButtonComponent final: public SHComponent + { + public: + SHToggleButtonComponent(); + virtual ~SHToggleButtonComponent() = default; + + SHVec2 size; + + AssetID GetToggledTexture() const noexcept; + AssetID GetDefaultTexture() const noexcept; + bool GetValue() const noexcept; + + + void SetDefaultTexture(AssetID texture) noexcept; + void SetToggledTexture(AssetID texture) noexcept; + void SetValue(bool value) noexcept; + + + + friend class SHUISystem; + private: + + //Set to true when mouse is hovering over the button. + bool isHovered; + //This is set to true when the mouse clicks down, and set back to false when mouse releases. + //The event for the button click will be broadcasted when mouse release. + bool isClicked; + bool value; + AssetID defaultTexture; + AssetID toggledTexture; + + + + RTTR_ENABLE() + }; + + +} \ No newline at end of file diff --git a/SHADE_Engine/src/UI/SHUISystem.cpp b/SHADE_Engine/src/UI/SHUISystem.cpp index 1387bc6b..c75af66f 100644 --- a/SHADE_Engine/src/UI/SHUISystem.cpp +++ b/SHADE_Engine/src/UI/SHUISystem.cpp @@ -9,7 +9,15 @@ #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/SHEditor.h" #include "Resource/SHResourceManager.h" +#include "Assets/SHAssetManager.h" #include "Input/SHInputManager.h" +#include "SHUIComponent.h" +#include "SHButtonComponent.h" +#include "SHToggleButtonComponent.h" +#include "SHSliderComponent.h" +#include "SHCanvasComponent.h" +#include "Events/SHEventManager.hpp" +#include "Events/SHButtonClickEvent.h" namespace SHADE { @@ -103,7 +111,7 @@ namespace SHADE { auto transform = SHComponentManager::GetComponent(comp.GetEID()); if (canvasComp != nullptr) - comp.localToCanvasMatrix = canvasComp->GetMatrix()* transform->GetTRS(); + comp.localToCanvasMatrix = transform->GetTRS() * canvasComp->GetMatrix(); else comp.localToCanvasMatrix = transform->GetTRS(); } @@ -139,77 +147,235 @@ namespace SHADE void SHUISystem::UpdateButtonComponent(SHButtonComponent& comp) noexcept { - if (!SHComponentManager::HasComponent(comp.GetEID()) || !SHComponentManager::HasComponent(comp.GetEID())) + if (!SHComponentManager::HasComponent(comp.GetEID())) + { + return; + } + auto cameraSystem = SHSystemManager::GetSystem(); + auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); + //auto canvasComp = SHComponentManager::GetComponent_s(uiComp->canvasID); + + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f,0.0f, 0.0f,1.0f); + + + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; + SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; + + + SHVec2 mousePos; + SHVec2 windowSize; +#ifdef SHEDITOR + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; + mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; + //mousePos.y = windowSize.y - mousePos.y; + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + mousePos /= windowSize; + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) + + + +#else + + int x, y; + SHInputManager::GetMouseScreenPosition(&x, &y); + mousePos.x = x; + mousePos.y = y; + auto ws = SHSystemManager::GetSystem()->GetWindow()->GetWindowSize(); + windowSize = { ws.first,ws.second }; + mousePos /= windowSize; +#endif + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0)}; + //SHLOG_INFO("TopExtent: {}, {}", topExtent.x, topExtent.y) + + topExtent = CanvasToScreenPoint(topExtent,true); + btmExtent = CanvasToScreenPoint(btmExtent,true); + //SHLOG_INFO("TopExtent: {}, {} Btm Extent: {}, {}", topExtent.x, topExtent.y, btmExtent.x, btmExtent.y) + + + //comp.isClicked = false; + if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x + && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) + { + comp.isHovered = true; + #ifdef SHEDITOR + //if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + } + #else + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + #endif + + //SHLOG_INFO("HOVERED") + } + else + { + comp.isHovered = false; + //SHLOG_INFO("NOT HOVERED") + } + if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = false; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + + if (SHComponentManager::HasComponent(comp.GetEID())) + { + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); + + auto material = renderable->GetModifiableMaterial(); + if(!comp.isHovered && !comp.isClicked) + if (comp.GetDefaultTexture() != 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + else if (comp.isClicked) + { + if (comp.GetClickedTexture() != 0 && SHAssetManager::GetType(comp.GetClickedTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetClickedTexture()); + //SHLOG_INFO("SETTING CLICKED TEXTURE") + } + } + else + { + if (comp.GetHoveredTexture() != 0 && SHAssetManager::GetType(comp.GetHoveredTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetHoveredTexture()); + //SHLOG_INFO("SETTING HOVERED TEXTURE") + } + } + + + + } + } + + + void SHUISystem::UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept + { + if (!SHComponentManager::HasComponent(comp.GetEID())) { return; } auto cameraSystem = SHSystemManager::GetSystem(); auto uiComp = SHComponentManager::GetComponent(comp.GetEID()); - SHVec4 topExtent4 = uiComp->GetMatrix() * SHVec4(-comp.size.x * 0.5f, comp.size.y * 0.5f , 0.0f,1.0f); - SHVec4 btmExtent4 = uiComp->GetMatrix() * SHVec4(comp.size.x * 0.5f , -comp.size.y * 0.5f , 0.0f, 1.0f); + SHVec4 topExtent4 = SHMatrix::Translate(-comp.size.x * 0.5f, comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); + SHVec4 btmExtent4 = SHMatrix::Translate(comp.size.x * 0.5f, -comp.size.y * 0.5f, 0.0f) * uiComp->GetMatrix() * SHVec4(0.0f, 0.0f, 0.0f, 1.0f); - SHVec2 topExtent{ topExtent4.x,-topExtent4.y }; - SHVec2 btmExtent{ btmExtent4.x,-btmExtent4.y }; - + SHVec2 topExtent{ topExtent4.x,topExtent4.y }; + SHVec2 btmExtent{ btmExtent4.x,btmExtent4.y }; - SHVec2 windowSize; SHVec2 mousePos; + SHVec2 windowSize; + #ifdef SHEDITOR - - windowSize = SHEditorWindowManager::GetEditorWindow()->windowSize; + windowSize = SHEditorWindowManager::GetEditorWindow()->beginContentRegionAvailable; mousePos = SHEditorWindowManager::GetEditorWindow()->viewportMousePos; + //mousePos.y = windowSize.y - mousePos.y; + //SHLOG_INFO("mouse pos: {}, {}", mousePos.x, mousePos.y) + mousePos /= windowSize; + //SHLOG_INFO("mouse pos normalized: {}, {}", mousePos.x, mousePos.y) -#endif - - - - SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0).x , cameraSystem->GetCameraWidthHeight(0).y }; - - topExtent += camSize * 0.5f; - btmExtent += camSize * 0.5f; - - //Convert everything to using ratios - topExtent /= camSize; - btmExtent /= camSize; +#else + int x, y; + SHInputManager::GetMouseScreenPosition(&x, &y); + mousePos.x = x; + mousePos.y = y; + auto ws = SHSystemManager::GetSystem()->GetWindow()->GetWindowSize(); + windowSize = { ws.first,ws.second }; mousePos /= windowSize; +#endif + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; + + + + topExtent = CanvasToScreenPoint(topExtent,true); + btmExtent = CanvasToScreenPoint(btmExtent, true); + + - //SHLOG_INFO("mousePos: {} , {}", mousePos.x, mousePos.y); comp.isClicked = false; if (mousePos.x >= topExtent.x && mousePos.x <= btmExtent.x && mousePos.y >= topExtent.y && mousePos.y <= btmExtent.y) { comp.isHovered = true; - if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) +#ifdef SHEDITOR + if (SHSystemManager::GetSystem()->editorState == SHEditor::State::PLAY) + { + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = true; + } + } +#else + if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::LMB)) { comp.isClicked = true; } - //SHLOG_INFO("BUTTON HOVERED"); - - +#endif } else { comp.isHovered = false; - - //SHLOG_INFO("BUTTON NOT HOVERED") } - - + + + if (comp.isClicked && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + { + comp.isClicked = false; + comp.value = !comp.value; + SHButtonClickEvent clickEvent; + clickEvent.EID = comp.GetEID(); + clickEvent.value = comp.value; + SHEventManager::BroadcastEvent(clickEvent, SH_BUTTON_CLICK_EVENT); + } + if (SHComponentManager::HasComponent(comp.GetEID())) { - //auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); + auto renderable = SHComponentManager::GetComponent_s(comp.GetEID()); //auto texture = SHResourceManager::Get(comp.GetDefaultTexture()); - //auto material = renderable->GetModifiableMaterial(); - //material->SetProperty("texture", comp.GetDefaultTexture()); + auto material = renderable->GetModifiableMaterial(); + if (comp.GetValue() == false) + { + if (comp.GetDefaultTexture()!= 0 && SHAssetManager::GetType(comp.GetDefaultTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetDefaultTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + } + else + { + if (comp.GetToggledTexture() != 0 && SHAssetManager::GetType(comp.GetToggledTexture()) == AssetType::TEXTURE) + { + material->SetProperty("data.textureIndex", comp.GetToggledTexture()); + //SHLOG_INFO("SETTING DEFAULT TEXTURE") + } + } + } } + void SHUISystem::UpdateButtonsRoutine::Execute(double dt) noexcept { SHUISystem* system = (SHUISystem*)GetSystem(); @@ -219,6 +385,34 @@ namespace SHADE if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) system->UpdateButtonComponent(comp); } + + auto& toggleButtonDense = SHComponentManager::GetDense(); + for (auto& comp : toggleButtonDense) + { + if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) + system->UpdateToggleButtonComponent(comp); + } } + SHVec2 SHUISystem::CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept + { + SHVec2 result{canvasPoint}; + + auto cameraSystem = SHSystemManager::GetSystem(); + + SHVec2 camSize{ cameraSystem->GetCameraWidthHeight(0) }; + //camSize.y *= -1.0f; + + result.y *= -1.0f; + result += camSize * 0.5f; + + if (normalized) + return result / camSize; + else + return result; + } + + + + }//end namespace diff --git a/SHADE_Engine/src/UI/SHUISystem.h b/SHADE_Engine/src/UI/SHUISystem.h index 04e057ad..ae1091ec 100644 --- a/SHADE_Engine/src/UI/SHUISystem.h +++ b/SHADE_Engine/src/UI/SHUISystem.h @@ -3,14 +3,20 @@ #include "SH_API.h" #include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystemRoutine.h" -#include "SHUIComponent.h" -#include "SHButtonComponent.h" -#include "SHCanvasComponent.h" + #include "Scene/SHSceneGraph.h" #include "Scene/SHSceneManager.h" +#include "Math/Vector/SHVec2.h" namespace SHADE { + + class SHButtonComponent; + class SHUIComponent; + class SHToggleButtonComponent; + class SHSliderComponent; + class SHCanvasComponent; + class SH_API SHUISystem final: public SHSystem { public: @@ -64,7 +70,11 @@ namespace SHADE private: void UpdateUIComponent(SHUIComponent& comp) noexcept; void UpdateButtonComponent(SHButtonComponent& comp) noexcept; + void UpdateToggleButtonComponent(SHToggleButtonComponent& comp) noexcept; void UpdateCanvasComponent(SHCanvasComponent& comp) noexcept; + + SHVec2 CanvasToScreenPoint(SHVec2& const canvasPoint, bool normalized) noexcept; + }; diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx index bc61eff3..d5b38967 100644 --- a/SHADE_Managed/src/Components/Transform.cxx +++ b/SHADE_Managed/src/Components/Transform.cxx @@ -107,8 +107,7 @@ namespace SHADE Vector3 Transform::Forward::get() { - const SHVec3 DIRECTION = SHVec3::Rotate(-SHVec3::UnitZ, Convert::ToNative(GlobalRotation)); - return Convert::ToCLI(DIRECTION); + return Vector3::Rotate(Vector3::Forward, GlobalRotation); } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Math/Vector3.cxx b/SHADE_Managed/src/Math/Vector3.cxx index d2862ac7..647174a2 100644 --- a/SHADE_Managed/src/Math/Vector3.cxx +++ b/SHADE_Managed/src/Math/Vector3.cxx @@ -167,6 +167,10 @@ namespace SHADE { return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(axis), radians)); } + Vector3 Vector3::Rotate(Vector3 vec, Quaternion quat) + { + return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(quat))); + } Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs) { float lx = lhs.x, rx = rhs.x; diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx index 76b11420..31a373ba 100644 --- a/SHADE_Managed/src/Math/Vector3.hxx +++ b/SHADE_Managed/src/Math/Vector3.hxx @@ -19,10 +19,17 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Vector2.hxx" -value struct Quaternion; - namespace SHADE { + /*---------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-------------------------------------------------------------------------- --- */ + value struct Quaternion; + + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-------------------------------------------------------------------------- --- */ + /// /// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector. /// Designed to closely match Unity's Vector3 struct. @@ -308,6 +315,12 @@ namespace SHADE /// The Vector3 that represents the rotated vector. static Vector3 Rotate(Vector3 vec, Vector3 axis, float radians); /// + /// Rotates a Vector3 using a Quaternion. + /// + /// A Vector3 to rotate. + /// A Quaternion to rotate the vector with. + static Vector3 Rotate(Vector3 vec, Quaternion quat); + /// /// Computes and returns a Vector3 that is made from the smallest components of /// the two specified Vector3s. /// From 1dc16fdcda0ec5becc71822d45ced957460b4fc9 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 22 Jan 2023 17:38:51 +0800 Subject: [PATCH 130/134] 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; /*---------------------------------------------------------------------------------*/ From 0c3106f15b9d770be1a2391655ecf63bcf404e36 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Sun, 22 Jan 2023 19:20:03 +0800 Subject: [PATCH 131/134] 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; - - - - }; From a0f6cd3ae7c6a4aadb5916e8042515e0dd7573f7 Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 23 Jan 2023 00:37:22 +0800 Subject: [PATCH 132/134] 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; + } +} From 5730381302bcc23fd0a7fffc6139ced1ce7bef7e Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 23 Jan 2023 00:56:46 +0800 Subject: [PATCH 133/134] 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 From 4ed7aa3aed2ccfcf0eb6742bd5dc5b041765aced Mon Sep 17 00:00:00 2001 From: Diren D Bharwani Date: Mon, 23 Jan 2023 03:03:40 +0800 Subject: [PATCH 134/134] 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;