diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig index d0fa83df..ee5e42a8 100644 --- a/Assets/Application.SHConfig +++ b/Assets/Application.SHConfig @@ -1,4 +1,4 @@ Start in Fullscreen: false -Starting Scene ID: 97402985 +Starting Scene ID: 87244611 Window Size: {x: 1920, y: 1080} Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/CollisionTags.SHConfig b/Assets/CollisionTags.SHConfig index 9488270c..d3ebe7e2 100644 --- a/Assets/CollisionTags.SHConfig +++ b/Assets/CollisionTags.SHConfig @@ -1,16 +1,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 +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 diff --git a/Assets/Editor/Editor.SHConfig b/Assets/Editor/Editor.SHConfig index b492a983..51425027 100644 --- a/Assets/Editor/Editor.SHConfig +++ b/Assets/Editor/Editor.SHConfig @@ -1,4 +1,4 @@ Start Maximized: true -Working Scene ID: 97402985 +Working Scene ID: 97161771 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 deleted file mode 100644 index 56f272e0..00000000 --- a/Assets/Scenes/PhysicsSandbox.shade +++ /dev/null @@ -1,247 +0,0 @@ -- EID: 0 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - Translate: {x: 2.72256827, y: 0.501797795, z: -0.0273017883} - Rotate: {x: 0, y: 0, z: 0.436332315} - Scale: {x: 4.61070776, y: 0.99999392, z: 0.999996722} - 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: ~ -- EID: 1 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Camera Component: - Position: {x: 0, y: 2, z: 10} - Pitch: 0 - Yaw: 0 - Roll: 0 - Width: 1920 - Height: 1080 - Near: 0.00999999978 - Far: 10000 - Perspective: true - IsActive: true - Scripts: ~ -- EID: 3 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - 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 - RigidBody Component: - Type: Dynamic - Auto Mass: false - Mass: 0.52359879 - Drag: 0.00999999978 - Angular Drag: 0 - 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: 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: 2 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - 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 - Collider Component: - DrawColliders: false - Colliders: - - Is Trigger: false - Collision Tag: 2 - 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: 4 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - Translate: {x: 0, y: -3, z: 0} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 10, y: 3, z: 10} - 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: ~ -- 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 - 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: ~ -- 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 - 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: ~ -- EID: 7 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - 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: - Type: Dynamic - Auto Mass: false - Mass: 1 - Drag: 0.00999999978 - 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 - 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: 5 -- EID: 8 - Name: Default - IsActive: true - NumberOfChildren: 0 - Components: - Transform Component: - Translate: {x: 0, y: 0, z: 3} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 1, y: 1, z: 1} - 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: ~ \ No newline at end of file diff --git a/Assets/Scenes/PhysicsSandbox.shade.shmeta b/Assets/Scenes/PhysicsSandbox.shade.shmeta deleted file mode 100644 index 97c00ca6..00000000 --- a/Assets/Scenes/PhysicsSandbox.shade.shmeta +++ /dev/null @@ -1,3 +0,0 @@ -Name: PhysicsSandbox -ID: 97402985 -Type: 5 diff --git a/Assets/Scripts/Gameplay/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs b/Assets/Scripts/Gameplay/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs index b5b03629..7c68712c 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, false)[0]; + RaycastHit sightRayHit = Physics.Raycast(sightRay); //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 8323dba2..9c879314 100644 --- a/Assets/Scripts/Gameplay/Player/SC_PickAndThrow.cs +++ b/Assets/Scripts/Gameplay/Player/SC_PickAndThrow.cs @@ -1,7 +1,6 @@ using SHADE; using SHADE_Scripting; using System; -using System.Collections.Generic; using static PlayerController; using static Item; @@ -204,13 +203,9 @@ public class PickAndThrow : Script Vector3 playerRayPos = pc.tranform.GlobalPosition; playerRayPos.y += 0.05f; dirNor.Normalise(); - 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]; + 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); inRange = CheckForItem(ray1) || CheckForItem(ray2) || CheckForItem(ray3); } } diff --git a/Assets/Scripts/Tests/PhysicsTestObj.cs b/Assets/Scripts/Tests/PhysicsTestObj.cs deleted file mode 100644 index 2348894f..00000000 --- a/Assets/Scripts/Tests/PhysicsTestObj.cs +++ /dev/null @@ -1,119 +0,0 @@ -using SHADE; -using System; -using System.Collections.Generic; -using static Item; - - -public class PhysicsTestObj : Script -{ - public RigidBody body { get; set; } - public Collider collider { 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() - { - body = GetComponent(); - collider = GetComponent(); - - for (int i = 0; i < 6; ++i) - { - move[i] = false; - rotate[i] = false; - } - } - - 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])) - 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); - body.AddForce(moveVec[i] * forceAmount); - move[i] = false; - } - - if (shouldRotate) - { - body.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 deleted file mode 100644 index 8c096651..00000000 --- a/Assets/Scripts/Tests/PhysicsTestObj.cs.shmeta +++ /dev/null @@ -1,3 +0,0 @@ -Name: PhysicsTestObj -ID: 159293012 -Type: 9 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 5f451dea..fcceacab 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -77,6 +77,9 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); +#ifndef _PUBLISH + SHSystemManager::CreateSystem(); +#endif SHSystemManager::CreateSystem(); SHSystemManager::CreateSystem(); @@ -87,6 +90,7 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHGraphicsSystem* graphicsSystem = static_cast(SHSystemManager::GetSystem()); + SHPhysicsSystem* physicsSystem = SHSystemManager::GetSystem(); // Link up SHDebugDraw SHSystemManager::CreateSystem(); @@ -101,8 +105,6 @@ namespace Sandbox editor->SetSDLWindow(sdlWindow); editor->SetSHWindow(&window); } - - SHSystemManager::CreateSystem(); #endif // Create Routines @@ -114,11 +116,11 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); -#ifdef SHEDITOR - SHSystemManager::RegisterRoutine(); +#ifndef _PUBLISH + SHSystemManager::RegisterRoutine(); #endif SHSystemManager::RegisterRoutine(); @@ -191,12 +193,32 @@ namespace Sandbox #endif SHSceneManager::SceneUpdate(0.016f); #ifdef SHEDITOR - SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, SHFrameRateController::GetRawDeltaTime()); editor->PollPicking(); #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 dd713980..73926115 100644 --- a/SHADE_Application/src/Scenes/SBMainScene.cpp +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -44,6 +44,23 @@ 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; + } + + #ifdef SHEDITOR + + physicsSystem->ForceBuild(SHSceneManager::GetCurrentSceneGraph()); + + #else + + physicsSystem->BuildScene(SHSceneManager::GetCurrentSceneGraph()); + + #endif + /*-----------------------------------------------------------------------*/ /* TESTING CODE */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 0603b22b..a5edd124 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -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/Camera/SHCameraArmComponent.h b/SHADE_Engine/src/Camera/SHCameraArmComponent.h index dfae1cd5..9d8ec853 100644 --- a/SHADE_Engine/src/Camera/SHCameraArmComponent.h +++ b/SHADE_Engine/src/Camera/SHCameraArmComponent.h @@ -10,7 +10,7 @@ namespace SHADE { - class SHAABB; + class SHBox; 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 4fb1d5cc..6feece48 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/SHAABB.h" +#include "Math/Geometry/SHBox.h" #include "Math/SHRay.h" #include "Physics/System/SHPhysicsSystem.h" @@ -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/ECS_Base/Managers/SHEntityManager.cpp b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp index f5f08674..1c603c57 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/ColliderTagPanel/SHColliderTagPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/ColliderTagPanel/SHColliderTagPanel.cpp index f28e29c5..8169aa5c 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/CollisionTags/SHCollisionTagMatrix.h" +#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Editor/SHEditorWidgets.hpp" namespace SHADE @@ -15,7 +15,7 @@ namespace SHADE ImGui::TableNextRow(); ImGui::PushID("CollisionTagNames"); - for (int i = SHCollisionTag::NUM_LAYERS; i >= 1; --i) + for (int i = SHCollisionTag::NUM_LAYERS; i >= 0; --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 - 1; ++i) + for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++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/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 17dfdd6a..3e1fdc44 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -18,11 +18,10 @@ #include "Physics/Interface/SHColliderComponent.h" #include "Reflection/SHReflectionMetadata.h" #include "Resource/SHResourceManager.h" +#include "Physics/Collision/SHCollisionTagMatrix.h" #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 { template @@ -256,34 +255,31 @@ 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); }, "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. Setting mass will turn this off."); - SHEditorWidgets::DragFloat("Mass", [component] {return component->GetMass(); }, [component](float const& value) {component->SetMass(value); }, "Mass"); + SHEditorWidgets::CheckBox("Use Gravity", [component]{return component->IsGravityEnabled();}, [component](bool const& value){component->SetGravityEnabled(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 { - 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::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::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "If the position between frames should be interpolated."); + SHEditorWidgets::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "Interpolate"); 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); }, "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."); + 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"); ImGui::PopID(); SHEditorWidgets::TextLabel("Freeze Rotation"); ImGui::PushID("FreezeRot"); - 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."); + 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"); ImGui::PopID(); SHEditorWidgets::EndPanel(); @@ -292,15 +288,9 @@ 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("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); + 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); @@ -310,7 +300,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->IsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); + SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->GetIsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); } } @@ -342,67 +332,64 @@ namespace SHADE { DrawContextMenu(component); - 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; - ImGui::BeginChild("Collision Shapes", { 0.0f, collisionShapes->empty() ? 1.0f : 250.0f }, true); + auto& colliders = component->GetCollisionShapes(); + int const size = static_cast(colliders.size()); + 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* shape = component->GetCollisionShape(i); + SHCollisionShape* collider = &component->GetCollisionShape(i); auto cursorPos = ImGui::GetCursorPos(); - //collider->IsTrigger - if (shape->GetType() == SHCollisionShape::Type::BOX) + + if (collider->GetType() == SHCollisionShape::Type::BOX) { SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto* box = reinterpret_cast(shape); + const auto* BOX = reinterpret_cast(collider->GetShape()); SHEditorWidgets::DragVec3 ( "Half Extents", { "X", "Y", "Z" }, - [box] { return box->GetRelativeExtents(); }, - [box](SHVec3 const& vec) { box->SetRelativeExtents(vec); }); + [BOX] { return BOX->GetRelativeExtents(); }, + [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } - else if (shape->GetType() == SHCollisionShape::Type::SPHERE) + else if (collider->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); + const auto* SPHERE = reinterpret_cast(collider->GetShape()); SHEditorWidgets::DragFloat ( "Radius", - [sphere] { return sphere->GetRelativeRadius(); }, - [sphere](float const& value) { sphere->SetRelativeRadius(value); }); + [SPHERE] { return SPHERE->GetRelativeRadius(); }, + [collider](float const& value) { collider->SetBoundingSphere(value); }); } - else if (shape->GetType() == SHCollisionShape::Type::CAPSULE) + else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) { } { - 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));}); - + SHEditorWidgets::CheckBox("Is Trigger", [collider] { return collider->IsTrigger(); }, [collider](bool value) { collider->SetIsTrigger(value); }); + SHEditorWidgets::ComboBox("Tag", collisionTagNames, [collider]{return SHCollisionTagMatrix::GetTagIndex(collider->GetCollisionTag().GetName());}, [collider](int const& value){collider->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));}); if(ImGui::CollapsingHeader("Physics Material")) { - 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::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::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f }); - SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&shape] {return shape->GetPositionOffset(); }, [&shape](SHVec3 const& vec) {shape->SetPositionOffset(vec); }); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, - [&shape] + [&collider] { - auto offset = shape->GetRotationOffset(); + auto offset = collider->GetRotationOffset(); return offset; }, - [&shape](SHVec3 const& vec) + [&collider](SHVec3 const& vec) { - shape->SetRotationOffset(vec); + collider->SetRotationOffset(vec); }, true); SHEditorWidgets::EndPanel(); } @@ -417,24 +404,21 @@ namespace SHADE } if (colliderToDelete.has_value()) { - component->GetCollider()->RemoveCollisionShape(colliderToDelete.value()); + component->RemoveCollider(colliderToDelete.value()); } ImGui::EndChild(); - // TODO: Handle differences between composite & hull collider if (ImGui::BeginMenu("Add Collider")) { int newColl = -1; if (ImGui::Selectable("Box Collider")) { - auto* compositeCollider = dynamic_cast(component->GetCollider()); - compositeCollider->AddBoxCollisionShape(SHVec3::One); + newColl = component->AddBoundingBox(); } if (ImGui::Selectable("Sphere Collider")) { - auto* compositeCollider = dynamic_cast(component->GetCollider()); - compositeCollider->AddSphereCollisionShape(1.0f); + newColl = component->AddBoundingSphere(); } //No idea why this doesn't work diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index c52d05e4..3fe9ceb5 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -25,7 +25,6 @@ #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" }; @@ -89,7 +88,6 @@ namespace SHADE DrawThemeMenu(); DrawLayoutMenu(); DrawApplicationConfig(); - DrawPhysicsSettings(); std::string const sceneName{std::format("Current Scene: {}",SHSceneManager::GetSceneName().data())}; auto const size = ImGui::CalcTextSize(sceneName.data()); @@ -306,32 +304,4 @@ namespace SHADE ImGui::EndMenu(); } } - - void SHEditorMenuBar::DrawPhysicsSettings() noexcept - { - 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 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(); - } - } - }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h index 4891dc5b..77ebcf55 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h @@ -25,7 +25,6 @@ namespace SHADE void DrawThemeMenu() noexcept; void DrawLayoutMenu() noexcept; void DrawApplicationConfig() noexcept; - void DrawPhysicsSettings() noexcept; float menuBarHeight = 20.0f; std::vector layoutPaths; diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index ca29d416..c090cd69 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -24,6 +24,4 @@ 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 }; -constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_DRAW_EVENT { 19 }; - diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.h b/SHADE_Engine/src/Math/Geometry/SHAABB.h deleted file mode 100644 index 9b62c85b..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.h +++ /dev/null @@ -1,173 +0,0 @@ -/**************************************************************************************** - * \file SHAABB.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a 3-Dimensional Axis Aligned 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 "Math/SHRay.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a 3D Axis-Aligned Bounding Box. - */ - class SH_API SHAABB : private DirectX::BoundingBox - { - public: - /*---------------------------------------------------------------------------------*/ - /* Static Data Members */ - /*---------------------------------------------------------------------------------*/ - - static constexpr size_t NUM_VERTICES = 8; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - ~SHAABB () noexcept = default; - - SHAABB () noexcept; - SHAABB (const SHVec3& center, const SHVec3& halfExtents) noexcept; - SHAABB (const SHAABB& rhs) noexcept; - SHAABB (SHAABB&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHAABB& operator= (const SHAABB& rhs) noexcept; - SHAABB& operator= (SHAABB&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[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 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; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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; - - /** - * @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; - - /** - * @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 Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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; - - /** - * @brief - * Checks if two aabbs are intersecting. - * @return - * True if they are intersecting. - */ - [[nodiscard]] static bool Intersect (const SHAABB& lhs, const SHAABB& rhs) noexcept; - - /** - * @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; - }; - - -} // namespace SHADE - diff --git a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp b/SHADE_Engine/src/Math/Geometry/SHBox.cpp similarity index 60% rename from SHADE_Engine/src/Math/Geometry/SHAABB.cpp rename to SHADE_Engine/src/Math/Geometry/SHBox.cpp index f5d9fd60..7261749b 100644 --- a/SHADE_Engine/src/Math/Geometry/SHAABB.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHBox.cpp @@ -1,5 +1,5 @@ /**************************************************************************************** - * \file SHAABB.cpp + * \file SHBox.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 * \brief Implementation for a 3-Dimensional Axis Aligned Bounding Box * @@ -11,7 +11,7 @@ #include // Primary Header -#include "SHAABB.h" +#include "SHBox.h" // Project Headers #include "Math/SHMathHelpers.h" #include "Math/SHRay.h" @@ -24,52 +24,75 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHAABB::SHAABB() noexcept + SHBox::SHBox() noexcept + : RelativeExtents { SHVec3::One } { - Extents = SHVec3::One * 0.5f; + type = Type::BOX; } - SHAABB::SHAABB(const SHVec3& c, const SHVec3& hE) noexcept + SHBox::SHBox(const SHVec3& c, const SHVec3& hE) noexcept + : RelativeExtents { SHVec3::One } { - Center = c; + type = Type::BOX; + + Center = c; Extents = hE; } - SHAABB::SHAABB(const SHAABB& rhs) noexcept + SHBox::SHBox(const SHBox& rhs) noexcept { if (this == &rhs) return; - Center = rhs.Center; - Extents = rhs.Extents; + type = Type::BOX; + + Center = rhs.Center; + Extents = rhs.Extents; + RelativeExtents = rhs.RelativeExtents; } - SHAABB::SHAABB(SHAABB&& rhs) noexcept + SHBox::SHBox(SHBox&& rhs) noexcept { - Center = rhs.Center; - Extents = rhs.Extents; + type = Type::BOX; + + Center = rhs.Center; + Extents = rhs.Extents; + RelativeExtents = rhs.RelativeExtents; } /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ - SHAABB& SHAABB::operator=(const SHAABB& rhs) noexcept + SHBox& SHBox::operator=(const SHBox& rhs) noexcept { - if (this != &rhs) + if (rhs.type != Type::BOX) { - Center = rhs.Center; - Extents = rhs.Extents; + SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") + } + else if (this != &rhs) + { + Center = rhs.Center; + Extents = rhs.Extents; + RelativeExtents = rhs.RelativeExtents; } return *this; } - SHAABB& SHAABB::operator=(SHAABB&& rhs) noexcept + SHBox& SHBox::operator=(SHBox&& rhs) noexcept { - Center = rhs.Center; - Extents = rhs.Extents; + if (rhs.type != Type::BOX) + { + SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!") + } + else + { + Center = rhs.Center; + Extents = rhs.Extents; + RelativeExtents = rhs.RelativeExtents; + } return *this; } @@ -78,22 +101,27 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHVec3 SHAABB::GetCenter() const noexcept + SHVec3 SHBox::GetCenter() const noexcept { return Center; } - SHVec3 SHAABB::GetExtents() const noexcept + SHVec3 SHBox::GetWorldExtents() const noexcept { return Extents; } - SHVec3 SHAABB::GetMin() const noexcept + const SHVec3& SHBox::GetRelativeExtents() const noexcept + { + return RelativeExtents; + } + + SHVec3 SHBox::GetMin() const noexcept { return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z }; } - SHVec3 SHAABB::GetMax() const noexcept + SHVec3 SHBox::GetMax() const noexcept { return SHVec3{ Center.x + Extents.x, Center.y + Extents.y, Center.z + Extents.z }; } @@ -102,17 +130,22 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHAABB::SetCenter(const SHVec3& newCenter) noexcept + void SHBox::SetCenter(const SHVec3& newCenter) noexcept { Center = newCenter; } - void SHAABB::SetExtents(const SHVec3& newHalfExtents) noexcept + void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept { - Extents = newHalfExtents; + Extents = newWorldExtents; } - void SHAABB::SetMin(const SHVec3& min) noexcept + void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept + { + RelativeExtents = newRelativeExtents; + } + + void SHBox::SetMin(const SHVec3& min) noexcept { const SHVec3 MAX = GetMax(); @@ -120,7 +153,7 @@ namespace SHADE Extents = SHVec3::Abs((MAX - min) * 0.5f); } - void SHAABB::SetMax(const SHVec3& max) noexcept + void SHBox::SetMax(const SHVec3& max) noexcept { const SHVec3 MIN = GetMin(); @@ -128,13 +161,13 @@ namespace SHADE Extents = SHVec3::Abs((max - MIN) * 0.5f); } - void SHAABB::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept + void SHBox::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept { Center = SHVec3::Lerp(min, max, 0.5f); Extents = SHVec3::Abs((max - min) * 0.5f); } - std::vector SHAABB::GetVertices() const noexcept + std::vector SHBox::GetVertices() const noexcept { std::vector vertices{ 8 }; GetCorners(vertices.data()); @@ -145,12 +178,12 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHAABB::TestPoint(const SHVec3& point) const noexcept + bool SHBox::TestPoint(const SHVec3& point) const noexcept { return BoundingBox::Contains(point); } - SHRaycastResult SHAABB::Raycast(const SHRay& ray) const noexcept + SHRaycastResult SHBox::Raycast(const SHRay& ray) const noexcept { SHRaycastResult result; @@ -159,24 +192,22 @@ namespace SHADE { result.position = ray.position + ray.direction * result.distance; result.angle = SHVec3::Angle(ray.position, result.position); - - // TODO: Compute normal } return result; } - bool SHAABB::Contains(const SHAABB& rhs) const noexcept + bool SHBox::Contains(const SHBox& rhs) const noexcept { - return BoundingBox::Contains(rhs) == CONTAINS; + return BoundingBox::Contains(rhs); } - float SHAABB::Volume() const noexcept + float SHBox::Volume() const noexcept { return 8.0f * (Extents.x * Extents.y * Extents.z); } - float SHAABB::SurfaceArea() const noexcept + float SHBox::SurfaceArea() const noexcept { return 8.0f * ((Extents.x * Extents.y) + (Extents.x * Extents.z) @@ -187,21 +218,21 @@ namespace SHADE /* Static Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHAABB SHAABB::Combine(const SHAABB& lhs, const SHAABB& rhs) noexcept + SHBox SHBox::Combine(const SHBox& lhs, const SHBox& rhs) noexcept { - SHAABB result; + SHBox result; CreateMerged(result, lhs, rhs); return result; } - bool SHAABB::Intersect(const SHAABB& lhs, const SHAABB& rhs) noexcept + bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept { return lhs.Intersects(rhs); } - SHAABB SHAABB::BuildFromBoxes(const SHAABB* boxes, size_t numBoxes) noexcept + SHBox SHBox::BuildFromBoxes(const SHBox* boxes, size_t numBoxes) noexcept { - SHAABB result; + SHBox result; for (size_t i = 1; i < numBoxes; ++i) CreateMerged(result, boxes[i - 1], boxes[i]); @@ -209,9 +240,9 @@ namespace SHADE return result; } - SHAABB SHAABB::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept + SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept { - SHAABB result; + SHBox result; CreateFromPoints(result, numVertices, vertices, stride); return result; } diff --git a/SHADE_Engine/src/Math/Geometry/SHBox.h b/SHADE_Engine/src/Math/Geometry/SHBox.h new file mode 100644 index 00000000..a0ca9458 --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHBox.h @@ -0,0 +1,105 @@ +/**************************************************************************************** + * \file SHBox.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a 3-Dimensional Axis Aligned 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, + private DirectX::BoundingBox + { + 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) 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]] 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; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + 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; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] bool TestPoint (const SHVec3& point) 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; + [[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; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHVec3 RelativeExtents; + }; + + +} // namespace SHADE + diff --git a/SHADE_Engine/src/Math/Geometry/SHPlane.cpp b/SHADE_Engine/src/Math/Geometry/SHPlane.cpp deleted file mode 100644 index 1ffbfaba..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHPlane.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************************** - * \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 deleted file mode 100644 index 6593c627..00000000 --- a/SHADE_Engine/src/Math/Geometry/SHPlane.h +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************************** - * \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 "Math/SHRay.h" -#include "Math/Vector/SHVec4.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a 3D plane in point-normal form. - */ - class SH_API SHPlane - { - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - ~SHPlane () noexcept = 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; - - /** - * @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; - - /** - * @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/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp b/SHADE_Engine/src/Math/Geometry/SHShape.cpp similarity index 57% rename from SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp rename to SHADE_Engine/src/Math/Geometry/SHShape.cpp index c75437cb..2f869029 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsCapsule.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHShape.cpp @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCapsuleVsCapsule.cpp + * \file SHShape.cpp * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Implementation for the Detecting Collisions between two capsules + * \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 @@ -11,25 +11,25 @@ #include // Primary Header -#include "SHCollision.h" - -// Project Headers -#include "Math/SHMathHelpers.h" +#include "SHShape.h" namespace SHADE { /*-----------------------------------------------------------------------------------*/ - /* Public Member Functions Definitions */ + /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - bool SHCollision::CapsuleVsCapsule(const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - return false; - } + SHShape::SHShape() + : type { Type::NONE } + {} - bool SHCollision::CapsuleVsCapsule(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHShape::Type SHShape::GetType() const noexcept { - return false; + return type; } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h b/SHADE_Engine/src/Math/Geometry/SHShape.h similarity index 57% rename from SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h rename to SHADE_Engine/src/Math/Geometry/SHShape.h index 3146a743..812cb169 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -1,8 +1,7 @@ /**************************************************************************************** - * \file SHContactSolver.h + * \file SHShape.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Contact Solver that builds contacct constraints and solves - * them. + * \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 @@ -12,8 +11,9 @@ #pragma once // Project Headers -#include "Constraints/SHContactConstraint.h" -#include "Constraints/SHVelocityState.h" +#include "SH_API.h" +#include "Math/SHRay.h" + namespace SHADE { @@ -21,73 +21,62 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates an object that builds contact constraints and solves them. - */ - class SH_API SHContactSolver + class SH_API SHShape { public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using VelocityStates = std::unordered_map; - using ContactConstraints = std::unordered_map; + enum class Type + { + BOX + , SPHERE + , CAPSULE + , CONVEX_HULL + + , COUNT + , NONE = -1 + }; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + bool isIntersecting; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHContactSolver () noexcept = default; - ~SHContactSolver () noexcept = default; + virtual ~SHShape () = default; + + SHShape (const SHShape&) = default; + SHShape (SHShape&&) = default; + + SHShape& operator=(const SHShape&) = default; + SHShape& operator=(SHShape&&) = default; + + SHShape(); /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] const VelocityStates& GetVelocities () const noexcept; - [[nodiscard]] const ContactConstraints& GetContantConstraints () const noexcept; + [[nodiscard]] Type GetType () const noexcept; /*---------------------------------------------------------------------------------*/ - /* Member Functions */ + /* Function Members */ /*---------------------------------------------------------------------------------*/ - /** - * @brief - * Build a contact constraint from a new manifold. - * @param manifold - * A manifold to build a contact constraint from. - */ - void AddContact (const SHCollisionKey& key, const SHManifold& manifold) noexcept; + [[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0; + [[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0; - void Reset () 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: + protected: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - VelocityStates velocityStates; - ContactConstraints contactConstraints; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - void preSolve (float dt) noexcept; - void solve () noexcept; - + Type type; }; - -} // namespace SHADE +} // 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 new file mode 100644 index 00000000..54935251 --- /dev/null +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.cpp @@ -0,0 +1,208 @@ +/**************************************************************************************** + * \file SHBoundingSphere.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 + : RelativeRadius { 1.0f } + { + type = Type::SPHERE; + } + + SHSphere::SHSphere(const SHVec3& center, float radius) noexcept + : RelativeRadius { 1.0f } + { + type = Type::SPHERE; + + Center = center; + Radius = radius; + } + + SHSphere::SHSphere(const SHSphere& rhs) noexcept + { + if (this == &rhs) + return; + + type = Type::SPHERE; + + Center = rhs.Center; + Radius = rhs.Radius; + RelativeRadius = rhs.RelativeRadius; + } + + SHSphere::SHSphere(SHSphere&& rhs) noexcept + { + type = Type::SPHERE; + + Center = rhs.Center; + Radius = rhs.Radius; + RelativeRadius = rhs.RelativeRadius; + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept + { + if (rhs.type != Type::SPHERE) + { + SHLOG_WARNING("Cannot assign a non-sphere to a sphere!") + } + else if (this != &rhs) + { + Center = rhs.Center; + Radius = rhs.Radius; + RelativeRadius = rhs.RelativeRadius; + } + + return *this; + } + + 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; + 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 */ + /*-----------------------------------------------------------------------------------*/ + + 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); + } + + return result; + } + + bool SHSphere::Contains(const SHSphere& rhs) const noexcept + { + return BoundingSphere::Contains(rhs); + } + + 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/Physics/Collision/Shapes/SHSphere.h b/SHADE_Engine/src/Math/Geometry/SHSphere.h similarity index 56% rename from SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h rename to SHADE_Engine/src/Math/Geometry/SHSphere.h index b874d2fe..e056f21a 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.h +++ b/SHADE_Engine/src/Math/Geometry/SHSphere.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHSphereCollisionShape.h + * \file SHBoundingSphere.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Sphere Collision Shape. + * \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 @@ -13,7 +13,8 @@ #include // Project Headers -#include "SHCollisionShape.h" +#include "SHShape.h" +#include "SH_API.h" namespace SHADE { @@ -21,44 +22,18 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates the information to create a sphere. - */ - struct SHSphereCreateInfo + class SH_API SHSphere : public SHShape, + private DirectX::BoundingSphere { - public: - SHVec3 Center = SHVec3::Zero; - float Radius = 1.0f; - float RelativeRadius = 1.0f; - float Scale = 1.0f; - }; - - /** - * @brief - * Encapsulate a Sphere Shape used for Physics Simulations. - */ - class SH_API SHSphere final : public SHCollisionShape - , private DirectX::BoundingSphere - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHCollider; - friend class SHCompositeCollider; - friend class SHCollision; - friend class SHCollisionShapeLibrary; - public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHSphere (SHCollisionShapeID id) noexcept; - SHSphere (const SHSphere& rhs) noexcept; - SHSphere (SHSphere&& rhs) noexcept; + SHSphere () noexcept; + SHSphere (const SHVec3& center, float radius) noexcept; + SHSphere (const SHSphere& rhs) noexcept; + SHSphere (SHSphere&& rhs) noexcept; ~SHSphere () override = default; @@ -73,43 +48,45 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] float GetWorldRadius () const noexcept; - [[nodiscard]] float GetRelativeRadius () const noexcept; - - [[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; + [[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; - void SetScale (float maxScale) noexcept; /*---------------------------------------------------------------------------------*/ /* 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; + [[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; + + + /*---------------------------------------------------------------------------------*/ + /* 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; + [[nodiscard]] static SHSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept; private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - float relativeRadius; - float scale; - }; + float RelativeRadius; -} // namespace SHADE \ No newline at end of file + }; +} // namespace SHADE diff --git a/SHADE_Engine/src/Math/SHColour.cpp b/SHADE_Engine/src/Math/SHColour.cpp index 7c372376..fc2f2a08 100644 --- a/SHADE_Engine/src/Math/SHColour.cpp +++ b/SHADE_Engine/src/Math/SHColour.cpp @@ -260,8 +260,6 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; - // This will never hit - default: return x; } } @@ -276,8 +274,6 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; - // This will never hit - default: return x; } } @@ -292,8 +288,6 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; - // This will never hit - default: return x; } } @@ -308,8 +302,6 @@ 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/SHMathHelpers.h b/SHADE_Engine/src/Math/SHMathHelpers.h index 1d65eb91..427011a6 100644 --- a/SHADE_Engine/src/Math/SHMathHelpers.h +++ b/SHADE_Engine/src/Math/SHMathHelpers.h @@ -46,16 +46,14 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /** Standard Epsilon value for comparing Single-Precision Floating-Point values. */ - static constexpr float EPSILON = 0.0001f; + 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 EULER_CONSTANT = std::numbers::egamma_v; + 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 Function Members */ diff --git a/SHADE_Engine/src/Math/SHMatrix.cpp b/SHADE_Engine/src/Math/SHMatrix.cpp index 2cbd5ef6..3d450a88 100644 --- a/SHADE_Engine/src/Math/SHMatrix.cpp +++ b/SHADE_Engine/src/Math/SHMatrix.cpp @@ -34,14 +34,6 @@ 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 ffd8ce89..6af8fdc9 100644 --- a/SHADE_Engine/src/Math/SHMatrix.h +++ b/SHADE_Engine/src/Math/SHMatrix.h @@ -45,7 +45,6 @@ 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/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp index 1bf51b28..1fa4e246 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.cpp +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -40,14 +40,20 @@ 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 ) {} + 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 */ /*-----------------------------------------------------------------------------------*/ @@ -135,6 +141,16 @@ 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 827f8929..29f6df7e 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.h +++ b/SHADE_Engine/src/Math/SHQuaternion.h @@ -11,6 +11,7 @@ #pragma once #include +#include #include @@ -47,10 +48,14 @@ namespace SHADE SHQuaternion (const SHQuaternion& rhs) = default; SHQuaternion (SHQuaternion&& rhs) = default; - SHQuaternion () noexcept; - SHQuaternion (const SHVec4& vec4) noexcept; - SHQuaternion (const XMFLOAT4& xmfloat4) noexcept; - SHQuaternion (float x, float y, float z, float w) noexcept; + SHQuaternion () noexcept; + 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 */ @@ -77,6 +82,8 @@ 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 622087c6..c4931aba 100644 --- a/SHADE_Engine/src/Math/SHRay.cpp +++ b/SHADE_Engine/src/Math/SHRay.cpp @@ -30,6 +30,12 @@ namespace SHADE , direction { dir } {} + SHRay::SHRay(const reactphysics3d::Ray rp3dRay) noexcept + : position { rp3dRay.point1 } + , direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) } + {} + + /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -56,6 +62,12 @@ 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 56599018..18efc224 100644 --- a/SHADE_Engine/src/Math/SHRay.h +++ b/SHADE_Engine/src/Math/SHRay.h @@ -10,7 +10,10 @@ #pragma once +#include + // Project Headers +#include "SH_API.h" #include "Vector/SHVec3.h" namespace SHADE @@ -37,6 +40,7 @@ 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; @@ -51,6 +55,8 @@ 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/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index 0a0ec092..03de360d 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -246,6 +246,8 @@ 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/Math/Vector/SHVec2.cpp b/SHADE_Engine/src/Math/Vector/SHVec2.cpp index da0215f4..9573be01 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec2.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec2.cpp @@ -50,6 +50,10 @@ namespace SHADE : XMFLOAT2( _x, _y ) {} + SHVec2::SHVec2(const reactphysics3d::Vector2& rp3dVec2) noexcept + : XMFLOAT2( rp3dVec2.x, rp3dVec2.y ) + {} + /*-----------------------------------------------------------------------------------*/ /* Operator Overload Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -161,8 +165,6 @@ namespace SHADE { case 0: return x; case 1: return y; - // This will never hit - default: return x; } } @@ -175,8 +177,6 @@ namespace SHADE { case 0: return x; case 1: return y; - // This will never hit - default: return x; } } @@ -189,8 +189,6 @@ namespace SHADE { case 0: return x; case 1: return y; - // This will never hit - default: return x; } } @@ -203,11 +201,14 @@ 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 78c1e6e8..e780d3ac 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec2.h +++ b/SHADE_Engine/src/Math/Vector/SHVec2.h @@ -11,6 +11,7 @@ #pragma once #include +#include #include #include @@ -58,6 +59,10 @@ 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 */ /*---------------------------------------------------------------------------------*/ @@ -68,6 +73,7 @@ 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 72d2b0a2..4b77636a 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec3.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec3.cpp @@ -57,6 +57,14 @@ 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 */ /*-----------------------------------------------------------------------------------*/ @@ -171,8 +179,6 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; - // This will never hit - default: return x; } } @@ -186,8 +192,6 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; - // This will never hit - default: return x; } } @@ -201,8 +205,6 @@ namespace SHADE case 0: return x; case 1: return y; case 2: return z; - // This will never hit - default: return x; } } @@ -216,11 +218,19 @@ 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; @@ -372,30 +382,6 @@ 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 4b0112c5..de37d6a5 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec3.h +++ b/SHADE_Engine/src/Math/Vector/SHVec3.h @@ -11,6 +11,8 @@ #pragma once #include +#include +#include #include #include @@ -67,6 +69,9 @@ namespace SHADE // Conversion from other math types to SHADE + SHVec3 (const reactphysics3d::Vector3& rp3dVec3) noexcept; + SHVec3 (const reactphysics3d::Quaternion& rp3dVec3) noexcept; + /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ @@ -76,6 +81,8 @@ 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; @@ -115,28 +122,27 @@ 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 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; + [[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; }; SHVec3 operator* (float lhs, const SHVec3& rhs) noexcept; diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.cpp b/SHADE_Engine/src/Math/Vector/SHVec4.cpp index c164e7f4..c6f01d9e 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec4.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec4.cpp @@ -164,8 +164,6 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; - // This will never hit - default: return x; } } @@ -180,8 +178,6 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; - // This will never hit - default: return x; } } @@ -196,8 +192,6 @@ namespace SHADE case 1: return y; case 2: return z; case 3: return w; - // This will never hit - default: return x; } } @@ -212,8 +206,6 @@ 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/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp deleted file mode 100644 index 7177e517..00000000 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.cpp +++ /dev/null @@ -1,644 +0,0 @@ -/**************************************************************************************** - * \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 AABBs 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 SHAABB& 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 SHAABB& 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); - - nodeMap.erase(id); - } - - const std::vector& SHAABBTree::Query(SHCollisionShapeID id, const SHAABB& 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 (!SHAABB::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; - 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; - } - - /*-----------------------------------------------------------------------------------*/ - /* 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 = freeList; - 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 SHAABB& LEAF_AABB = nodes[index].AABB; - - uint32_t searchIndex = root; - while (!isLeaf(searchIndex)) - { - 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()); - - 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 = 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)) - 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 = SHAABB::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; - - 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; - - 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 = SHAABB::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 = 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); - } - else - { - nodeC.right = G; - nodeA.right = F; - nodeF.parent = index; - - 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); - } - - 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 = 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); - } - else - { - nodeB.left = E; - nodeA.left = D; - nodeD.parent = index; - - 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); - } - - 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 deleted file mode 100644 index 292c3528..00000000 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************************** - * \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/Shapes/SHCollisionShape.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a dynamic AABB Tree for collision detection. - */ - class SH_API SHAABBTree - { - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using AABBs = std::vector; - - /*---------------------------------------------------------------------------------*/ - /* 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 AABBs& GetAABBs () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - 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 SHAABB& 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 */ - /*-------------------------------------------------------------------------------*/ - - SHAABB 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/Contacts/SHCollisionEvents.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h deleted file mode 100644 index 15142303..00000000 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionEvents.h +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionKey.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 "SHCollisionKey.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: - SHCollisionKey info; - SHCollisionState state = SHCollisionState::INVALID; - }; - - /** - * @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; - - SHCollisionKey info; - SHCollisionState state = SHCollisionState::INVALID; - SHVec3 normal; - SHVec3 contactPoints[MAX_NUM_CONTACTS]; - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp b/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp deleted file mode 100644 index 4bb22697..00000000 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.cpp +++ /dev/null @@ -1,166 +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 "SHCollisionKey.h" - -// Project Headers -#include "Physics/Collision/SHCollider.h" -#include "Physics/Interface/SHColliderComponent.h" - - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionKey::SHCollisionKey() 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(); - } - - SHCollisionKey::SHCollisionKey(const SHCollisionKey& rhs) noexcept - { - value[0] = rhs.value[0]; - value[1] = rhs.value[1]; - } - - SHCollisionKey::SHCollisionKey(SHCollisionKey&& rhs) noexcept - { - value[0] = rhs.value[0]; - value[1] = rhs.value[1]; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionKey& SHCollisionKey::operator=(const SHCollisionKey& rhs) noexcept - { - if (this == &rhs) - return *this; - - value[0] = rhs.value[0]; - value[1] = rhs.value[1]; - - return *this; - } - - SHCollisionKey& SHCollisionKey::operator=(SHCollisionKey&& rhs) noexcept - { - value[0] = rhs.value[0]; - value[1] = rhs.value[1]; - - return *this; - } - - bool SHCollisionKey::operator==(const SHCollisionKey& 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 SHCollisionKey::GetEntityA() const noexcept - { - return ids[ENTITY_A]; - } - - EntityID SHCollisionKey::GetEntityB() const noexcept - { - return ids[ENTITY_B]; - } - - uint32_t SHCollisionKey::GetShapeIndexA() const noexcept - { - return ids[SHAPE_INDEX_A]; - } - - uint32_t SHCollisionKey::GetShapeIndexB() const noexcept - { - return ids[SHAPE_INDEX_B]; - } - - const SHRigidBodyComponent* SHCollisionKey::GetRigidBodyA() const noexcept - { - return SHComponentManager::GetComponent_s(ids[ENTITY_A]); - } - - const SHRigidBodyComponent* SHCollisionKey::GetRigidBodyB() const noexcept - { - return SHComponentManager::GetComponent_s(ids[ENTITY_B]); - } - - 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* SHCollisionKey::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 SHCollisionKey::SetEntityA(EntityID entityID) noexcept - { - ids[ENTITY_A] = entityID; - } - - void SHCollisionKey::SetEntityB(EntityID entityID) noexcept - { - ids[ENTITY_B] = entityID; - } - - void SHCollisionKey::SetCollisionShapeA(uint32_t shapeIndexA) noexcept - { - ids[SHAPE_INDEX_A] = shapeIndexA; - } - - 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/SHContact.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h deleted file mode 100644 index bacf2255..00000000 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHContact.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************************** - * \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/Shapes/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 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(); - }; - - /** - * @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; // 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; - }; -} - -#pragma once diff --git a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h b/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h deleted file mode 100644 index e60e5329..00000000 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************************** - * \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/Narrowphase/SHSATInfo.h" -#include "Physics/Collision/Shapes/SHCollisionShape.h" -#include "SHContact.h" -#include "SHCollisionEvents.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - 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 */ - /*---------------------------------------------------------------------------------*/ - - // We only need 4 contact points to build a stable manifold. - static constexpr int MAX_NUM_CONTACTS = 4; - - SHCollisionShape* shapeA; - SHCollisionShape* shapeB; - - SHRigidBody* bodyA = nullptr; - SHRigidBody* bodyB = nullptr; - - uint32_t numContacts = 0; - SHCollisionState state = SHCollisionState::INVALID; - - SHSATInfo cachedSATInfo; - - SHVec3 normal; - SHVec3 tangents[SHContact::NUM_TANGENTS]; - SHContact contacts[MAX_NUM_CONTACTS]; - - }; - -} // 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 deleted file mode 100644 index f1b93a43..00000000 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHManifold.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************************** - * \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 - : shapeA { a } - , shapeB { b } - { - bodyA = shapeA->collider->rigidBody; - bodyB = shapeB->collider->rigidBody; - } - - 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 } - , 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); - - for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) - tangents[i] = rhs.tangents[i]; - } - - inline SHManifold::SHManifold(SHManifold&& rhs) noexcept - : 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); - - for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) - tangents[i] = rhs.tangents[i]; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - inline SHManifold& SHManifold::operator=(const SHManifold& rhs) noexcept - { - if (this == &rhs) - return *this; - - 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); - - for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) - tangents[i] = rhs.tangents[i]; - - return *this; - } - - 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; - 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); - - for (int i = 0; i < SHContact::NUM_TANGENTS; ++i) - tangents[i] = rhs.tangents[i]; - - return *this; - } -} // 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 deleted file mode 100644 index 6c82c3a5..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCapsuleVsConvex.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************************** - * \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/Shapes/SHConvexPolyhedron.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 deleted file mode 100644 index 060d42cc..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollision.h +++ /dev/null @@ -1,222 +0,0 @@ -/**************************************************************************************** - * \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 "Math/Geometry/SHPlane.h" -#include "Physics/Collision/Contacts/SHManifold.h" -#include "Physics/Collision/Contacts/SHCollisionKey.h" -#include "Physics/Collision/Shapes/SHHalfEdgeStructure.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; - - [[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: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - struct FaceQuery - { - 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; - int32_t axis = -1; - 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; - - // Capsule VS Convex - - // TODO: Capsule VS Convex uses the same gauss map optimisation as convex vs convex - - // Convex VS Convex - - /* - * ! 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 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; - - // 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/SHCollisionDispatch.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp deleted file mode 100644 index 075e113f..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************************** - * \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] - { - // vs Sphere / Box / 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] - { - // vs Sphere / Box / Capsule - - { SHCollision::SphereVsSphere, SHCollision::SphereVsConvex, SHCollision::SphereVsCapsule } // Sphere - , { SHCollision::ConvexVsSphere, SHCollision::ConvexVsConvex, SHCollision::ConvexVsCapsule } // Box - , { SHCollision::CapsuleVsSphere, SHCollision::CapsuleVsConvex, SHCollision::CapsuleVsCapsule } // Capsule - }; - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - 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/SHConvexVsConvex.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp deleted file mode 100644 index e38a66a7..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHConvexVsConvex.cpp +++ /dev/null @@ -1,822 +0,0 @@ -/**************************************************************************************** - * \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" -#include "Math/Geometry/SHPlane.h" -#include "Physics/Collision/Shapes/SHConvexPolyhedron.h" -#include "Physics/SHPhysicsConstants.h" -#include "Tools/Utilities/SHUtilities.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Public Member Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHCollision::ConvexVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - 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; - - return true; - } - - bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - 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); - - 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. - bool flipNormal = false; - const SHConvexPolyhedron* referencePoly = nullptr; - const SHConvexPolyhedron* incidentPoly = nullptr; - - FaceQuery minFaceQuery; - if (FACE_QUERY_A.bestDistance + ABSOLUTE_TOLERANCE > FACE_QUERY_B.bestDistance * RELATIVE_TOLERANCE) - { - minFaceQuery = FACE_QUERY_A; - 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 - { - minFaceQuery = FACE_QUERY_B; - referencePoly = &POLY_B; - incidentPoly = &POLY_A; - flipNormal = true; - - cachedInfo.type = SHSATInfo::Type::FACE; - cachedInfo.info.refPoly = SHSATInfo::ShapeID::B; - cachedInfo.info.refFace = minFaceQuery.closestFace; - } - - - - - // 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 * 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); - - 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 - 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); - contact.penetration = -EDGE_QUERY.bestDistance; - - 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); - } - - /*-----------------------------------------------------------------------------------*/ - /* 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(); - - 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) - { - const bool IS_MINKOWSKI_FACE = buildMinkowskiFace(A, B, i, j); - 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; - } - } - } - - 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); - } - - 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); - - 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); - - /* - * Find a1, a2, b1, b2, c1, c2 to solve the simultaneous equation - * - * C' = TAIL_B - TAIL_A - * - * a = VB /dot U - * b = -VA /dot U - * 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 C_DOT_VB = SHVec3::Dot(C, VB); // c2 - - /* - * We only need to solve for R - * R = (c1a2 / a1 - c2) / ( b2 - a2b1/a1 ) - */ - - 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 = DENOMINATOR == 0.0f ? NUMERATOR : 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; - } - - 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; - - 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; - } - - 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; - } - - 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 deleted file mode 100644 index 25606084..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************************** - * \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 deleted file mode 100644 index 8e51d54b..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSATInfo.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************************** - * \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; - } -} diff --git a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp b/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp deleted file mode 100644 index 25515fd7..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsCapsule.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************************** - * \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/Shapes/SHSphere.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 deleted file mode 100644 index 07466ab1..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsConvex.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/**************************************************************************************** - * \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/Geometry/SHPlane.h" -#include "Math/SHMathHelpers.h" -#include "Physics/Collision/Shapes/SHSphere.h" -#include "Physics/Collision/Shapes/SHConvexPolyhedron.h" -#include "Physics/SHPhysicsConstants.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Public Member Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHCollision::SphereVsConvex(const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - const SHSphere& SPHERE = dynamic_cast(A); - const SHConvexPolyhedron& POLYHEDRON = dynamic_cast(B); - - const SHVec3 CENTER = SPHERE.Center; - 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; - - // 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 - { - return SphereVsConvex(B, A); - } - - 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 SHSphere& SPHERE = dynamic_cast(A); - const SHConvexPolyhedron& POLYHEDRON = dynamic_cast(B); - - const SHVec3 CENTER = SPHERE.Center; - const float RADIUS = SPHERE.GetWorldRadius(); - - 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 = CENTER; - - 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 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); - if (REGION == 0) - return false; - - // Create contact information based on region - - const SHVec3 P1_TO_CENTER = CENTER - P1; - switch (REGION) - { - case 1: // Region A - case 2: // Region B - { - // 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); - - contact.penetration = RADIUS - SHVec3::Dot(CP_TO_CENTER, -manifold.normal); - contact.position = CP; - - 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 - } - - manifold.contacts[numContacts++] = contact; - manifold.numContacts = numContacts; - - return true; - } - - bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - if (SphereVsConvex(manifold, B, A)) - { - manifold.normal = -manifold.normal; - return true; - }; - - return false; - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Member Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollision::FaceQuery SHCollision::findClosestFace - ( - const SHSphere& sphere - , const SHConvexPolyhedron& polyhedron - ) noexcept - { - FaceQuery faceQuery; - - const SHVec3 CENTER = sphere.Center; - const float RADIUS = sphere.GetWorldRadius(); - - /* - * Test against each 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 < polyhedron.GetFaceCount(); ++i) - { - const SHHalfEdgeStructure::Face& FACE = polyhedron.GetFace(i); - - // Build plane equation - // 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 = FACE_PLANE.SignedDistance(CENTER); - - // 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 > RADIUS) - return faceQuery; - - if (SIGNED_DIST > faceQuery.bestDistance) - { - faceQuery.bestDistance = SIGNED_DIST; - faceQuery.closestFace = i; - } - } - - faceQuery.colliding = true; - return faceQuery; - } - - int32_t SHCollision::findClosestPoint - ( - const SHSphere& sphere - , const SHConvexPolyhedron& polyhedron - , int32_t faceIndex - ) noexcept - { - // Find closest point on face - int32_t closestPointIndex = -1; - - const SHVec3 CENTER = sphere.Center; - - const SHHalfEdgeStructure::Face& FACE = polyhedron.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; - } - - int32_t SHCollision::findVoronoiRegion - ( - const SHSphere& 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: 1 -> 2, 1 -> 3 and 1 -> 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.Center; - 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) - { - 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; - } - - -} // 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 deleted file mode 100644 index 1a76924e..00000000 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHSphereVsSphere.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************************** - * \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/Shapes/SHSphere.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Public Member Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHCollision::SphereVsSphere(const SHCollisionShape& A, const SHCollisionShape& B) noexcept - { - const SHSphere& SPHERE_A = dynamic_cast(A); - const SHSphere& SPHERE_B = dynamic_cast(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 SHSphere& SPHERE_A = dynamic_cast(A); - const SHSphere& SPHERE_B = dynamic_cast(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; - - // 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 = CENTER_A; - contact.penetration = RADIUS_B; - - manifold.contacts[numContacts++] = contact; - } - else - { - manifold.normal = SHVec3::Normalise(A_TO_B); - contact.position = CENTER_B - manifold.normal * RADIUS_B; - 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 deleted file mode 100644 index 2e7cc3c6..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/**************************************************************************************** - * \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 deleted file mode 100644 index a326215f..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************************** - * \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/SHCollisionInfo.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp new file mode 100644 index 00000000..43ad05ca --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp @@ -0,0 +1,93 @@ +/**************************************************************************************** + * \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" + +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 + { + return &SHComponentManager::GetComponent(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]); + } + + const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept + { + return &SHComponentManager::GetComponent(ids[ENTITY_B])->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/Shapes/SHCollisionShapeID.h b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h similarity index 55% rename from SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.h rename to SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h index 09f712d1..d2dad647 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollisionShapeKey.h + * \file SHCollisionInfo.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Collison Shape ID Class and it's hashing function + * \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 @@ -11,95 +11,92 @@ #pragma once // Project Headers -#include "ECS_Base/Entity/SHEntity.h" +#include "Physics/Interface/SHColliderComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" + namespace SHADE { - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - struct SHCollisionShapeIDHash; - /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates an identifier for a collision shape. - */ - union SHCollisionShapeID + class SH_API SHCollisionInfo { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend struct SHCollisionShapeIDHash; + friend class SHCollisionListener; public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class State + { + ENTER + , STAY + , EXIT + + , TOTAL + , INVALID = -1 + }; + /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionShapeID (EntityID eid, uint32_t shapeID) noexcept; - SHCollisionShapeID (const SHCollisionShapeID& rhs) noexcept; - SHCollisionShapeID (SHCollisionShapeID&& rhs) noexcept; + SHCollisionInfo () noexcept; + SHCollisionInfo (EntityID entityA, EntityID entityB) noexcept; - ~SHCollisionShapeID () noexcept = default; + + SHCollisionInfo (const SHCollisionInfo& rhs) = default; + SHCollisionInfo (SHCollisionInfo&& rhs) = default; + ~SHCollisionInfo () = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHCollisionShapeID& operator=(const SHCollisionShapeID& rhs) noexcept; - SHCollisionShapeID& operator=(SHCollisionShapeID&& rhs) noexcept; + bool operator== (const SHCollisionInfo& rhs) const noexcept; + bool operator!= (const SHCollisionInfo& rhs) const noexcept; - bool operator==(const SHCollisionShapeID& rhs) const; + SHCollisionInfo& operator= (const SHCollisionInfo& rhs) = default; + SHCollisionInfo& operator= (SHCollisionInfo&& rhs) = default; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] EntityID GetEntityID () const noexcept; - [[nodiscard]] uint32_t GetShapeIndex () const noexcept; + [[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: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - struct IDs - { - public: - EntityID entityID = MAX_EID; - uint32_t shapeIndex = std::numeric_limits::max(); - }; + 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 */ /*---------------------------------------------------------------------------------*/ - uint64_t value; - IDs ids; + union + { + uint64_t value[2]; // EntityValue, ColliderIndexValue + uint32_t ids [4]; // EntityA, EntityB, ColliderIndexA, ColliderIndexB + }; + + State collisionState; }; - /** - * @brief - * Encapsulates a functor to hash a CollisionShapeID - */ - struct SHCollisionShapeIDHash - { - public: - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - std::size_t operator()(const SHCollisionShapeID& id) const; - }; - -} // namespace SHADE - -#include "SHCollisionShapeID.hpp" +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp new file mode 100644 index 00000000..3e485153 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.cpp @@ -0,0 +1,254 @@ +/**************************************************************************************** + * \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/Shapes/SHCollisionShapeLibrary.h b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h similarity index 50% rename from SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.h rename to SHADE_Engine/src/Physics/Collision/SHCollisionListener.h index 462b8dd8..62882556 100644 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionListener.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollisionShapeLibrary.h + * \file SHCollisionListener.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for a Collison Shape Library. + * \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 @@ -10,99 +10,71 @@ #pragma once -#include +// External Dependencies +#include -// Project Header -#include "SHSphere.h" -#include "SHBox.h" +// Project Headers +#include "SH_API.h" +#include "SHCollisionInfo.h" namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHPhysicsSystem; + /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates a class for Creating, Storing and Destroying Collision Shapes.
- * All memory for collision shapes are stored in this factory class.
- */ - class SH_API SHCollisionShapeLibrary final + class SH_API SHCollisionListener final : public rp3d::EventListener { public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionShapeLibrary () noexcept; - ~SHCollisionShapeLibrary () noexcept; + SHCollisionListener() noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] const std::vector& GetCollisionInfoContainer () const noexcept; + [[nodiscard]] const std::vector& GetTriggerInfoContainer () const 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 new sphere collision shape. - */ - SHSphere* CreateSphere (SHCollisionShapeID id, const SHSphereCreateInfo& createInfo); + void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept; + void BindToWorld (rp3d::PhysicsWorld* world) noexcept; + void CleanContainers () noexcept; + void ClearContainers () noexcept; - /** - * @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. - */ - SHBox* CreateBox (SHCollisionShapeID id, const SHBoxCreateInfo& 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); + void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override; + void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override; 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; - using Boxes = std::unordered_map; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - - SHHalfEdgeStructure boxHalfEdgeStructure; - Spheres spheres; - Boxes boxes; - // TODO: Add capsules and hulls + SHPhysicsSystem* system; + std::vector collisionInfoContainer; + std::vector triggerInfoContainer; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - void createBoxPolyhedron() noexcept; + 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/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp deleted file mode 100644 index c643e05e..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/**************************************************************************************** - * \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->IsActive(); - const bool HAS_MOVED = collider->flags & SHCollider::MOVED_FLAG; - - if (!IS_ACTIVE || !HAS_MOVED) - continue; - - // Clear hasMoved flag here - collider->flags &= ~SHCollider::MOVED_FLAG; - - // Update moved shapes in broadphase - for (auto* shape : collider->shapes) - broadphase.Update(shape->id, shape->ComputeAABB()); - } - } - - void SHCollisionSpace::DetectCollisions() noexcept - { - // TODO: Profile broad-phase and narrow-phase - - /* - * 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_ACTIVE = collider->IsActive(); - - // Skip inactive colliders - 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 - // 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) - { - // 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(); - - if (IS_A_TRIGGER || IS_B_TRIGGER) - collideTriggers(key, narrowphasePair); - else - collideManifolds(key, narrowphasePair); - } - - // Clear every frame - narrowphaseBatch.clear(); - - // Test all collisions - if (contactManager) - contactManager->Update(); - } - - const SHCollisionSpace::RaycastResults& SHCollisionSpace::Raycast(const RaycastInfo& info) noexcept - { - 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); - - if (POTENTIAL_HITS.empty()) - return results; - - // 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 uint32_t IDX = HIT_ID.GetShapeIndex(); - const auto* SHAPE = colliders.find(EID)->second->GetCollisionShape(IDX); - - // Filter the layers - const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & info.layers; - if (!LAYER_MATCH) - continue; - - // 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 baseResult; - switch (SHAPE->GetType()) - { - case SHCollisionShape::Type::SPHERE: - { - baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); - break; - } - case SHCollisionShape::Type::BOX: - { - baseResult = dynamic_cast(SHAPE)->Raycast(info.ray); - break; - } - case SHCollisionShape::Type::CAPSULE: - { - // TODO - break; - } - default: continue; // Redundant case - } - - if (!baseResult || baseResult.distance > info.distance) - continue; - - // Copy to a physics raycast result - SHPhysicsRaycastResult result; - memcpy_s(&result, sizeof(SHRaycastResult), &baseResult, sizeof(SHRaycastResult)); - - result.entityHit = EID; - result.shapeIndex = IDX; - - results.emplace_back(result); - } - - return results; - } - - - /*-----------------------------------------------------------------------------------*/ - /* 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 - { - auto* A = narrowphasePair.A; - auto* B = narrowphasePair.B; - - // Send to contact manager - if (contactManager) - contactManager->AddTrigger(key, A, B); - } - - void SHCollisionSpace::collideManifolds(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept - { - auto* A = narrowphasePair.A; - auto* B = narrowphasePair.B; - - // Send to contact manager - if (contactManager) - contactManager->AddManifold(key, A, B); - } -} // 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 deleted file mode 100644 index 8607cf45..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h +++ /dev/null @@ -1,196 +0,0 @@ -/**************************************************************************************** - * \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 - -#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 -{ - /*-----------------------------------------------------------------------------------*/ - /* 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: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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 */ - /*---------------------------------------------------------------------------------*/ - - 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; - - /** - * @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 RaycastResults& Raycast(const RaycastInfo& info) 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/Collision/CollisionTags/SHCollisionTagMatrix.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp similarity index 86% rename from SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp rename to SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp index 4d3980b0..b687c6ca 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.cpp @@ -14,9 +14,6 @@ // Primary Header #include "SHCollisionTagMatrix.h" -// Project Headers -#include "Tools/Utilities/SHUtilities.h" - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -148,9 +145,8 @@ namespace SHADE /** * I HATE FILE IO * - * 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. + * Each line in the file should be "indextag name". + * If the line fails to follow this format, use the default tag name (index + 1) */ // Populate tag names with default @@ -191,40 +187,18 @@ namespace SHADE { SHLOG_ERROR ( - "Collision tag file line {} does not match the required format of 'indextag namemask'. Default tag used for index {}" + "Collision tag file line {} does not match the required format of 'indextag name'. 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(); } @@ -241,9 +215,8 @@ namespace SHADE return; } - // Index Name Mask for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) - collisionTagNamesFile << i << " " << collisionTags[i].GetName() << " " << collisionTags[i].GetMask() << std::endl; + collisionTagNamesFile << i << " " << collisionTags[i].GetName() << std::endl; collisionTagNamesFile.close(); } diff --git a/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.h b/SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTagMatrix.h rename to SHADE_Engine/src/Physics/Collision/SHCollisionTagMatrix.h diff --git a/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.cpp rename to SHADE_Engine/src/Physics/Collision/SHCollisionTags.cpp diff --git a/SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.h b/SHADE_Engine/src/Physics/Collision/SHCollisionTags.h similarity index 100% rename from SHADE_Engine/src/Physics/Collision/CollisionTags/SHCollisionTags.h rename to SHADE_Engine/src/Physics/Collision/SHCollisionTags.h diff --git a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp deleted file mode 100644 index 28b6aafe..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/**************************************************************************************** - * \file SHCompositeCollider.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * of DigiPen Institute of Technology is prohibited. -****************************************************************************************/ - -#include - -// Primary Header -#include "SHCompositeCollider.h" - -// Project Headers -#include "Broadphase/SHDynamicAABBTree.h" -#include "Math/SHMathHelpers.h" -#include "Physics/SHPhysicsEvents.h" -#include "Physics/Dynamics/SHRigidBody.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCompositeCollider::SHCompositeCollider(EntityID eid, const SHTransform& worldTransform) noexcept - : SHCollider( eid, worldTransform ) - { - flags |= COMPOSITE_FLAG; - } - - SHCompositeCollider::SHCompositeCollider(const SHCompositeCollider& rhs) noexcept - : SHCollider( rhs ) - {} - - SHCompositeCollider::SHCompositeCollider(SHCompositeCollider&& rhs) noexcept - : SHCollider( rhs ) - {} - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCompositeCollider& SHCompositeCollider::operator=(const SHCompositeCollider& rhs) noexcept - { - if (this == &rhs) - return *this; - - SHCollider::operator=(rhs); - - return *this; - } - - SHCompositeCollider& SHCompositeCollider::operator=(SHCompositeCollider&& rhs) noexcept - { - SHCollider::operator=(rhs); - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - int SHCompositeCollider::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset) - { - if (!shapeLibrary) - { - SHLOGV_ERROR("Shape factory is unlinked with 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 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); - - // Set offsets - sphere->collider = this; - sphere->SetPositionOffset(posOffset); - sphere->SetRotationOffset(rotOffset); - - 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(NEW_INDEX) - }; - - SHEventManager::BroadcastEvent(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); - - if (rigidBody) - rigidBody->ComputeMassData(); - - return static_cast(NEW_INDEX); - } - - int SHCompositeCollider::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset) - { - if (!shapeLibrary) - { - 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 }; - - SHBox* box = shapeLibrary->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); - } - - -} // 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 deleted file mode 100644 index 8ab71186..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCompositeCollider.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************************** - * \file SHCompositeCollider.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * of DigiPen Institute of Technology is prohibited. -****************************************************************************************/ - -#pragma once - -// Project Headers -#include "SHCollider.h" - -namespace SHADE -{ - /** - * @brief - * Encapsulates the behaviour of a collider with composited shapes.
- * Contains no data members but methods to add multiple shapes. - */ - class SH_API SHCompositeCollider : public SHCollider - { - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHCompositeCollider(EntityID eid, const SHTransform& worldTransform = SHTransform::Identity) noexcept; - SHCompositeCollider(const SHCompositeCollider& rhs) noexcept; - SHCompositeCollider(SHCompositeCollider&& rhs) noexcept; - ~SHCompositeCollider () noexcept override = default; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHCompositeCollider& operator=(const SHCompositeCollider& rhs) noexcept; - SHCompositeCollider& operator=(SHCompositeCollider&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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. - * @return - * The index of the newly added shape. - */ - int AddSphereCollisionShape (float relativeRadius, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero); - - /** - * @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 - }; - - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp new file mode 100644 index 00000000..cab5c93b --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.cpp @@ -0,0 +1,350 @@ +/**************************************************************************************** + * \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 new file mode 100644 index 00000000..447207c7 --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHPhysicsRaycaster.h @@ -0,0 +1,134 @@ +/**************************************************************************************** + * \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/Collision/Shapes/SHBox.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp deleted file mode 100644 index 8022e487..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/**************************************************************************************** - * \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 "SHBox.h" - -// Project Headers -#include "Math/SHMathHelpers.h" -#include "Math/SHMatrix.h" -#include "Physics/Collision/SHCollider.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHBox::SHBox(SHCollisionShapeID id) noexcept - : SHConvexPolyhedron (id, Type::BOX) - , relativeExtents { SHVec3::One } - , scale { SHVec3::One } - { - Extents = SHVec3::One * 0.5f; - } - - SHBox::SHBox(const SHBox& rhs) noexcept - : SHConvexPolyhedron ( rhs ) - , relativeExtents { rhs.relativeExtents } - , scale { rhs.scale } - { - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; - } - - 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 */ - /*-----------------------------------------------------------------------------------*/ - - SHBox& SHBox::operator=(const SHBox& rhs) noexcept - { - if (this == &rhs) - return *this; - - // Collision Shape Properties - - SHConvexPolyhedron::operator=(rhs); - - // Box Properties - - Center = rhs.Center; - Extents = rhs.Extents; - Orientation = rhs.Orientation; - - // Local Properties - - relativeExtents = rhs.relativeExtents; - scale = rhs.scale; - - return *this; - } - - SHBox& SHBox::operator=(SHBox&& rhs) noexcept - { - // Collision Shape Properties - - SHConvexPolyhedron::operator=(rhs); - - // 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 SHBox::GetWorldExtents() const noexcept - { - return Extents; - } - - SHVec3 SHBox::GetRelativeExtents() const noexcept - { - return relativeExtents; - } - - SHVec3 SHBox::GetVertex(int index) const - { - if (index < 0 || index >= NUM_VERTICES) - throw std::invalid_argument("Index out-of-range!"); - - SHVec3 vertices[NUM_VERTICES]; - GetCorners(vertices); - - return vertices[index]; - } - - SHVec3 SHBox::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); - } - - SHVec3 SHBox::GetWorldCentroid() const noexcept - { - return Center; - } - - SHVec3 SHBox::GetRelativeCentroid() const noexcept - { - if (collider) - return SHVec3{ Center } - collider->GetPosition(); - - return Center; - } - - SHVec3 SHBox::GetLocalCentroid() const noexcept - { - return SHVec3::Zero; - } - - SHQuaternion SHBox::GetWorldOrientation() const noexcept - { - return Orientation; - } - - SHQuaternion SHBox::GetRelativeOrientation() const noexcept - { - return transform.orientation; - } - - float SHBox::GetVolume() const noexcept - { - return 8.0f * (Extents.x * Extents.y * Extents.z); - } - - float SHBox::GetSurfaceArea() const noexcept - { - return 8.0f * (Extents.x * Extents.y - + Extents.x * Extents.z - + Extents.y * Extents.z); - } - - SHMatrix SHBox::GetInertiaTensor(float mass) const noexcept - { - static constexpr float ONE_OVER_TWELVE = (1.0f / 12.0f); - - 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; - result.m[1][1] = ONE_OVER_TWELVE * mass * W2_PLUS_H2; - result.m[2][2] = ONE_OVER_TWELVE * mass * W2_PLUS_D2; - return result; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept - { - Extents = newWorldExtents; - - // Recompute Relative radius - relativeExtents = 2.0f * Extents / scale; - } - - 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() }; - - SHVec3 vertices[NUM_VERTICES]; - GetCorners(vertices); - - for (auto& vertex : vertices) - { - min = SHVec3::Min({ vertex, min }); - max = SHVec3::Max({ vertex, max }); - } - - const SHVec3 HALF_EXTENTS = (max - min) * 0.5f; - const SHVec3 CENTROID = min + HALF_EXTENTS; - - 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 deleted file mode 100644 index 480b2501..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHBox.h +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************************** - * \file SHBox.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 - -#include - -// Project Headers -#include "SHConvexPolyhedron.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 Shape used for Physics Simulations. - */ - 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 */ - /*---------------------------------------------------------------------------------*/ - - SHBox (SHCollisionShapeID id) noexcept; - SHBox (const SHBox& rhs) noexcept; - SHBox (SHBox&& rhs) noexcept; - - ~SHBox () override = default; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHBox& operator= (const SHBox& rhs) noexcept; - SHBox& operator= (SHBox&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[nodiscard]] SHVec3 GetWorldExtents () const noexcept; - [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept; - - // Overriden Methods - - [[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 SetWorldExtents (const SHVec3& newWorldExtents) noexcept; - void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept; - void SetScale (const SHVec3& newScale) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* 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; - [[nodiscard]] SHVec3 FindSupportPoint (const SHVec3& direction) const noexcept override; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - SHVec3 relativeExtents; - SHVec3 scale; - }; - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp deleted file mode 100644 index dfbed047..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.cpp +++ /dev/null @@ -1,188 +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 "Physics/Collision/SHCollider.h" -#include "Physics/Collision/CollisionTags/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 } - , collider { nullptr } - , collisionTag { SHCollisionTagMatrix::GetTag(0) } - { - flags |= 1U << SHUtilities::ConvertEnum(colliderType); - } - - /*-----------------------------------------------------------------------------------*/ - /* 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(); - } - - 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 transform.position; - } - - 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; - } - - const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept - { - return *collisionTag; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept - { - collisionTag = newCollisionTag; - } - - 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 - { - transform.position = posOffset; - - Update(); - } - - void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept - { - rotationOffset = rotOffset; - transform.orientation = SHQuaternion::FromEuler(rotationOffset); - - Update(); - } - - 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; - } - -} // 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/Collision/Shapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h deleted file mode 100644 index 3e57b74a..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShape.h +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionShape.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * of DigiPen Institute of Technology is prohibited. -****************************************************************************************/ - -#pragma once - -#include - -// Project Headers -#include "ECS_Base/Entity/SHEntity.h" -#include "Physics/Collision/CollisionTags/SHCollisionTags.h" -#include "Physics/Collision/SHPhysicsMaterial.h" -#include "SHCollisionShapeID.h" -#include "Math/Geometry/SHAABB.h" -#include "Math/Transform/SHTransform.h" -#include "Physics/Collision/SHPhysicsRaycastResult.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - class SHRigidBody; - - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - class SH_API SHCollisionShape - { - private: - - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHCollider; - friend class SHCompositeCollider; - friend class SHColliderComponent; - friend class SHCollisionShapeLibrary; - friend class SHCollisionSpace; - friend struct SHManifold; - - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - enum class Type - { - SPHERE - , BOX - , CAPSULE - , CONVEX_HULL - - , COUNT - , INVALID = -1 - }; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionShape (SHCollisionShapeID id, Type colliderType = Type::SPHERE); - - SHCollisionShape (const SHCollisionShape& rhs) noexcept = default; - SHCollisionShape (SHCollisionShape&& rhs) noexcept = default; - virtual ~SHCollisionShape () noexcept = default; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept = default; - SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept = default; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[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; - - // Offsets - - [[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]] const SHCollisionTag& GetCollisionTag () const noexcept; - - // Virtual methods - - [[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; - void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; - - void SetPositionOffset (const SHVec3& posOffset) noexcept; - void SetRotationOffset (const SHVec3& rotOffset) noexcept; - - // Flags - - // Forces rigidbody to recompute mass if one exists - void SetIsTrigger (bool isTrigger) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - SHCollisionShapeID id; - - SHCollider* collider; // The collider it belongs to. - SHCollisionTag* collisionTag; - SHPhysicsMaterial material; // TODO: Change to pointer once instancing is supported - - SHTransform transform; // Stores the local position and rotation. - - // Needed for conversion to euler angles - SHVec3 rotationOffset; - - uint8_t flags; // 0 0 0 trigger convexHull capsule sphere box - - - RTTR_ENABLE() - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.hpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.hpp deleted file mode 100644 index bb9ccb1f..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeID.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************************** - * \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.shapeIndex } - {} - - inline SHCollisionShapeID::SHCollisionShapeID(SHCollisionShapeID&& rhs) noexcept - : ids { rhs.ids.entityID, rhs.ids.shapeIndex } - {} - - - /*-----------------------------------------------------------------------------------*/ - /* 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); - } - - /*-----------------------------------------------------------------------------------*/ - /* 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/Shapes/SHCollisionShapeLibrary.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp deleted file mode 100644 index c70728f3..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHCollisionShapeLibrary.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************************** - * \file SHCollisionShapeLibrary.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 "SHCollisionShapeLibrary.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHCollisionShapeLibrary::SHCollisionShapeLibrary() noexcept - { - createBoxPolyhedron(); - } - - SHCollisionShapeLibrary::~SHCollisionShapeLibrary() noexcept - { - // 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); - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere* SHCollisionShapeLibrary::CreateSphere(SHCollisionShapeID id, const SHSphereCreateInfo& createInfo) - { - const auto RESULT = spheres.emplace(id, new SHSphere{ id }); - if (RESULT.second) - { - SHSphere* 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; - } - - SHBox* SHCollisionShapeLibrary::CreateBox(SHCollisionShapeID id, const SHBoxCreateInfo& createInfo) - { - const auto RESULT = boxes.emplace(id, new SHBox{ id }); - if (RESULT.second) - { - SHBox* box = RESULT.first->second; - - box->Center = createInfo.Center; - box->Extents = createInfo.Extents; - box->relativeExtents = createInfo.RelativeExtents; - box->Orientation = createInfo.Orientation; - box->scale = createInfo.Scale; - - // Set halfEdge data structure for the box - box->halfEdgeStructure = &boxHalfEdgeStructure; - - return box; - } - - return boxes.find(id)->second; - } - - - void SHCollisionShapeLibrary::DestroyShape(SHCollisionShape* shape) - { - switch (shape->GetType()) - { - case SHCollisionShape::Type::BOX: - { - break; - } - case SHCollisionShape::Type::SPHERE: - { - SHSphere* sphere = spheres.find(shape->id)->second; - spheres.erase(shape->id); - - delete sphere; - sphere = nullptr; - - break; - } - case SHCollisionShape::Type::CAPSULE: - { - break; - } - default: break; - } - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHCollisionShapeLibrary::createBoxPolyhedron() noexcept - { - static constexpr int NUM_VERTICES_PER_FACE = 4; - static constexpr int NUM_FACES = 6; - - /* - * Vertices (Front/Back Face): - * - * 3/7 ---------- 2/6 - * | | - * | | - * | | - * 0/4 ---------- 1/5 - * - * Faces: - * - * 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 } - , { 5, 6, 2, 1 } - , { 5, 4, 7, 6 } - , { 0, 3, 7, 4 } - , { 2, 6, 7, 3 } - , { 5, 1, 0, 4 } - }; - - for (int i = 0; i < NUM_FACES; ++i) - { - SHHalfEdgeStructure::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]); - - boxHalfEdgeStructure.AddFace(newFace); - } - - boxHalfEdgeStructure.Build(); - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.cpp deleted file mode 100644 index 8cccd837..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************************** - * \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 "SHConvexPolyhedron.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHConvexPolyhedron::SHConvexPolyhedron(SHCollisionShapeID id,Type polyhedronType) noexcept - : SHCollisionShape (id, polyhedronType) - , halfEdgeStructure { nullptr } - {} - - SHConvexPolyhedron::SHConvexPolyhedron(const SHConvexPolyhedron& rhs) noexcept - : SHCollisionShape ( rhs ) - , halfEdgeStructure { rhs.halfEdgeStructure } - {} - - SHConvexPolyhedron::SHConvexPolyhedron(SHConvexPolyhedron&& rhs) noexcept - : SHCollisionShape ( rhs ) - , halfEdgeStructure { rhs.halfEdgeStructure } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHConvexPolyhedron& SHConvexPolyhedron::operator=(const SHConvexPolyhedron& rhs) noexcept - { - if (this == &rhs) - return *this; - - SHCollisionShape::operator=(rhs); - - // Local Properties - halfEdgeStructure = rhs.halfEdgeStructure; - - return *this; - } - - SHConvexPolyhedron& SHConvexPolyhedron::operator=(SHConvexPolyhedron&& rhs) noexcept - { - SHCollisionShape::operator=(rhs); - - // Local Properties - halfEdgeStructure = rhs.halfEdgeStructure; - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHHalfEdgeStructure* SHConvexPolyhedron::GetHalfEdgeStructure() const noexcept - { - return halfEdgeStructure; - } - - int32_t SHConvexPolyhedron::GetFaceCount() const noexcept - { - return halfEdgeStructure->GetFaceCount(); - } - - int32_t SHConvexPolyhedron::GetHalfEdgeCount() const noexcept - { - return halfEdgeStructure->GetHalfEdgeCount(); - } - - const SHHalfEdgeStructure::Face& SHConvexPolyhedron::GetFace(int index) const - { - // Assume it has already been initialised - return halfEdgeStructure->GetFace(index); - } - - const SHHalfEdgeStructure::HalfEdge& SHConvexPolyhedron::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/Shapes/SHConvexPolyhedron.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h deleted file mode 100644 index 3944c556..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHConvexPolyhedron.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************************** - * \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 "SHHalfEdgeStructure.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a convex polyhedron shape used for Physics Simulations.. - */ - class SH_API SHConvexPolyhedron : public SHCollisionShape - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHCollider; - friend class SHCollision; - friend class SHCollisionShapeLibrary; - - public: - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHConvexPolyhedron (SHCollisionShapeID id, Type polyhedronType) noexcept; - SHConvexPolyhedron (const SHConvexPolyhedron& rhs) noexcept; - SHConvexPolyhedron (SHConvexPolyhedron&& rhs) noexcept; - - ~SHConvexPolyhedron () override = default; - - /*---------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*---------------------------------------------------------------------------------*/ - - SHConvexPolyhedron& operator=(const SHConvexPolyhedron& rhs) noexcept; - SHConvexPolyhedron& operator=(SHConvexPolyhedron&& rhs) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - [[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; - - // 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: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - SHHalfEdgeStructure* halfEdgeStructure; // Defines the polyhedron by it's half edges. - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.cpp deleted file mode 100644 index a25b5b8b..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************************** - * \file SHHalfEdgeStructure.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * of DigiPen Institute of Technology is prohibited. -****************************************************************************************/ - -#include - -// Primary Header -#include "SHHalfEdgeStructure.h" - -// Helper Macros - -#define BUILD_UINT64_FROM_UINT32S(a, b) (uint64_t)a << 32 | b - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHHalfEdgeStructure::Face::Face(const Face& rhs) noexcept - : normal { rhs.normal } - { - std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); - } - - SHHalfEdgeStructure::Face::Face(Face&& rhs) noexcept - : normal { rhs.normal } - { - std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices)); - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHHalfEdgeStructure::Face& SHHalfEdgeStructure::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; - } - - SHHalfEdgeStructure::Face& SHHalfEdgeStructure::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 SHHalfEdgeStructure::GetFaceCount() const noexcept - { - return static_cast(faces.size()); - } - - int32_t SHHalfEdgeStructure::GetHalfEdgeCount() const noexcept - { - return static_cast(halfEdges.size()); - } - - 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!"); - - return faces[index]; - } - - 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!"); - - return halfEdges[index]; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHHalfEdgeStructure::AddFace(const Face& face) - { - faces.emplace_back(face); - } - - void SHHalfEdgeStructure::Build() 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) - { - 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].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); - - // 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; - - // Map vertex to this edge index - face.vertexIndices[j].edgeIndex = newHalfEdge.edgeIndex; - } - - // 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); - - // 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/Shapes/SHHalfEdgeStructure.h b/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.h deleted file mode 100644 index 8982ae23..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHHalfEdgeStructure.h +++ /dev/null @@ -1,143 +0,0 @@ -/**************************************************************************************** - * \file SHHalfEdgeStructure.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * 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 SHHalfEdgeStructure - { - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates the data half edge of a face on a polyhedron. - */ - struct HalfEdge - { - /*-------------------------------------------------------------------------------*/ - /* Data Members */ - /*-------------------------------------------------------------------------------*/ - - //Head and tail forms the edge. - //Head <----- Tail - int32_t tailVertexIndex = -1; - - // Head is also tail of the next edge. - int32_t headVertexIndex = -1; - - int32_t edgeIndex = -1; - // Other half of the edge on a different face. - // Important for extrapolating face normals. - int32_t twinEdgeIndex = -1; - - // Adjacent face of this edge. - 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: - /*-------------------------------------------------------------------------------*/ - /* 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 Build() noexcept; - - private: - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - std::vector faces; - std::vector halfEdges; - - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp b/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp deleted file mode 100644 index 5708bf91..00000000 --- a/SHADE_Engine/src/Physics/Collision/Shapes/SHSphere.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/**************************************************************************************** - * \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 "SHSphere.h" - -// Project Headers -#include "Math/SHMathHelpers.h" -#include "Math/SHMatrix.h" -#include "Physics/Collision/SHCollider.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere::SHSphere(SHCollisionShapeID id) noexcept - : SHCollisionShape (id, Type::SPHERE) - , relativeRadius { 1.0f } - , scale { 1.0f } - { - Radius = 0.5f; - } - - SHSphere::SHSphere(const SHSphere& rhs) noexcept - : SHCollisionShape ( rhs ) - , relativeRadius { rhs.relativeRadius } - , scale { rhs.scale } - { - Center = rhs.Center; - Radius = rhs.Radius; - } - - SHSphere::SHSphere(SHSphere&& rhs) noexcept - : SHCollisionShape ( rhs ) - , relativeRadius { rhs.relativeRadius } - , scale { rhs.scale } - { - Center = rhs.Center; - Radius = rhs.Radius; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept - { - if (this == &rhs) - return *this; - - SHCollisionShape::operator=(rhs); - - // Sphere Properties - - Center = rhs.Center; - Radius = rhs.Radius; - - // Local Properties - - relativeRadius = rhs.relativeRadius; - scale = rhs.scale; - - return *this; - } - - SHSphere& SHSphere::operator=(SHSphere&& rhs) noexcept - { - SHCollisionShape::operator=(rhs); - - // Sphere Properties - - Center = rhs.Center; - Radius = rhs.Radius; - - // Local Properties - - relativeRadius = rhs.relativeRadius; - scale = rhs.scale; - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - float SHSphere::GetWorldRadius() const noexcept - { - return Radius; - } - - float SHSphere::GetRelativeRadius() const noexcept - { - return relativeRadius; - } - - SHVec3 SHSphere::GetWorldCentroid() const noexcept - { - return Center; - } - - SHVec3 SHSphere::GetRelativeCentroid() const noexcept - { - if (collider) - return SHVec3{ Center } - collider->GetPosition(); - - return Center; - } - - 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 SHSphere::SetWorldRadius(float newWorldRadius) noexcept - { - Radius = newWorldRadius; - - // Recompute Relative radius - relativeRadius = 2.0f * Radius / scale; - } - - void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept - { - relativeRadius = newRelativeRadius; - - // Recompute world radius - Radius = relativeRadius * scale * 0.5f; - } - - void SHSphere::SetScale(float maxScale) noexcept - { - scale = std::fabs(maxScale); - - // Recompute world radius - Radius = relativeRadius * scale * 0.5f; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHSphere::Update() noexcept - { - 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 = PARENT_TRANSFORM.orientation * transform.orientation; - const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(PARENT_TRANSFORM.position); - - Center = SHVec3::Transform(transform.position, TRS); - } - - bool SHSphere::TestPoint(const SHVec3& point) const noexcept - { - return 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); - result.normal = SHVec3::Normalise(result.position - Center); - } - - return result; - } - - SHMatrix SHSphere::GetTRS() const noexcept - { - const SHQuaternion ROTATION = collider ? collider->GetTransform().orientation * transform.orientation : transform.orientation; - const SHVec3 SCALE { Radius }; - - return SHMatrix::Transform(Center, ROTATION, SCALE); - } - - SHAABB SHSphere::ComputeAABB() const noexcept - { - return SHAABB{ Center, SHVec3{ Radius } }; - } - - -} // 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 deleted file mode 100644 index 04be00b4..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHContactConstraint.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************************** - * \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 - - SHCollisionKey key; - - // 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]; - - uint32_t numContacts = 0; - }; -} // namespace SHADE - diff --git a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h b/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h deleted file mode 100644 index 7c9b6a10..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/Constraints/SHVelocityState.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************************** - * \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 { SHVec3::Zero } - , AngularVelocity { SHVec3::Zero } - , LinearLockFactor { SHVec3::Zero } - , AngularLockFactor { SHVec3::Zero } - { - if (rigidBody) - { - 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 deleted file mode 100644 index 7434953e..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/**************************************************************************************** - * \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" - -// Project Headers -#include "Math/SHMathHelpers.h" -#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Getter Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHContactManager::TriggerEvents& SHContactManager::GetTriggerEvents() const noexcept - { - static TriggerEvents triggerEvents; - - triggerEvents.clear(); - - for (auto& [id, trigger] : triggers) - triggerEvents.emplace_back(SHTriggerEvent{ id, trigger.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; - } - - 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) - { - const ContactInfo INFO - { - .position = manifold.contacts[i].position - , .normal = manifold.normal - }; - - contactPoints.emplace_back(INFO); - } - } - - return contactPoints; - } - - /*-----------------------------------------------------------------------------------*/ - /* 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. - for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) - { - // Test collision of every manifold. - SHManifold& manifold = manifoldPair->second; - SHManifold oldManifold = manifold; - - const bool IS_COLLIDING = SHCollisionDispatcher::Collide(manifold, *manifold.shapeA, *manifold.shapeB); - - auto& collisionState = manifold.state; - updateCollisionState(IS_COLLIDING, collisionState); - - const bool IS_INVALID = collisionState == SHCollisionState::INVALID; - if (IS_INVALID) - { - manifoldPair = manifolds.erase(manifoldPair); - continue; - } - - updateManifold(manifold, oldManifold); - ++manifoldPair; - } - - // Clear expired or invalid triggers, If not, test collision. - for (auto triggerPair = triggers.begin(); triggerPair != triggers.end();) - { - // Test collision of every trigger. - Trigger& oldTrigger = triggerPair->second; - Trigger newTrigger = oldTrigger; - - const bool IS_COLLIDING = SHCollisionDispatcher::Collide(*newTrigger.A, *newTrigger.B); - - auto& collisionState = newTrigger.state; - updateCollisionState(IS_COLLIDING, collisionState); - - const bool IS_INVALID = collisionState == SHCollisionState::INVALID; - if (IS_INVALID) - triggerPair = triggers.erase(triggerPair); - else - ++triggerPair; - } - } - - void SHContactManager::SolveCollisions(int numIterations, float dt) noexcept - { - 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; - - if (bodyA) - { - bodyA->SetLinearVelocity(STATE_A.LinearVelocity); - bodyA->SetAngularVelocity(STATE_A.AngularVelocity); - } - - if (bodyB) - { - bodyB->SetLinearVelocity(STATE_B.LinearVelocity); - bodyB->SetAngularVelocity(STATE_B.AngularVelocity); - } - } - - contactSolver.Reset(); - } - - - /*-----------------------------------------------------------------------------------*/ - /* 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 - { - // 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. - if (state == SHCollisionState::ENTER || state == SHCollisionState::STAY) - state = SHCollisionState::EXIT; - } - } - - 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; - - 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) >= SQRT_ONE_THIRD) - 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) - { - // 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 deleted file mode 100644 index 81f37146..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************************** - * \file SHContactManager.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * 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" -#include "SHContactSolver.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a class that stores collision information. - */ - class SH_API SHContactManager - { - private: - /*---------------------------------------------------------------------------------*/ - /* Friends */ - /*---------------------------------------------------------------------------------*/ - - friend class SHPhysicsWorld; - - public: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - struct ContactInfo - { - SHVec3 position; - SHVec3 normal; - }; - - using TriggerEvents = std::vector; - using CollisionEvents = std::vector; - using ContactPoints = std::vector; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - SHContactManager () noexcept = default; - ~SHContactManager () noexcept = default; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - const TriggerEvents& GetTriggerEvents () const noexcept; - const CollisionEvents& GetCollisionEvents () const noexcept; - const ContactPoints& GetContactPoints () const noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - 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; - - /** - * @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 */ - /*---------------------------------------------------------------------------------*/ - - struct Trigger - { - SHCollisionShape* A = nullptr; - SHCollisionShape* B = nullptr; - - SHCollisionState state = SHCollisionState::INVALID; - }; - - using Manifolds = std::unordered_map; - using Triggers = std::unordered_map; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - Manifolds manifolds; - Triggers triggers; - - SHContactSolver contactSolver; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - static void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; - static void updateManifold (SHManifold& manifold, const SHManifold& oldManifold) noexcept; - - // Removal Helpers - - template - static void removeInvalidObject (std::unordered_map& container, EntityID eid) noexcept; - template - static void removeInvalidObject (std::unordered_map& container, EntityID eid, uint32_t shapeIndex) noexcept; - - }; - - -} // 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 deleted file mode 100644 index 04a4b234..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************************** - * \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::removeInvalidObject(std::unordered_map& container, EntityID eid) noexcept - { - 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::removeInvalidObject(std::unordered_map& container, EntityID eid, uint32_t shapeIndex) noexcept - { - 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/SHContactSolver.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp deleted file mode 100644 index f16d7f1e..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHContactSolver.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/**************************************************************************************** - * \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" -#include "Physics/SHPhysicsConstants.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 SHCollisionKey& key, const SHManifold& manifold) noexcept - { - SHContactConstraint& newConstraint = contactConstraints.emplace(key, SHContactConstraint{}).first->second; - - const auto* SHAPE_A = manifold.shapeA; - const auto* SHAPE_B = manifold.shapeB; - - const auto* BODY_A = manifold.bodyA; - const auto* BODY_B = manifold.bodyB; - - // Add velocities if it doesn't already exist - velocityStates.emplace(key.GetEntityA(), SHVelocityState{ BODY_A }); - velocityStates.emplace(key.GetEntityB(), SHVelocityState{ BODY_B }); - - // Mix friction & restitution - const float FRICTION_A = SHAPE_A->GetFriction(); - const float RESTITUTION_A = SHAPE_A->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); - - // Mass data - - // 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; - - // 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 - - 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::Reset() noexcept - { - velocityStates.clear(); - 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& [key, constraint] : contactConstraints) - { - const float INV_MASS_SUM = constraint.invMassA + constraint.invMassB; - - 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) - { - 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 = 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] = 1.0f / contact.tangentMass[j]; - } - - // Calculate bias per contact - /* - * error bias = baumgarte factor / dt * penetration - * restituion bias = restitution * (relative velocity /dot normal) - */ - - const float ERROR_BIAS = -SHPHYSICS_BAUMGARTE * INV_DT * std::max(0.0f, contact.penetration - SHPHYSICS_LINEAR_SLOP); - - // 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; - - 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; - velocityStateA.AngularVelocity = wA; - velocityStateB.LinearVelocity = vB; - velocityStateB.AngularVelocity = wB; - } - } - - void SHContactSolver::solve() noexcept - { - for (auto& [key, constraint] : contactConstraints) - { - 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) - { - 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; - - // 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) - { - // 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 * LINEAR_LOCK_A; - wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, TANGENT_IMPULSE) * ANGULAR_LOCK_A; - - vB += TANGENT_IMPULSE * constraint.invMassB * LINEAR_LOCK_B; - wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE) * ANGULAR_LOCK_B; - } - } - - velocityStateA.LinearVelocity = vA; - velocityStateA.AngularVelocity = wA; - velocityStateB.LinearVelocity = vB; - velocityStateB.AngularVelocity = wB; - } - } - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp b/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp deleted file mode 100644 index 89c8ad32..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************************** - * \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 = true; - - prevPosition = newPosition; - 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. - // This call should never reach here. - - hasMoved = true; - - prevPosition = position; - 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; - - orientation += orientation * SHQuaternion{ velocity.x, velocity.y, velocity.z, 0.0f } * dt * 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 deleted file mode 100644 index 778e6a8b..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHMotionState.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************************** - * \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/SHQuaternion.h" -#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; - - SHQuaternion orientation; - SHQuaternion prevOrientation; - - /*-----------------------------------------------------------------------------------*/ - /* 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 - * 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 linear velocity to integrate. - * @param dt - * The delta time to integrate with respect to. - */ - 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 - * 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; - - /** - * @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; - - }; - - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp deleted file mode 100644 index ed00e80e..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ /dev/null @@ -1,190 +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 */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept - : settings { worldSettings } - , collisionSpace { nullptr } - { - SHLOG_INFO_D("Creating Physics World") - } - - SHPhysicsWorld::~SHPhysicsWorld() noexcept - { - collisionSpace = nullptr; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - const SHContactManager::ContactPoints& SHPhysicsWorld::GetContactPoints() const noexcept - { - return contactManager.GetContactPoints(); - } - - const SHContactManager::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept - { - return contactManager.GetTriggerEvents(); - } - - const SHContactManager::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept - { - return contactManager.GetCollisionEvents(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsWorld::SetCollisionSpace(SHCollisionSpace* _collisionSpace) noexcept - { - collisionSpace = _collisionSpace; - _collisionSpace->SetContactManager(&contactManager); - } - - /*-----------------------------------------------------------------------------------*/ - /* 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); - - // 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::Step(float dt) - { - /* - * Detect Collisions - */ - - if (collisionSpace) - collisionSpace->DetectCollisions(); - - /* - * Integrate Forces - */ - - for (auto* rigidBody : rigidBodies | std::views::values) - { - if (!rigidBody->IsActive()) - continue; - - rigidBody->ComputeWorldData(); - integrateForces(*rigidBody, dt); - } - - - /* - * Resolve Contacts - */ - - contactManager.SolveCollisions(settings.numVelocitySolverIterations, dt); - - /* - * Integrate Velocities - */ - - for (auto* rigidBody : rigidBodies | std::views::values) - { - if (!rigidBody->IsActive()) - continue; - - 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; - - // 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.angularVelocity *= 1.0f / (1.0f + dt * rigidBody.angularDrag); - - rigidBody.constrainLinearVelocities(); - rigidBody.constrainAngularVelocities(); - } - - void SHPhysicsWorld::integrateVelocities(SHRigidBody& rigidBody, float dt) const noexcept - { - // 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; - } - // Dynamic & Kinematic bodies - // Both dynamic and kinematic can sleep when their velocities are under the thresholds. - else if (!rigidBody.IsSleeping()) - { - rigidBody.constrainLinearVelocities(); - rigidBody.constrainAngularVelocities(); - - rigidBody.motionState.IntegratePosition(rigidBody.linearVelocity, dt); - rigidBody.motionState.IntegrateOrientation(rigidBody.angularVelocity, dt); - - // Sync with collider transforms if a collider is present - if (rigidBody.collider) - { - rigidBody.collider->SetPosition(rigidBody.motionState.position); - rigidBody.collider->SetOrientation(rigidBody.motionState.orientation); - - rigidBody.collider->Update(); - } - } - - // 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/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h deleted file mode 100644 index 9ad525e8..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsWorld.h - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface 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. -****************************************************************************************/ - -#pragma once - -#include - -// Project Headers -#include "Physics/Collision/SHCollisionSpace.h" -#include "SHContactManager.h" -#include "SHContactSolver.h" -#include "SHRigidBody.h" - - -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 */ - /*---------------------------------------------------------------------------------*/ - - struct WorldSettings - { - public: - /*-------------------------------------------------------------------------------*/ - /* Data Members */ - /*-------------------------------------------------------------------------------*/ - - SHVec3 gravity = SHVec3{ 0.0f, -9.81f, 0.0f }; - uint16_t numVelocitySolverIterations = 10; - uint16_t numPositionSolverIterations = 5; // Unused until PGS is implemented - bool sleepingEnabled = true; - }; - - /*---------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*---------------------------------------------------------------------------------*/ - - 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; - - /*---------------------------------------------------------------------------------*/ - /* Getter Functions */ - /*---------------------------------------------------------------------------------*/ - - const SHContactManager::ContactPoints& GetContactPoints () const noexcept; - const SHContactManager::TriggerEvents& GetTriggerEvents () const noexcept; - const SHContactManager::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; - - /** - * @brief - * 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 deterministic - * behaviour. - */ - void Step (float dt); - - private: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - // EntityIDs are used to map resolved constraints back to bodies - using RigidBodies = std::unordered_map; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - WorldSettings settings; - SHCollisionSpace* collisionSpace; - - RigidBodies rigidBodies; - SHContactManager contactManager; - SHContactSolver contactSolver; - - /*---------------------------------------------------------------------------------*/ - /* Function Members */ - /*---------------------------------------------------------------------------------*/ - - // 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; - }; - - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp b/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp deleted file mode 100644 index bdaaf230..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.cpp +++ /dev/null @@ -1,765 +0,0 @@ -/**************************************************************************************** - * \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" - -// Project Headers -#include -#include - -#include "Physics/Collision/SHCollider.h" -#include "Tools/Logger/SHLogger.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHRigidBody::SHRigidBody(EntityID eid, Type type) noexcept - : entityID { eid } - , collider { nullptr } - , bodyType { type } - , gravityScale { 1.0f } - , invMass { type == Type::DYNAMIC ? 1.0f : 0.0f } - , linearDrag { 0.01f } - , angularDrag { 0.01f } - , 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 } - , 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. - } - - 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 } - , 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. - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHRigidBody& SHRigidBody::operator=(const SHRigidBody& rhs) noexcept - { - // Handle self assignment - if (this == &rhs) - return *this; - - 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; - 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; - - return *this; - } - - 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; - 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; - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Getter Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHRigidBody::Type SHRigidBody::GetType() const noexcept - { - return bodyType; - } - - float SHRigidBody::GetGravityScale() const noexcept - { - return gravityScale; - } - - float SHRigidBody::GetMass() const noexcept - { - return 1.0f/ invMass; - } - - float SHRigidBody::GetLinearDrag() const noexcept - { - return linearDrag; - } - - float SHRigidBody::GetAngularDrag() const noexcept - { - return angularDrag; - } - - 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 - { - // Check if linear velocity needs to be constrained - - 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::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; - 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); - } - - SHMotionState& SHRigidBody::GetMotionState() noexcept - { - return motionState; - } - - /*-----------------------------------------------------------------------------------*/ - /* Setter Functions Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHRigidBody::SetCollider(SHCollider* c) noexcept - { - collider = c; - } - - void SHRigidBody::SetType(Type newType) noexcept - { - if (newType == bodyType) - return; - - bodyType = newType; - - 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 - { - gravityScale = newGravityScale; - } - - void SHRigidBody::SetMass(float newMass) noexcept - { - if (bodyType != Type::DYNAMIC) - { - invMass = 0.0f; - 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; - - // Turn off automass - static constexpr unsigned int AUTO_MASS_FLAG = 4; - static constexpr uint16_t VALUE = 1U << AUTO_MASS_FLAG; - - flags &= ~(VALUE); - ComputeMassData(); - } - - 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::SetAngularDrag(float newAngularDrag) noexcept - { - 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; - constrainLinearVelocities(); - } - - 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; - constrainAngularVelocities(); - } - - 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; - - if (isSleeping) - { - flags |= VALUE; - - ClearForces(); - linearVelocity = SHVec3::Zero; - angularVelocity = SHVec3::Zero; - } - else - { - 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; - } - else - { - flags &= ~VALUE; - // 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 - { - 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; - // Set inertia tensor on the x-axis to 0 - localInvInertia.m[0][0] = 0.0f; - } - else - { - flags &= ~VALUE; - ComputeMassData(); - } - } - - 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; - // Set inertia tensor on the y-axis to 0 - localInvInertia.m[1][1] = 0.0f; - } - else - { - flags &= ~VALUE; - ComputeMassData(); - } - } - - 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; - // Set inertia tensor on the z-axis to 0 - localInvInertia.m[2][2] = 0.0f; - } - else - { - flags &= ~VALUE; - ComputeMassData(); - } - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Function Definition */ - /*-----------------------------------------------------------------------------------*/ - - void SHRigidBody::AddForce(const SHVec3& force, const SHVec3& pos) noexcept - { - if (bodyType != Type::DYNAMIC) - return; - - accumulatedForce += force; - accumulatedTorque += SHVec3::Cross(pos, force); - } - - void SHRigidBody::AddImpulse(const SHVec3& impulse, const SHVec3& pos) noexcept - { - if (bodyType != Type::DYNAMIC) - return; - - 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; - accumulatedTorque = SHVec3::Zero; - } - - 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::DYNAMIC) - return; - - // Compute world inertia - worldInvInertia = R * (localInvInertia * RT); - } - - void SHRigidBody::ComputeMassData() noexcept - { - // 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(); - - - // Compute Total mass and store individual masses if custom mass is being used. - // Compute local centroid at the same time - - // Zero matrix; - SHMatrix J = SHMatrix::Zero; - - float totalMass = 0.0f; - 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; - - // 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->GetRelativeCentroid(); - } - - 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); - - // 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) - { - 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 - // R * I * RT = R * (I * RT) - SHMatrix I = SHAPE->GetInertiaTensor( actualMass ) * RT; - 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->GetWorldCentroid() - worldCentroid; - const float R_MAG2 = R.LengthSquared(); - const SHMatrix R_OX_R = SHVec3::OuterProduct(R, R); - - J += I + actualMass * (SHMatrix::Identity * R_MAG2 - R_OX_R); - } - - // Set diagonals then invert - 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); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Member Function Definition */ - /*-----------------------------------------------------------------------------------*/ - - 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 deleted file mode 100644 index 3c869ad2..00000000 --- a/SHADE_Engine/src/Physics/Dynamics/SHRigidBody.h +++ /dev/null @@ -1,268 +0,0 @@ -/**************************************************************************************** - * \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/Entity/SHEntity.h" -#include "Math/SHMatrix.h" -#include "Math/Vector/SHVec3.h" -#include "SHMotionState.h" - -namespace SHADE -{ - /*-------------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-------------------------------------------------------------------------------------*/ - - class SHCollider; - - /*-------------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-------------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a Rigid Body used in Physics Simulations - */ - class SH_API SHRigidBody - { - private: - /*-----------------------------------------------------------------------------------*/ - /* Friends */ - /*-----------------------------------------------------------------------------------*/ - - friend class SHPhysicsWorld; - friend class SHContactSolver; - - 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 GetGravityScale () 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; - - // 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 IsTriggerInMassData () 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; - - [[nodiscard]] SHMotionState& GetMotionState () noexcept; - - /*-----------------------------------------------------------------------------------*/ - /* Setter Functions */ - /*-----------------------------------------------------------------------------------*/ - - void SetCollider (SHCollider* c) noexcept; - - /** - * @brief - * Changing the type from non-Dynamic to Dynamic will set the default - * mass and drag values. - */ - void SetType (Type newType) noexcept; - - void SetGravityScale (float newGravityScale) 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; - - /** - * @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 SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; - void SetAngularVelocity (const SHVec3& newAngularVelocity)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 SetTriggerInMassData(bool triggerInMassData) 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.
- * 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; - - /** - * @brief - * 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; - - /** - * @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; - - /** - * @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: - /*-----------------------------------------------------------------------------------*/ - /* Data Members */ - /*-----------------------------------------------------------------------------------*/ - - // The entityID here is only meant for linking with the actual component in the engine. - EntityID entityID; - SHCollider* collider; - - Type bodyType; - - float gravityScale; - - float invMass; - float linearDrag; - float angularDrag; - - SHMatrix localInvInertia; - SHMatrix worldInvInertia; - - SHVec3 localCentroid; - SHVec3 worldCentroid; - - SHVec3 accumulatedForce; - SHVec3 accumulatedTorque; - - SHVec3 linearVelocity; - SHVec3 angularVelocity; - - // aZ aY aX pZ pY pX 0 0 0 addTriggersToMassData inIsland autoMass enableGravity enableSleeping sleeping active - uint16_t flags; - - SHMotionState motionState; - - /*-----------------------------------------------------------------------------------*/ - /* Member Functions */ - /*-----------------------------------------------------------------------------------*/ - - void constrainLinearVelocities () noexcept; - void constrainAngularVelocities () noexcept; - - }; - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp deleted file mode 100644 index 2353e3f3..00000000 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.cpp +++ /dev/null @@ -1,163 +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" - -#include "Physics/Collision/SHCollider.h" -#include "Physics/Collision/SHCompositeCollider.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructor & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject::SHPhysicsObject(EntityID eid) noexcept - : entityID { eid } - {} - - SHPhysicsObject::SHPhysicsObject(const SHPhysicsObject& rhs) noexcept - : entityID { rhs.entityID } - { - deepCopyComponents(rhs.rigidBody, rhs.collider); - } - - SHPhysicsObject::SHPhysicsObject(SHPhysicsObject&& rhs) noexcept - : entityID { rhs.entityID } - { - deepCopyComponents(rhs.rigidBody, rhs.collider); - } - - SHPhysicsObject::~SHPhysicsObject() noexcept - { - entityID = MAX_EID; - - delete rigidBody; - rigidBody = nullptr; - - delete collider; - collider = nullptr; - } - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject& SHPhysicsObject::operator=(const SHPhysicsObject& rhs) noexcept - { - if (this == &rhs) - return *this; - - entityID = rhs.entityID; - - deepCopyComponents(rhs.rigidBody, rhs.collider); - - return *this; - } - - SHPhysicsObject& SHPhysicsObject::operator=(SHPhysicsObject&& rhs) noexcept - { - entityID = rhs.entityID; - - deepCopyComponents(rhs.rigidBody, rhs.collider); - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ - /* Public Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - bool SHPhysicsObject::IsEmpty() const noexcept - { - 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); - rigidBody->SetCollider(collider); - } - - rigidBody->ComputeMassData(); - return rigidBody; - } - - void SHPhysicsObject::DestroyRigidBody() noexcept - { - delete rigidBody; - rigidBody = nullptr; - - // Unlink with collider - if (collider) - collider->SetRigidBody(nullptr); - } - - SHCollider* SHPhysicsObject::CreateCompositeCollider(const SHTransform& transform) - { - if (collider) - { - SHLOG_INFO_D("Collider for Entity {} has already been created!", entityID) - return collider; - } - - collider = new SHCompositeCollider{ entityID, transform }; - - // Link with rigidBody if it exists - if (rigidBody) - { - rigidBody->SetCollider(collider); - collider->SetRigidBody(rigidBody); - } - - return collider; - } - - void SHPhysicsObject::DestroyCollider() noexcept - { - delete collider; - collider = nullptr; - - // Unlink with rigid body - if (rigidBody) - { - rigidBody->SetCollider(nullptr); - rigidBody->ComputeMassData(); - } - } - - /*-----------------------------------------------------------------------------------*/ - /* 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 deleted file mode 100644 index 9736f8d0..00000000 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObject.h +++ /dev/null @@ -1,109 +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 - -// Project Headers -#include "Physics/Collision/SHCollider.h" -#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; - SHCollider* collider = 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; - - /*-----------------------------------------------------------------------------------*/ - /* Member Functions */ - /*-----------------------------------------------------------------------------------*/ - - /** - * @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* CreateCompositeCollider (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 deleted file mode 100644 index 956f8078..00000000 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.cpp +++ /dev/null @@ -1,178 +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 "Math/Transform/SHTransformComponent.h" -#include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" -#include "Tools/Utilities/SHUtilities.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObjectManager::~SHPhysicsObjectManager() noexcept - { - RemoveAllObjects(); - } - - /*-----------------------------------------------------------------------------------*/ - /* 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 = ensurePhysicsObject(entityID); - - // Get the component - auto* rigidBodyComponent = SHComponentManager::GetComponent(entityID); - - // Create a new rigidbody in the physics object - const auto RIGID_BODY_TYPE = static_cast(rigidBodyComponent->GetType()); - auto* rigidBody = physicsObject->CreateRigidBody(RIGID_BODY_TYPE); - - SHVec3 worldPos = SHVec3::Zero; - 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); - } - - void SHPhysicsObjectManager::RemoveRigidBody(EntityID entityID) noexcept - { - const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); - if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end()) - return; - - SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; - - physicsObject->DestroyRigidBody(); - - // Destroy empty physics objects - if (physicsObject->IsEmpty()) - destroyPhysicsObject(entityID); - } - - void SHPhysicsObjectManager::AddCollider(EntityID entityID, SHCollider::Type type) noexcept - { - SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID); - - // 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 - if (type == SHCollider::Type::COMPOSITE) - physicsObject->CreateCompositeCollider(worldTransform); - - // TODO: Hull collider - - physicsObject->collider->SetLibrary(&shapeLibrary); - - // Link with the component - colliderComponent->SetCollider(dynamic_cast(physicsObject->collider)); - } - - void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept - { - const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID); - if (PHYSICS_OBJECT_ITERATOR != physicsObjects.end()) - { - SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second; - - physicsObject->DestroyCollider(); - - // Destroy empty physics objects - if (physicsObject->IsEmpty()) - destroyPhysicsObject(entityID); - } - } - - void SHPhysicsObjectManager::RemoveAllObjects() noexcept - { - // Physics objects itself will delete the object - physicsObjects.clear(); - } - - /*-----------------------------------------------------------------------------------*/ - /* Private Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID entityID) - { - const auto& NEW_OBJECT = physicsObjects.emplace(entityID, SHPhysicsObject{entityID}).first; - 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); - } - -} // 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 deleted file mode 100644 index 8b4e79c1..00000000 --- a/SHADE_Engine/src/Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h +++ /dev/null @@ -1,116 +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 - -// Project Headers -#include "SHPhysicsObject.h" -#include "Physics/Collision/Shapes/SHCollisionShapeLibrary.h" - -namespace SHADE -{ - /*-------------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-------------------------------------------------------------------------------------*/ - - /** - * @brief - * Encapsulates a manager for physics objects that links raw physics components with the - * engine's components. - */ - class SH_API SHPhysicsObjectManager - { - private: - /*-----------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*-----------------------------------------------------------------------------------*/ - - using EntityObjectMap = std::unordered_map; - - public: - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsObjectManager () noexcept = default; - ~SHPhysicsObjectManager () noexcept; - - /*-----------------------------------------------------------------------------------*/ - /* 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 composite collider and links it with the collider component. - * @param entityID - * The entity to link the new collider to. - */ - void AddCollider (EntityID entityID, SHCollider::Type type) noexcept; - - /** - * @brief - * 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 - * 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 */ - /*-----------------------------------------------------------------------------------*/ - - EntityObjectMap physicsObjects; - SHCollisionShapeLibrary shapeLibrary; - - /*-----------------------------------------------------------------------------------*/ - /* 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 a36fb730..d7db2c64 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.cpp @@ -13,6 +13,11 @@ // Primary Header #include "SHColliderComponent.h" +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/SHMathHelpers.h" +#include "Physics/System/SHPhysicsSystem.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -20,58 +25,185 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHColliderComponent::SHColliderComponent() noexcept - : collider { nullptr } + : system { nullptr } {} /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCompositeCollider* const SHColliderComponent::GetCollider() const noexcept + + const SHVec3& SHColliderComponent::GetPosition() const noexcept { - return collider; + return position; } - const SHCollider::CollisionShapes* const SHColliderComponent::GetCollisionShapes() const noexcept + const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept { - if (!collider) - return nullptr; - - return &collider->GetCollisionShapes(); + return orientation; } - - SHCollisionShape* const SHColliderComponent::GetCollisionShape(int index) const + SHVec3 SHColliderComponent::GetRotation() const noexcept { - if (!collider) - return nullptr; - - return collider->GetCollisionShape(index); + return orientation.ToEuler(); } - bool SHColliderComponent::GetDebugDrawState() const noexcept + const SHVec3& SHColliderComponent::GetScale() const noexcept { - if (!collider) - return false; - - return collider->GetDebugDrawState(); + return scale; } - + + const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept + { + return collisionShapes; + } + + SHCollisionShape& SHColliderComponent::GetCollisionShape(int index) + { + if (index < 0 || static_cast(index) >= collisionShapes.size()) + throw std::invalid_argument("Out-of-range access!"); + + return collisionShapes[index]; + } + /*-----------------------------------------------------------------------------------*/ - /* Setter Function Definitions */ + /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHColliderComponent::SetCollider(SHCompositeCollider* c) noexcept + void SHColliderComponent::OnCreate() { - collider = c; + 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::SetDebugDrawState(bool state) noexcept + void SHColliderComponent::OnDestroy() { - if (collider) - collider->SetDebugDrawState(state); + } + 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; + } + + 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; + } + + 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 @@ -80,6 +212,5 @@ RTTR_REGISTRATION using namespace rttr; using namespace SHADE; - registration::class_("Collider Component") - .property("Is Debug Drawing", &SHColliderComponent::GetDebugDrawState, &SHColliderComponent::SetDebugDrawState); -} \ No newline at end of file + registration::class_("Collider Component"); +} \ 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 39552949..0781f3cf 100644 --- a/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHColliderComponent.h @@ -14,7 +14,14 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" -#include "Physics/Collision/SHCompositeCollider.h" +#include "Math/Geometry/SHBox.h" +#include "Math/Geometry/SHSphere.h" +#include "SHCollisionShape.h" + +//namespace SHADE +//{ +// class SHPhysicsSystem; +//} namespace SHADE { @@ -30,7 +37,13 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; - friend struct SHPhysicsObject; + friend class SHPhysicsObject; + + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using CollisionShapes = std::vector; public: @@ -54,30 +67,42 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHCompositeCollider* const GetCollider () const noexcept; - [[nodiscard]] const SHCollider::CollisionShapes* const GetCollisionShapes() const noexcept; - [[nodiscard]] SHCollisionShape* const GetCollisionShape (int index) const; + [[nodiscard]] bool HasChanged () const noexcept; - // Required for serialisation + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; + [[nodiscard]] const SHVec3& GetScale () const noexcept; - [[nodiscard]] bool GetDebugDrawState () const noexcept; + [[nodiscard]] const CollisionShapes& GetCollisionShapes() const noexcept; + [[nodiscard]] SHCollisionShape& GetCollisionShape (int index); /*---------------------------------------------------------------------------------*/ - /* Setter Functions */ + /* Function Members */ /*---------------------------------------------------------------------------------*/ - void SetCollider (SHCompositeCollider* c) noexcept; + void OnCreate () override; + void OnDestroy () override; - // Required for serialisation + void RecomputeCollisionShapes () noexcept; - void SetDebugDrawState (bool state) 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; private: + /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - SHCompositeCollider* collider; + SHPhysicsSystem* system; + + SHVec3 position; + SHQuaternion orientation; + SHVec3 scale; + CollisionShapes collisionShapes; RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp new file mode 100644 index 00000000..f597077f --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.cpp @@ -0,0 +1,368 @@ +/**************************************************************************************** + * \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/SHCollisionShape.h b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h new file mode 100644 index 00000000..597814a6 --- /dev/null +++ b/SHADE_Engine/src/Physics/Interface/SHCollisionShape.h @@ -0,0 +1,134 @@ +/**************************************************************************************** + * \file SHCollider.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface 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. +****************************************************************************************/ + +#pragma once + +#include + +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" +#include "Math/Geometry/SHShape.h" +#include "Math/SHQuaternion.h" +#include "SHPhysicsMaterial.h" +#include "Physics/Collision/SHCollisionTags.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHCollisionShape + { + private: + + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHColliderComponent; + friend class SHPhysicsObject; + + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Type + { + BOX + , SPHERE + , CAPSULE + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShape (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT); + + SHCollisionShape (const SHCollisionShape& rhs) noexcept; + SHCollisionShape (SHCollisionShape&& rhs) noexcept; + ~SHCollisionShape () noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept; + SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] bool HasChanged () const noexcept; + + [[nodiscard]] bool IsTrigger () const noexcept; + + [[nodiscard]] Type GetType () const noexcept; + + [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; + + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; + + [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; + [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; + + [[nodiscard]] const SHShape* GetShape () 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; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Type type; + EntityID entityID; // The entity this collider belongs to + bool isTrigger; + bool dirty; + + SHShape* shape; + SHPhysicsMaterial material; + + SHVec3 positionOffset; + SHVec3 rotationOffset; + + SHCollisionTag* collisionTag; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void CopyShape(const SHShape* rhs); + + RTTR_ENABLE() + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.cpp b/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp similarity index 100% rename from SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.cpp rename to SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.cpp diff --git a/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h similarity index 98% rename from SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h rename to SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h index 773ac4c1..b3db1655 100644 --- a/SHADE_Engine/src/Physics/Collision/SHPhysicsMaterial.h +++ b/SHADE_Engine/src/Physics/Interface/SHPhysicsMaterial.h @@ -19,10 +19,6 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates the data of a physics material for physics simulations. - */ class SH_API SHPhysicsMaterial { public: diff --git a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp index 04bb5b6b..330c3abe 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.cpp @@ -10,9 +10,17 @@ #include +// External Dependencies +#include + // Primary Header #include "SHRigidBodyComponent.h" +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/SHMathHelpers.h" +#include "Physics/System/SHPhysicsSystem.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -21,318 +29,382 @@ namespace SHADE SHRigidBodyComponent::SHRigidBodyComponent() noexcept : type { Type::DYNAMIC } - , interpolate { true } - , rigidBody { nullptr } - {} + , 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 + } /*-----------------------------------------------------------------------------------*/ - /* Getter Functions Definitions */ + /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + bool SHRigidBodyComponent::IsGravityEnabled() const noexcept + { + static constexpr int FLAG_POS = 0; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept + { + static constexpr int FLAG_POS = 1; + return flags & (1U << FLAG_POS); + } + + bool SHRigidBodyComponent::IsInterpolating() const noexcept + { + static constexpr int FLAG_POS = 8; + return flags & (1U << FLAG_POS); + } + + 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; } - bool SHRigidBodyComponent::IsGravityEnabled() const noexcept - { - return rigidBody ? rigidBody->IsGravityEnabled() : false; - } - - bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept - { - return rigidBody ? rigidBody->IsSleepingEnabled() : false; - } - - bool SHRigidBodyComponent::IsInterpolating() const noexcept - { - return interpolate; - } - - bool SHRigidBodyComponent::IsSleeping() const noexcept - { - return rigidBody ? rigidBody->IsSleeping() : false; - } - - bool SHRigidBodyComponent::GetAutoMass() const noexcept - { - return rigidBody ? rigidBody->IsAutoMassEnabled() : false; - } - bool SHRigidBodyComponent::GetFreezePositionX() const noexcept { - return rigidBody ? rigidBody->GetFreezePositionX() : false; + static constexpr int FLAG_POS = 2; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezePositionY() const noexcept { - return rigidBody ? rigidBody->GetFreezePositionY() : false; + static constexpr int FLAG_POS = 3; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept { - return rigidBody ? rigidBody->GetFreezePositionZ() : false; + static constexpr int FLAG_POS = 4; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept { - return rigidBody ? rigidBody->GetFreezeRotationX() : false; + static constexpr int FLAG_POS = 5; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept { - return rigidBody ? rigidBody->GetFreezeRotationY() : false; + static constexpr int FLAG_POS = 6; + return flags & (1U << FLAG_POS); } bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept { - return rigidBody ? rigidBody->GetFreezeRotationZ() : false; + static constexpr int FLAG_POS = 7; + return flags & (1U << FLAG_POS); } - float SHRigidBodyComponent::GetGravityScale() const noexcept - { - return rigidBody ? rigidBody->GetGravityScale() : 0.0f; - } + //bool SHRigidBodyComponent::GetAutoMass() const noexcept + //{ + // static constexpr int FLAG_POS = 9; + // return flags & (1U << FLAG_POS); + //} - float SHRigidBodyComponent::GetMass() const noexcept + float SHRigidBodyComponent::GetMass() const noexcept { - return rigidBody ? rigidBody->GetMass() : -1.0f; + return mass; } float SHRigidBodyComponent::GetDrag() const noexcept { - return rigidBody ? rigidBody->GetLinearDrag() : -1.0f; + return drag; } float SHRigidBodyComponent::GetAngularDrag() const noexcept { - return rigidBody ? rigidBody->GetAngularDrag() : -1.0f; + return angularDrag; } SHVec3 SHRigidBodyComponent::GetForce() const noexcept { - return rigidBody ? rigidBody->GetForce() : SHVec3::Zero; + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getForce(); + + return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetTorque() const noexcept { - return rigidBody ? rigidBody->GetTorque() : SHVec3::Zero; + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getTorque(); + + return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept { - return rigidBody ? rigidBody->GetLinearVelocity() : SHVec3::Zero; + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getLinearVelocity(); + + return SHVec3::Zero; } SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept { - return rigidBody ? rigidBody->GetAngularVelocity() : SHVec3::Zero; + if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) + return physicsObject->GetRigidBody()->getAngularVelocity(); + + return SHVec3::Zero; } - SHVec3 SHRigidBodyComponent::GetPosition() const noexcept + const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept { - return rigidBody ? rigidBody->GetMotionState().position : SHVec3::Zero; + return position; + } + + const SHQuaternion& SHRigidBodyComponent::GetOrientation() const noexcept + { + return orientation; } SHVec3 SHRigidBodyComponent::GetRotation() const noexcept { - return rigidBody ? rigidBody->GetMotionState().orientation.ToEuler() : SHVec3::Zero; + return orientation.ToEuler(); } /*-----------------------------------------------------------------------------------*/ - /* Setter Functions Definitions */ + /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ void SHRigidBodyComponent::SetType(Type newType) noexcept { - if (newType == type) + static constexpr int FLAG_POS = 8; + + if (type == newType) return; type = newType; - - if (rigidBody) - rigidBody->SetType(static_cast(newType)); + dirtyFlags |= 1U << FLAG_POS; } - void SHRigidBodyComponent::SetRigidBody(SHRigidBody* rb) noexcept + void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept { - rigidBody = rb; - } + static constexpr int FLAG_POS = 0; - void SHRigidBodyComponent::SetIsGravityEnabled(bool enableGravity) noexcept - { - if (rigidBody) - rigidBody->SetGravityEnabled(enableGravity); + 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 { - if (rigidBody) - rigidBody->SetSleepingEnabled(isAllowedToSleep); - } + static constexpr int FLAG_POS = 1; - void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept - { - if (rigidBody) - rigidBody->SetAutoMassEnabled(autoMass); + 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 { - if (rigidBody) - rigidBody->SetFreezePositionX(freezePositionX); + 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 { - if (rigidBody) - rigidBody->SetFreezePositionY(freezePositionY); + 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 { - if (rigidBody) - rigidBody->SetFreezePositionZ(freezePositionZ); + 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 { - if (rigidBody) - rigidBody->SetFreezeRotationX(freezeRotationX); + 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 { - if (rigidBody) - rigidBody->SetFreezeRotationY(freezeRotationY); + 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 { - if (rigidBody) - rigidBody->SetFreezeRotationZ(freezeRotationZ); + 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 { - interpolate = allowInterpolation; + static constexpr int FLAG_POS = 8; + allowInterpolation ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); } - void SHRigidBodyComponent::SetGravityScale(float gravityScale) noexcept - { - if (rigidBody) - rigidBody->SetGravityScale(gravityScale); - } + //void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept + //{ + // static constexpr int FLAG_POS = 9; + // autoMass ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS); - void SHRigidBodyComponent::SetMass(float newMass) noexcept - { - if (rigidBody) - rigidBody->SetMass(newMass); - } + // 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 { - if (rigidBody) - rigidBody->SetLinearDrag(newDrag); + 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 { - if (rigidBody) - rigidBody->SetAngularDrag(newAngularDrag); + 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 (rigidBody) - rigidBody->SetLinearVelocity(newLinearVelocity); + + 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 { - if (rigidBody) - rigidBody->SetAngularVelocity(newAngularVelocity); - } + static constexpr int FLAG_POS = 13; - /*-----------------------------------------------------------------------------------*/ - /* Member Function Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept - { - if (rigidBody) - rigidBody->AddForce(force); - } - - 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) + if (type == Type::STATIC) { - // Convert world pos into local space of the body - const SHVec3 LOCAL_POS = worldPos - rigidBody->GetWorldCentroid(); - rigidBody->AddForce(force, LOCAL_POS); + SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID()) + return; } - } - void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept - { - if (rigidBody) + auto* physicsObject = system->GetPhysicsObject(GetEID()); + if (!physicsObject) { - // Rotate force into world space - const SHVec3 FORCE = SHVec3::Rotate(relativeForce, rigidBody->GetMotionState().orientation); - rigidBody->AddForce(FORCE); + SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID()) + return; } - } - - 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 - { - if (rigidBody) - rigidBody->ClearForces(); + physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity); } /*-----------------------------------------------------------------------------------*/ @@ -341,7 +413,81 @@ 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 @@ -359,19 +505,18 @@ RTTR_REGISTRATION ); registration::class_("RigidBody Component") - .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 ); + .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("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 ) + .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/SHRigidBodyComponent.h index 1173c1d5..532b3312 100644 --- a/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Interface/SHRigidBodyComponent.h @@ -15,7 +15,7 @@ // Project Headers #include "ECS_Base/Components/SHComponent.h" #include "Math/Vector/SHVec3.h" -#include "Physics/Dynamics/SHRigidBody.h" +#include "Math/SHQuaternion.h" namespace SHADE { @@ -31,7 +31,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ friend class SHPhysicsSystem; - friend struct SHPhysicsObject; + friend class SHPhysicsObject; public: /*---------------------------------------------------------------------------------*/ @@ -67,13 +67,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 IsSleeping () const noexcept; - [[nodiscard]] bool GetAutoMass () const noexcept; + + [[nodiscard]] bool GetIsSleeping () const noexcept; + + [[nodiscard]] Type GetType () const noexcept; [[nodiscard]] bool GetFreezePositionX () const noexcept; [[nodiscard]] bool GetFreezePositionY () const noexcept; @@ -82,7 +82,8 @@ namespace SHADE [[nodiscard]] bool GetFreezeRotationY () const noexcept; [[nodiscard]] bool GetFreezeRotationZ () const noexcept; - [[nodiscard]] float GetGravityScale () const noexcept; + //[[nodiscard]] bool GetAutoMass () const noexcept; + [[nodiscard]] float GetMass () const noexcept; [[nodiscard]] float GetDrag () const noexcept; [[nodiscard]] float GetAngularDrag () const noexcept; @@ -92,7 +93,8 @@ namespace SHADE [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; - [[nodiscard]] SHVec3 GetPosition () const noexcept; + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; [[nodiscard]] SHVec3 GetRotation () const noexcept; /*---------------------------------------------------------------------------------*/ @@ -101,12 +103,8 @@ namespace SHADE void SetType (Type newType) noexcept; - void SetRigidBody (SHRigidBody* rb) noexcept; - - void SetIsGravityEnabled (bool enableGravity) noexcept; + void SetGravityEnabled (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; @@ -114,9 +112,9 @@ namespace SHADE void SetFreezeRotationY (bool freezeRotationY) noexcept; void SetFreezeRotationZ (bool freezeRotationZ) noexcept; void SetInterpolate (bool allowInterpolation) noexcept; + //void SetAutoMass (bool autoMass) noexcept; - void SetGravityScale (float gravityScale) noexcept; - void SetMass (float newMass) noexcept; + //void SetMass (float newMass) noexcept; void SetDrag (float newDrag) noexcept; void SetAngularDrag (float newAngularDrag) noexcept; @@ -139,17 +137,33 @@ namespace SHADE void AddRelativeTorque (const SHVec3& relativeTorque) const noexcept; void ClearForces () const noexcept; + void ClearTorque () const noexcept; private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; - bool interpolate; - SHRigidBody* rigidBody; + 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 new file mode 100644 index 00000000..71b08831 --- /dev/null +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.cpp @@ -0,0 +1,431 @@ +/**************************************************************************************** + * \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/Collision/Contacts/SHCollisionKey.h b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h similarity index 51% rename from SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.h rename to SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h index 811f8375..c572ca2e 100644 --- a/SHADE_Engine/src/Physics/Collision/Contacts/SHCollisionKey.h +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObject.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollisionID.h + * \file SHPhysicsObject.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for Collision Information for Collision & Triggers. + * \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 @@ -10,108 +10,102 @@ #pragma once -// Project Headers -#include "Physics/Interface/SHColliderComponent.h" -#include "Physics/Interface/SHRigidBodyComponent.h" +#include +// Project Headers +#include "Math/Transform/SHTransformComponent.h" +#include "Physics/Interface/SHRigidBodyComponent.h" +#include "Physics/Interface/SHColliderComponent.h" namespace SHADE { - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - struct SHCollisionKeyHash; - /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates the information when two collision shapes intersect. - */ - class SH_API SHCollisionKey + class SH_API SHPhysicsObject { private: /*---------------------------------------------------------------------------------*/ /* Friends */ /*---------------------------------------------------------------------------------*/ - friend struct SHCollisionKeyHash; + friend class SHPhysicsSystem; + friend class SHPhysicsObjectManager; public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollisionKey () noexcept; - SHCollisionKey (const SHCollisionKey& rhs) noexcept; - SHCollisionKey (SHCollisionKey&& rhs) noexcept; - - ~SHCollisionKey () noexcept = default; + 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 */ /*---------------------------------------------------------------------------------*/ - - SHCollisionKey& operator= (const SHCollisionKey& rhs) noexcept; - SHCollisionKey& operator= (SHCollisionKey&& rhs) noexcept; - - bool operator==(const SHCollisionKey& rhs) const; + + SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept = default; + SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept = default; /*---------------------------------------------------------------------------------*/ /* 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; + [[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 SetEntityA (EntityID entityID) noexcept; - void SetEntityB (EntityID entityID) noexcept; - void SetCollisionShapeA (uint32_t shapeIndexA) noexcept; - void SetCollisionShapeB (uint32_t shapeIndexB) noexcept; + 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: - - 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 - }; - }; + 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 - /** - * @brief - * Encapsulates a functor to hash a CollisionKey - */ - struct SHCollisionKeyHash - { - public: /*---------------------------------------------------------------------------------*/ - /* Member Functions */ + /* Function Members */ /*---------------------------------------------------------------------------------*/ - std::size_t operator()(const SHCollisionKey& id) const; - }; + 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 new file mode 100644 index 00000000..7c111a2d --- /dev/null +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.cpp @@ -0,0 +1,309 @@ +/**************************************************************************************** + * \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 new file mode 100644 index 00000000..f41c62ad --- /dev/null +++ b/SHADE_Engine/src/Physics/PhysicsObject/SHPhysicsObjectManager.h @@ -0,0 +1,181 @@ +/**************************************************************************************** + * \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/SHPhysicsConstants.h b/SHADE_Engine/src/Physics/SHPhysicsConstants.h deleted file mode 100644 index b680515e..00000000 --- a/SHADE_Engine/src/Physics/SHPhysicsConstants.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************************** - * \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.01f * 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; - - /** - * @brief - * Distance threshold to consider two contacts as the same. - */ - static constexpr float SHPHYSICS_SAME_CONTACT_DISTANCE = 0.01; - -} diff --git a/SHADE_Engine/src/Physics/SHPhysicsEvents.h b/SHADE_Engine/src/Physics/SHPhysicsEvents.h index a192ec3f..ae48a75b 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsEvents.h +++ b/SHADE_Engine/src/Physics/SHPhysicsEvents.h @@ -11,7 +11,8 @@ #pragma once // Project Headers -#include "Collision/Shapes/SHCollisionShape.h" +#include "Interface/SHCollisionShape.h" + namespace SHADE { @@ -27,16 +28,9 @@ namespace SHADE }; struct SHPhysicsColliderRemovedEvent - { - EntityID entityID; - SHCollisionShape::Type colliderType; - int colliderIndex; - }; - - struct SHColliderOnDebugDrawEvent { EntityID entityID; - bool debugDrawState; + int colliderIndex; }; diff --git a/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp new file mode 100644 index 00000000..85e76702 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsWorld.cpp @@ -0,0 +1,71 @@ +/**************************************************************************************** + * \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 */ + /*-----------------------------------------------------------------------------------*/ + + 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/Collision/Narrowphase/SHCollisionDispatch.h b/SHADE_Engine/src/Physics/SHPhysicsWorld.h similarity index 51% rename from SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h rename to SHADE_Engine/src/Physics/SHPhysicsWorld.h index 1df84da0..c5152c44 100644 --- a/SHADE_Engine/src/Physics/Collision/Narrowphase/SHCollisionDispatch.h +++ b/SHADE_Engine/src/Physics/SHPhysicsWorld.h @@ -1,7 +1,7 @@ /**************************************************************************************** - * \file SHCollisionDispatch.h + * \file SHPhysicsWorld.h * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \brief Interface for the static Collision Dispatcher + * \brief Interface 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 @@ -10,9 +10,11 @@ #pragma once +#include + // Project Headers -#include "Physics/Collision/Contacts/SHManifold.h" -#include "Physics/Collision/Contacts/SHCollisionKey.h" +#include "Math/SHMath.h" +#include "SH_API.h" namespace SHADE { @@ -20,36 +22,52 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates static methods for running narrow-phase collision detection. - */ - class SH_API SHCollisionDispatcher + struct SH_API SHPhysicsWorldState { public: - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - 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); + struct WorldSettings + { + public: + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + + SHVec3 gravity = SHVec3{ 0.0f, -9.81f, 0.0f }; + uint16_t numVelocitySolverIterations = 10; + uint16_t numPositionSolverIterations = 5; + bool sleepingEnabled = true; + }; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr int NUM_SHAPES = static_cast(SHCollisionShape::Type::COUNT); + rp3d::PhysicsWorld* world; + WorldSettings settings; - static const ManifoldCollide manifoldCollide [NUM_SHAPES][NUM_SHAPES]; - static const TriggerCollide triggerCollide [NUM_SHAPES][NUM_SHAPES]; + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsWorldState() noexcept; + + /*---------------------------------------------------------------------------------*/ + /* 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/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp deleted file mode 100644 index 69317e59..00000000 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsDebugDrawRutine.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * of DigiPen Institute of Technology is prohibited. -****************************************************************************************/ - -#include - -// Primary Header -#include "Physics/System/SHPhysicsDebugDrawSystem.h" - -// Project Headers -#include "ECS_Base/Managers/SHSystemManager.h" -#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" -#include "Math/Transform/SHTransformComponent.h" -#include "Physics/System/SHPhysicsSystem.h" -#include "Tools/Utilities/SHUtilities.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsDebugDrawSystem::PhysicsDebugDraw::PhysicsDebugDraw() - : SHSystemRoutine { "Physics Debug-Draw", true } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsDebugDrawSystem::PhysicsDebugDraw::Execute(double) noexcept - { - auto* physicsDebugDrawSystem = reinterpret_cast(GetSystem()); - - if (!physicsDebugDrawSystem->IsDebugDrawActive()) - return; - - 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); - } - } - - auto* physicsSystem = SHSystemManager::GetSystem(); - if (!physicsSystem) - return; - - if (DRAW_CONTACTS) - { - 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.position, SHQuaternion::Identity, SHVec3{ 0.1f }); - debugDrawSystem->DrawCube(TRS, CONTACT_COLOUR); - debugDrawSystem->DrawLine(contactPoint.position, contactPoint.position + contactPoint.normal * 0.5f, CONTACT_COLOUR, true); - } - } - - if (DRAW_RAYCASTS) - { - 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) - { - const SHColour& AABB_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::BROADPHASE)]; - - 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.GetExtents() * 2.0f); - debugDrawSystem->DrawWireCube(TRS, AABB_COLOUR); - } - } - } - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp deleted file mode 100644 index a08b943b..00000000 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************************** - * \file SHPhysicsPostUpdateRoutine.cpp - * \author Diren D Bharwani, diren.dbharwani, 390002520 - * \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 - * of DigiPen Institute of Technology is prohibited. -****************************************************************************************/ - -#include - -// Primary Header -#include "Physics/System/SHPhysicsSystem.h" - -// Project Headers -#include "ECS_Base/Managers/SHSystemManager.h" -#include "Math/Transform/SHTransformComponent.h" -#include "Scene/SHSceneManager.h" -#include "Scripting/SHScriptEngine.h" - -namespace SHADE -{ - /*-----------------------------------------------------------------------------------*/ - /* Constructors & Destructor Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate() - : SHSystemRoutine { "Physics Post-Update", false } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Public Function Member Definitions */ - /*-----------------------------------------------------------------------------------*/ - - void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept - { - auto* physicsSystem = reinterpret_cast(GetSystem()); - auto* scriptingSystem = SHSystemManager::GetSystem(); - - if (scriptingSystem == nullptr) - { - SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); - } - - 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. - if (physicsSystem->worldUpdated) - { - 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; - - 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(); - } - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp deleted file mode 100644 index 3f2de93f..00000000 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************************** - * \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" -#include "Scene/SHSceneManager.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 - auto& physicsObjects = physicsSystem->physicsObjectManager.GetPhysicsObjects(); - for (auto& [entityID, physicsObject] : physicsObjects) - { - const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); - // 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) - { - const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); - const bool RIGIDBODY_ACTIVE = physicsObject.rigidBody->IsActive(); - - 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) - { - const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); - const bool COLLIDER_ACTIVE = physicsObject.collider->IsActive(); - - if (IS_ACTIVE != COLLIDER_ACTIVE) - physicsObject.collider->SetIsActive(IS_ACTIVE); - - 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->Update(); - } - } - } - - physicsSystem->collisionSpace->UpdateBroadphase(); - } - -} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp deleted file mode 100644 index 6ae53b31..00000000 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsUpdateRoutine.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************************** - * \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) - { - if (scriptEngine) - scriptEngine->ExecuteFixedUpdates(); - - if (physicsSystem->physicsWorld) - physicsSystem->physicsWorld->Step(static_cast(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/SHPhysicsDebugDrawSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp index ae25216f..96af5e39 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.cpp @@ -13,60 +13,79 @@ // Primary Header #include "SHPhysicsDebugDrawSystem.h" -// Project Header +// Project Headers #include "ECS_Base/Managers/SHSystemManager.h" -#include "Math/Transform/SHTransformComponent.h" -#include "Physics/SHPhysicsEvents.h" -#include "Tools/Utilities/SHUtilities.h" +#include "Editor/SHEditor.h" +#include "Scene/SHSceneManager.h" namespace SHADE { - const SHColour SHPhysicsDebugDrawSystem::DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::COUNT)] + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[NUM_FLAGS] = { - SHColour::GREEN // Colliders - , SHColour::PURPLE // Triggers - , SHColour::RED // Contacts - , SHColour::ORANGE // Raycasts - , SHColour::CYAN // Broadphase + drawColliders + , drawColliderAABBs + , drawBroadPhaseAABBs + , drawContactPoints + , drawContactNormals + , drawRaycasts }; + SHVec3 SHPhysicsDebugDrawSystem::boxVertices[NUM_BOX_VERTICES]; + /*-----------------------------------------------------------------------------------*/ /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept - : flags { 0 } + : debugDrawFlags { 0 } + , physicsSystem { nullptr } { - collidersToDraw.clear(); + 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::IsDebugDrawActive() const noexcept + bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept { - return flags & ACTIVE_FLAG; - } + 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; + } - bool SHPhysicsDebugDrawSystem::GetFlagState(DebugDrawFlags flag) const noexcept - { - const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); - return flags & ENUM_VALUE; + return debugDrawFlags & 1U << SHUtilities::ConvertEnum(flag); } /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsDebugDrawSystem::SetFlagState(DebugDrawFlags flag, bool state) noexcept + void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept { - const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag); - state ? flags |= ENUM_VALUE : flags &= ~ENUM_VALUE; + 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; + } - // 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; + value ? (debugDrawFlags |= 1U << INT_FLAG) : (debugDrawFlags &= ~(1U << INT_FLAG)); } /*-----------------------------------------------------------------------------------*/ @@ -77,76 +96,240 @@ namespace SHADE { 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); + SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!") + physicsSystem = SHSystemManager::GetSystem(); - SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_DRAW_EVENT, EVENT_RECEIVER_PTR); + // Generate shapes + generateBox(); } void SHPhysicsDebugDrawSystem::Exit() { - + physicsSystem = nullptr; } - void SHPhysicsDebugDrawSystem::AddRaycast(const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept + 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 */ /*-----------------------------------------------------------------------------------*/ - SHEventHandle SHPhysicsDebugDrawSystem::onColliderDraw(SHEventPtr onColliderDrawEvent) + void SHPhysicsDebugDrawSystem::drawColliders(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept { - const auto& EVENT_DATA = reinterpret_cast*>(onColliderDrawEvent.get())->data; - - // Add to the container to draw all colliders - if (EVENT_DATA->debugDrawState) + const auto& COLLIDER_SET = SHComponentManager::GetDense(); + for (const auto& COLLIDER : COLLIDER_SET) { - if (collidersToDraw.empty()) - flags |= ACTIVE_FLAG; + // Skip inactive colliders + if (!SHSceneManager::CheckNodeAndComponentsActive(COLLIDER.GetEID())) + continue; - collidersToDraw.emplace(EVENT_DATA->entityID); - } - else - { - collidersToDraw.erase(EVENT_DATA->entityID); - - // 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; - } - - void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept - { - for (const auto* SHAPE : collider.GetCollisionShapes()) - { - const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(SHAPE->IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)]; - - switch (SHAPE->GetType()) + for (auto& collisionShape : COLLIDER.GetCollisionShapes()) { - case SHCollisionShape::Type::SPHERE: + switch (collisionShape.GetType()) { - debugDrawSystem->DrawWireSphere(SHAPE->GetTRS(), DRAW_COLOUR, true); - break; + case SHCollisionShape::Type::BOX: debugDrawBox(debugRenderer, COLLIDER, collisionShape); break; + case SHCollisionShape::Type::SPHERE: debugDrawSphere(debugRenderer, COLLIDER, collisionShape); break; + default: break; } - case SHCollisionShape::Type::BOX: - { - debugDrawSystem->DrawWireCube(SHAPE->GetTRS(), DRAW_COLOUR, true); - break; - } - case SHCollisionShape::Type::CAPSULE: - { - 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(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, SHColour::RED); + } + + #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(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, SHColour::RED); + + #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(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, SHColour::RED); + } + + #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(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, SHColour::RED); + + #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.position, END_POS, RAY_COLOUR); + } + } + + + 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(transformedVertices[IDX1], transformedVertices[IDX2], COLLIDER_COLOUR); + } + + // A, B, C, D + std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] }; + debugRenderer->DrawLineLoop(backQuad.begin(), backQuad.end(), COLLIDER_COLOUR); + + // E, F, G, H + std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] }; + debugRenderer->DrawLineLoop(frontQuad.begin(), frontQuad.end(), COLLIDER_COLOUR); + } + + 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()); + + /* #KWFix */ + //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 index 336dff0c..dc703092 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsDebugDrawSystem.h @@ -10,18 +10,14 @@ #pragma once -#include +#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/Shapes/SHSphere.h" - +#include "Math/SHColour.h" +#include "SHPhysicsSystem.h" +#include "Tools/Utilities/SHUtilities.h" namespace SHADE { @@ -32,55 +28,63 @@ namespace SHADE class SH_API SHPhysicsDebugDrawSystem final : public SHSystem { public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ - enum class DebugDrawFlags : uint8_t + enum class DebugDrawFlags { - COLLIDERS = 0x02 - , CONTACTS = 0x04 - , RAYCASTS = 0x08 - , BROADPHASE = 0x10 + COLLIDER + , COLLIDER_AABB + , BROAD_PHASE_AABB + , CONTACT_POINTS + , CONTACT_NORMALS + , RAYCASTS + + , NUM_FLAGS }; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHPhysicsDebugDrawSystem () noexcept; - ~SHPhysicsDebugDrawSystem() noexcept = default; + SHPhysicsDebugDrawSystem() noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool IsDebugDrawActive () const noexcept; - [[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept; + bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept; + /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetFlagState (DebugDrawFlags flag, bool state) noexcept; + void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept; /*---------------------------------------------------------------------------------*/ - /* Member Functions */ + /* Function Members */ /*---------------------------------------------------------------------------------*/ - void Init () override; - void Exit () override; - - void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept; + void Init() override; + void Exit() override; /*---------------------------------------------------------------------------------*/ /* 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 + class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine { public: - PhysicsDebugDraw(); + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsDebugDrawRoutine(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ void Execute(double dt) noexcept override; }; @@ -89,59 +93,46 @@ namespace SHADE /* 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 - }; + using DebugDrawFunction = void(*)(SHDebugDrawSystem*, rp3d::DebugRenderer*) noexcept; /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr uint8_t ACTIVE_FLAG = 0x01; + static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); + static const DebugDrawFunction drawFunctions[NUM_FLAGS]; - static const SHColour DEBUG_DRAW_COLOURS[static_cast(Colours::COUNT)]; + // SHAPES INFO - // 0 0 0 drawBroadphase drawRaycasts drawContacts drawAllColliders debugDrawActive - uint8_t flags; - - Colliders collidersToDraw; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent); - - static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHCollider& collider) noexcept; - static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept; + 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 97b555af..768c9b77 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -19,9 +19,9 @@ #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 "Physics/Collision/SHCollisionTagMatrix.h" +#include "Physics/SHPhysicsEvents.h" +#include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" namespace SHADE @@ -30,26 +30,11 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsSystem::SHPhysicsSystem() noexcept + SHPhysicsSystem::SHPhysicsSystem() : worldUpdated { false } , interpolationFactor { 0.0 } , fixedDT { DEFAULT_FIXED_STEP } - , physicsWorld { nullptr } - , collisionSpace { nullptr } - { - // 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_INIT_POST }; - eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST }; - } - - SHPhysicsSystem::~SHPhysicsSystem() noexcept - { - delete collisionSpace; - delete physicsWorld; - } + {} /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ @@ -60,58 +45,45 @@ namespace SHADE return 1.0 / fixedDT; } - double SHPhysicsSystem::GetFixedDT() const noexcept + const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept { - return fixedDT; + return worldState.settings; } - const std::vector& SHPhysicsSystem::GetTriggerInfo() const noexcept + const std::vector& SHPhysicsSystem::GetAllCollisionInfo() const noexcept { - return physicsWorld->GetTriggerEvents(); + return collisionListener.GetCollisionInfoContainer(); } - const std::vector& SHPhysicsSystem::GetCollisionInfo() const noexcept + const std::vector& SHPhysicsSystem::GetAllTriggerInfo() const noexcept { - return physicsWorld->GetCollisionEvents(); + 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 */ /*-----------------------------------------------------------------------------------*/ - 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 + void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) 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.") - } + worldState.settings = settings; + worldState.UpdateSettings(); } /*-----------------------------------------------------------------------------------*/ @@ -120,271 +92,390 @@ 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); - // 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); + // Link Physics Object Manager with System & Raycaster + objectManager.SetFactory(factory); + raycaster.SetObjectManager(&objectManager); - SHEventManager::SubscribeTo(eventFunctions[i].second, EVENT_RECEIVER_PTR); - } + // 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 }; defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath); } - void SHPhysicsSystem::ForceUpdate() + void SHPhysicsSystem::BuildScene(SHSceneGraph& sceneGraph) { - if (!physicsWorld) - return; - - auto* scriptingSystem = SHSystemManager::GetSystem(); - - if (scriptingSystem == nullptr) + static const auto BUILD_NEW_SCENE_PHYSICS_OBJECT = [&](SHSceneNode* node) { - SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); + 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); } - scriptingSystem->ExecuteFixedUpdates(); - physicsWorld->Step(static_cast(fixedDT)); + worldState.CreateWorld(factory); +#ifdef _PUBLISH + worldState.world->setIsDebugRenderingEnabled(false); +#else + worldState.world->setIsDebugRenderingEnabled(true); +#endif - const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); - for (auto& rigidBodyComponent : RIGIDBODY_DENSE) + // 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) { - const EntityID EID = rigidBodyComponent.GetEID(); + SHLOGV_ERROR("Unable to force update without a Physics world!") + return; + } - // Skip missing transforms - auto* transformComponent = SHComponentManager::GetComponent_s(EID); - if (!transformComponent) - continue; + auto* scriptingSystem = SHSystemManager::GetSystem(); + if (scriptingSystem == nullptr) + { + SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); + } - // Skip invalid bodies (Should not occur) - if (!rigidBodyComponent.rigidBody) - continue; + // Force the physics world to update once + if (scriptingSystem != nullptr) + scriptingSystem->ExecuteFixedUpdates(); - // Skip inactive bodies - const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); - if (!IS_ACTIVE) - continue; + worldState.world->update(static_cast(fixedDT)); - const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); + // 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); - // Skip objects that have not moved - if (!MOTION_STATE) - continue; + const auto& CURRENT_TF = physicsObject.GetRigidBody()->getTransform(); + const auto& RENDER_POS = CURRENT_TF.getPosition(); + const auto& RENDER_ROT = CURRENT_TF.getOrientation(); - // We ignore interpolations here because we are only stepping once - transformComponent->SetWorldPosition(MOTION_STATE.position); - transformComponent->SetWorldOrientation(MOTION_STATE.orientation); + // 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); + } } } - const std::vector& SHPhysicsSystem::Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept + SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept { - auto& results = collisionSpace->Raycast(info); + return raycaster.Raycast(ray, distance, collisionTag); + } - // Load start and end points into the container for debug drawing - #ifdef SHEDITOR + SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept + { + return raycaster.Linecast(start, end, collisionTag); + } - SHVec3 endPos = info.ray.position + info.ray.direction * SHRay::MAX_RAYCAST_DIST; + SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept + { + return raycaster.ColliderRaycast(eid, ray, distance); + } - if (!results.empty()) - endPos = results.back().position; - - raycastHits.emplace_back(info.ray.position, endPos); - - #endif + SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept + { + return raycaster.ColliderRaycast(eid, shapeIndex, ray, distance); + } - return results; + 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::onSceneInit(SHEventPtr onSceneInitEvent) + SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept { - /* - * 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. - */ + const auto& EVENT_DATA = reinterpret_cast*>(addComponentEvent.get()); - // Destroy an existing world if there is one. - //! This should almost never happen. - if (physicsWorld) + 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) { - // 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); - } + const EntityID EID = EVENT_DATA->data->eid; - delete physicsWorld; - physicsWorld = nullptr; + // 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 } - 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. - // 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) - physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); - - if (PHYSICS_OBJECT.collider) - collisionSpace->AddCollider(PHYSICS_OBJECT.collider); - } - - return onSceneInitEvent.get()->handle; + return EVENT_DATA->handle; } - SHEventHandle SHPhysicsSystem::onSceneExit(SHEventPtr onSceneExitEvent) + SHEventHandle SHPhysicsSystem::removePhysicsComponent(SHEventPtr removeComponentEvent) noexcept { - /* - * Destroy the physics world. - * Destroy all physics objects. - */ + const auto& EVENT_DATA = reinterpret_cast*>(removeComponentEvent.get()); - for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + 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) { - if (PHYSICS_OBJECT.rigidBody) - physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); + const EntityID EID = EVENT_DATA->data->eid; - if (PHYSICS_OBJECT.collider) - collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider); + // 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 } - delete collisionSpace; - collisionSpace = nullptr; - - delete physicsWorld; - physicsWorld = nullptr; - - return onSceneExitEvent.get()->handle; + return EVENT_DATA->handle; } - SHEventHandle SHPhysicsSystem::onComponentAdded(SHEventPtr onComponentAddedEvent) + SHEventHandle SHPhysicsSystem::onPlay(SHEventPtr onPlayEvent) { - 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; - - // TODO: Hull Collider - - // Check if its a physics component - 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) + static const auto BUILD_PHYSICS_OBJECT = [&](SHSceneNode* node) { - physicsObjectManager.AddRigidBody(EID); + const EntityID EID = node->GetEntityID(); - if (physicsWorld) + if (SHComponentManager::HasComponent(EID)) + objectManager.AddRigidBody(EID); + + if (SHComponentManager::HasComponent(EID)) { - auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; - physicsWorld->AddRigidBody(rigidBody); + objectManager.AddCollider(EID); + + auto* COLLIDER = SHComponentManager::GetComponent(EID); + for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i) + objectManager.AddCollisionShape(EID, i); } - } + }; - if (IS_COLLIDER) - { - physicsObjectManager.AddCollider(EID, SHCollider::Type::COMPOSITE); + //////////////////////////////// - if (collisionSpace) - { - auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; - collisionSpace->AddCollider(collider); - } - } + // Create physics world + if (worldState.world != nullptr) + return onPlayEvent->handle; - return onComponentAddedEvent.get()->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::onComponentRemoved(SHEventPtr onComponentRemovedEvent) + SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent) { - static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID(); - static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID(); + // Remove all physics objects + objectManager.RemoveAllObjects(); + objectManager.SetWorld(nullptr); - const auto& EVENT_DATA = reinterpret_cast*>(onComponentRemovedEvent.get())->data; + // Clear all collision info + // Collision listener is automatically unbound when world is destroyed + collisionListener.ClearContainers(); + raycaster.ClearFrame(); - const auto REMOVED_DATA = EVENT_DATA->removedComponentType; + // Destroy the world + worldState.DestroyWorld(factory); - 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 - 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) - { - if (physicsWorld) - { - auto* rigidBody = physicsObjectManager.GetPhysicsObject(EID)->rigidBody; - physicsWorld->RemoveRigidBody(rigidBody); - } - - physicsObjectManager.RemoveRigidBody(EID); - } - - if (IS_COLLIDER) - { - if (collisionSpace) - { - auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; - collisionSpace->RemoveCollider(collider); - } - - physicsObjectManager.RemoveCollider(EID); - } - - return onComponentRemovedEvent.get()->handle; + return onStopEvent->handle; } - -} // namespace SHADE +} // 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 712727ec..99db493e 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -10,16 +10,24 @@ #pragma once +#include +#include + +// External Dependencies +#include + // 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 "Physics/Dynamics/SHPhysicsWorld.h" -#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.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" namespace SHADE { @@ -27,10 +35,6 @@ 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 { private: @@ -45,146 +49,248 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHPhysicsSystem () noexcept; - ~SHPhysicsSystem() noexcept; + SHPhysicsSystem(); /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] double GetFixedUpdateRate() const noexcept; - [[nodiscard]] double GetFixedDT () const noexcept; + [[nodiscard]] double GetFixedUpdateRate () const noexcept; + [[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept; - [[nodiscard]] const std::vector& GetTriggerInfo () const noexcept; - [[nodiscard]] const std::vector& GetCollisionInfo () 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 */ /*---------------------------------------------------------------------------------*/ - void SetFixedUpdateRate(double fixedUpdateRate) noexcept; - void SetFixedDT(double fixedDt) noexcept; - - /*---------------------------------------------------------------------------------*/ - /* Member Functions */ - /*---------------------------------------------------------------------------------*/ - - /** - * @brief - * - Initialises the static collision tag matrix. - * - Registers the system to catch specific events. - */ - 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 */ - /*---------------------------------------------------------------------------------*/ - - /** - * @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: - PhysicsPreUpdate(); - void Execute(double dt) noexcept override; - }; - - /** - * @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: - 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: - PhysicsPostUpdate(); - void Execute(double dt) noexcept override; - }; - - private: - /*---------------------------------------------------------------------------------*/ - /* Type Definitions */ - /*---------------------------------------------------------------------------------*/ - - using EventFunctionPair = std::pair; - - struct RaycastHit - { - SHVec3 start; - SHVec3 end; - }; - - /*---------------------------------------------------------------------------------*/ - /* Data Members */ - /*---------------------------------------------------------------------------------*/ - - static constexpr int NUM_EVENT_FUNCTIONS = 4; - - // Event function container for cleanly registering to events - EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS]; - - // System data - bool worldUpdated; - double interpolationFactor; - double fixedDT; - - // Sub-systems / managers - - SHPhysicsWorld* physicsWorld; - SHCollisionSpace* collisionSpace; - SHPhysicsObjectManager physicsObjectManager; - - // For the debug drawer to draw rays - #ifdef SHEDITOR - std::vector raycastHits; - #endif + void SetFixedUpdateRate (double fixedUpdateRate) noexcept; + void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHEventHandle onSceneInit (SHEventPtr onSceneInitEvent); - SHEventHandle onSceneExit (SHEventPtr onSceneExitEvent); + void Init () override; + void Exit () override; - SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent); - SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent); + 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 */ + /*---------------------------------------------------------------------------------*/ + + class SH_API PhysicsPreUpdate final : public SHSystemRoutine + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsPreUpdate(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute(double dt) noexcept override; + + private: + /*-------------------------------------------------------------------------------*/ + /* 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 + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsFixedUpdate(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute (double dt) noexcept override; + }; + + class SH_API PhysicsPostUpdate final : public SHSystemRoutine + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsPostUpdate(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute(double dt) noexcept override; + + private: + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + static void postUpdateSyncTransforms + ( + SHPhysicsObject& physicsObject + , SHTransformComponent* transformComponent + , SHRigidBodyComponent* rigidBodyComponent + , SHColliderComponent* colliderComponent + , double interpolationFactor + ) noexcept; + }; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + // System data + + bool worldUpdated; + 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 b6ed9d56..1fb11274 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -1,6 +1,8 @@ /************************************************************************************//*! \file SHPhysicsSystemInterface.cpp -\author Diren D Bharwani, diren.dbharwani, 390002520 +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 31, 2022 \brief Contains the definitions of the functions of the static SHPhysicsSystemInterface class. @@ -8,13 +10,10 @@ 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" @@ -24,24 +23,28 @@ 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* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - return physicsSystem->GetCollisionInfo(); + auto phySystem = SHSystemManager::GetSystem(); + if (phySystem) + { + return phySystem->GetAllCollisionInfo(); + } 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* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - return physicsSystem->GetTriggerInfo(); + auto phySystem = SHSystemManager::GetSystem(); + if (phySystem) + { + return phySystem->GetAllTriggerInfo(); + } SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); return emptyVec; @@ -49,34 +52,85 @@ namespace SHADE double SHPhysicsSystemInterface::GetFixedDT() noexcept { - auto* physicsSystem = SHSystemManager::GetSystem(); - if (physicsSystem) - return physicsSystem->GetFixedDT(); + auto phySystem = SHSystemManager::GetSystem(); + if (phySystem) + { + return 1.0 / phySystem->GetFixedUpdateRate(); + } SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); return 0.0; } - int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept + SHPhysicsRaycastResult SHPhysicsSystemInterface::Raycast(const SHRay& ray, float distance) noexcept { auto* physicsSystem = SHSystemManager::GetSystem(); if (physicsSystem) - return physicsSystem->GetFixedUpdateRate(); + { + return physicsSystem->Raycast(ray, distance); + } - SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead."); - return 0.0; + SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); + return SHPhysicsRaycastResult{}; } - const std::vector& SHPhysicsSystemInterface::Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept + SHPhysicsRaycastResult SHPhysicsSystemInterface::Linecast(const SHVec3& start, const SHVec3& end) noexcept { - static std::vector emptyVec; - auto* physicsSystem = SHSystemManager::GetSystem(); if (physicsSystem) - return physicsSystem->Raycast(info); + { + return physicsSystem->Linecast(start, end); + } - SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead."); - return emptyVec; + 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 8a1f6be8..0065aee3 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -1,21 +1,21 @@ /************************************************************************************//*! \file SHPhysicsSystemInterface.h -\author Diren D Bharwani, diren.dbharwani, 390002520 +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 31, 2022 \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/SHCollisionSpace.h" -#include "Physics/Collision/Contacts/SHCollisionEvents.h" namespace SHADE @@ -24,10 +24,10 @@ namespace SHADE /* Forward Declarations */ /*-----------------------------------------------------------------------------------*/ + class SHCollisionInfo; class SHVec3; struct SHRay; struct SHPhysicsRaycastResult; - struct SHCollisionSpace::RaycastInfo; /*-----------------------------------------------------------------------------------*/ @@ -49,12 +49,15 @@ 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& Raycast (const SHCollisionSpace::RaycastInfo& info) noexcept; - + [[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 new file mode 100644 index 00000000..a5ca957a --- /dev/null +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemRoutines.cpp @@ -0,0 +1,412 @@ +/**************************************************************************************** + * \file SHPhysicsSystemRoutines.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics System Routines + * + * \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 "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 +{ + /*-----------------------------------------------------------------------------------*/ + /* 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 } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + 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) + { + SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!"); + } + + 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)); + + 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()); + auto* scriptingSystem = SHSystemManager::GetSystem(); + + if (scriptingSystem == nullptr) + { + SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); + } + + // 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(); + + // 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_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index 7dc8d84d..b876f5b0 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 @@ -260,7 +260,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); } @@ -305,7 +305,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); } @@ -352,7 +352,7 @@ namespace SHADE return NODE_ITER->second; } - SHSceneNode* newNode = allocateNode(entityID); + SHSceneNode* newNode = AllocateNode(entityID); if (parent == nullptr) { @@ -362,7 +362,7 @@ namespace SHADE } else { - changeParent(newNode, parent); + ChangeParent(newNode, parent); } return newNode; @@ -389,9 +389,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; } @@ -399,16 +399,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 @@ -498,39 +498,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) @@ -538,7 +538,7 @@ namespace SHADE // Remove child if (node->parent) - removeChild(node->parent, node); + RemoveChild(node->parent, node); if (newParent == nullptr) { @@ -548,16 +548,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); @@ -571,7 +571,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!") @@ -592,12 +592,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 ce51db5e..3285fc6f 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -24,10 +24,6 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - /** - * @brief - * Encapsulates a hierarchical tree for objects in the scene. - */ class SH_API SHSceneGraph { public: @@ -69,28 +65,7 @@ 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; void SetActive (EntityID entityID, bool isActive) noexcept; @@ -99,47 +74,15 @@ namespace SHADE /* 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; - /** - * @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; + 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 (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; + void Traverse (const UnaryFunction& function) const; private: /*---------------------------------------------------------------------------------*/ @@ -153,14 +96,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 79e8818a..3614fa52 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -19,7 +19,6 @@ #include "Events/SHEventManager.hpp" //#include "FRC/SHFrameRateController.h" //#include "ECS_Base/System/SHApplication.h" -#include "SHSceneEvents.h" #include @@ -67,6 +66,7 @@ namespace SHADE SHEventManager::BroadcastEvent(exitEvent, SH_SCENE_EXIT_POST); delete currentScene; + } if (!prevSceneReload) { diff --git a/SHADE_Engine/src/Scene/SHSceneNode.h b/SHADE_Engine/src/Scene/SHSceneNode.h index 45d81c1d..62979850 100644 --- a/SHADE_Engine/src/Scene/SHSceneNode.h +++ b/SHADE_Engine/src/Scene/SHSceneNode.h @@ -15,17 +15,20 @@ // 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: @@ -64,7 +67,7 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetActive (bool newActiveState) noexcept; + void SetActive (bool newActiveState) noexcept; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 1b485633..2e2d45f4 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -3,6 +3,9 @@ #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" +#include "Physics/Interface/SHCollisionShape.h" #include "Resource/SHResourceManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" @@ -11,8 +14,7 @@ #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "SHSerializationTools.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h" -#include "Physics/Collision/SHCompositeCollider.h" -#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" +#include "Physics/Collision/SHCollisionTagMatrix.h" namespace YAML { @@ -144,14 +146,14 @@ namespace YAML { case SHCollisionShape::Type::BOX: { - const auto& BOX = dynamic_cast(rhs); - node[HalfExtents] = BOX.GetRelativeExtents(); + const auto* BOX = reinterpret_cast(rhs.GetShape()); + node[HalfExtents] = BOX->GetRelativeExtents(); } break; case SHCollisionShape::Type::SPHERE: { - const auto& SPHERE = dynamic_cast(rhs); - node[Radius] = SPHERE.GetRelativeRadius(); + const auto* SPHERE = reinterpret_cast(rhs.GetShape()); + node[Radius] = SPHERE->GetRelativeRadius(); } break; case SHCollisionShape::Type::CAPSULE: break; @@ -187,19 +189,13 @@ namespace YAML case SHCollisionShape::Type::BOX: { if (node[HalfExtents].IsDefined()) - { - auto* box = dynamic_cast(&rhs); - box->SetRelativeExtents(node[HalfExtents].as()); - } + rhs.SetBoundingBox(node[HalfExtents].as()); } break; case SHCollisionShape::Type::SPHERE: { if (node[Radius].IsDefined()) - { - auto* sphere = dynamic_cast(&rhs); - sphere->SetRelativeRadius(node[Radius].as()); - } + rhs.SetBoundingSphere(node[Radius].as()); } break; case SHCollisionShape::Type::CAPSULE: break; @@ -223,19 +219,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()); + auto const& colliders = rhs.GetCollisionShapes(); + int const numColliders = static_cast(colliders.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; @@ -245,9 +237,6 @@ 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{}; @@ -260,16 +249,14 @@ namespace YAML if (!ok) 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::BOX: rhs.AddBoundingBox(); break; + case SHCollisionShape::Type::SPHERE: rhs.AddBoundingSphere(); break; + case SHCollisionShape::Type::CAPSULE: break; + default:; } - - YAML::convert::decode(colliderNode, *collider->GetCollisionShape(numColliders++)); + YAML::convert::decode(colliderNode, rhs.GetCollisionShape(numColliders++)); } } return true; diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index f4b4f09d..b5f1444f 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) @@ -107,7 +107,7 @@ namespace SHADE try { - auto& shape = *collider->GetCollisionShape(arrayIndex); + auto& shape = collider->GetCollisionShape(arrayIndex); return shape; } catch (std::invalid_argument&) @@ -128,19 +128,35 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 BoxCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetWorldCentroid()); + return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + } + void BoxCollider::Center::set(Vector3 value) + { + getNativeCollisionShape().SetCenter(Convert::ToNative(value)); } 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() + Vector3 BoxCollider::Min::get() { - return Convert::ToCLI(getNativeCollisionShape().GetWorldOrientation()); + return Convert::ToCLI(getNativeCollisionShape().GetMin()); + } + void BoxCollider::Min::set(Vector3 value) + { + getNativeCollisionShape().SetMin(Convert::ToNative(value)); + } + Vector3 BoxCollider::Max::get() + { + return Convert::ToCLI(getNativeCollisionShape().GetMax()); + } + void BoxCollider::Max::set(Vector3 value) + { + getNativeCollisionShape().SetMax(Convert::ToNative(value)); } /*---------------------------------------------------------------------------------*/ @@ -148,13 +164,11 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ bool BoxCollider::TestPoint(Vector3 point) { - //return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); - return false; + return getNativeCollisionShape().TestPoint(Convert::ToNative(point)); } bool BoxCollider::Raycast(Ray ray, float maxDistance) { - //return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); - return false; + return getNativeCollisionShape().Raycast(Convert::ToNative(ray)); } /*---------------------------------------------------------------------------------*/ @@ -162,7 +176,11 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ Vector3 SphereCollider::Center::get() { - return Convert::ToCLI(getNativeCollisionShape().GetWorldCentroid()); + return Convert::ToCLI(getNativeCollisionShape().GetCenter()); + } + void SphereCollider::Center::set(Vector3 value) + { + getNativeCollisionShape().SetCenter(Convert::ToNative(value)); } float SphereCollider::Radius::get() { @@ -178,11 +196,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)); } /*---------------------------------------------------------------------------------*/ @@ -213,10 +231,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ int Collider::CollisionShapeCount::get() { - if (const auto* shapes = GetNativeComponent()->GetCollisionShapes()) - return static_cast(shapes->size()); - - return -1; + return static_cast(GetNativeComponent()->GetCollisionShapes().size()); } /*---------------------------------------------------------------------------------*/ @@ -296,10 +311,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 c2e732f4..8ea648aa 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 || shape->GetType() == SHCollisionShape::Type::INVALID) + auto& shape = collider->GetCollisionShape(arrayIndex); + if (shape.GetType() != SHCollisionShape::Type::BOX) throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); - return dynamic_cast(*shape); + return reinterpret_cast(shape); } catch (std::invalid_argument&) { diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index 19235571..a649483f 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -142,14 +142,15 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Center of the box collider. + /// Center of the Bounding Box formed by this bound. /// property Vector3 Center { Vector3 get(); + void set(Vector3 value); } /// - /// Half of the scale of the box collider. + /// Half of the scale of the Bounding Box formed by this bound. /// property Vector3 HalfExtents { @@ -157,11 +158,22 @@ namespace SHADE void set(Vector3 value); } /// - /// The orientation of the box. + /// Position of the bottom left back corner of the Bounding Box formed by this + /// bound. /// - property Quaternion Orientation + property Vector3 Min { - Quaternion get(); + 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); } /*-----------------------------------------------------------------------------*/ @@ -189,11 +201,12 @@ namespace SHADE /* Properties */ /*-----------------------------------------------------------------------------*/ /// - /// Center of the sphere. + /// Center of the Bounding Sphere formed by this bound. /// property Vector3 Center { Vector3 get(); + void set(Vector3 value); } /// /// Radius of the Bounding Sphere formed by this bound. diff --git a/SHADE_Managed/src/Components/RigidBody.cxx b/SHADE_Managed/src/Components/RigidBody.cxx index 6237f3a9..a564402f 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()->SetIsGravityEnabled(value); + return GetNativeComponent()->SetGravityEnabled(value); } bool RigidBody::IsAllowedToSleep::get() { @@ -217,4 +217,10 @@ 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 8293cca4..8bfe34aa 100644 --- a/SHADE_Managed/src/Components/RigidBody.hxx +++ b/SHADE_Managed/src/Components/RigidBody.hxx @@ -155,6 +155,7 @@ namespace SHADE void AddRelativeTorque(Vector3 relativeForce); Vector3 GetTorque(); + void ClearTorque(); }; } \ No newline at end of file diff --git a/SHADE_Managed/src/Physics/Physics.cxx b/SHADE_Managed/src/Physics/Physics.cxx index 60aba58d..9e2c1413 100644 --- a/SHADE_Managed/src/Physics/Physics.cxx +++ b/SHADE_Managed/src/Physics/Physics.cxx @@ -15,15 +15,10 @@ // 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 { /*-----------------------------------------------------------------------------------*/ @@ -46,262 +41,49 @@ namespace SHADE /* Raycast Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - List^ Physics::Raycast(Ray ray, bool continuous) + RaycastHit Physics::Raycast(Ray ray) { - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray))); } - List^ Physics::Raycast(Ray ray, float distance, bool continuous) + RaycastHit Physics::Raycast(Ray ray, float distance) { - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray), distance)); } - List^ Physics::Linecast(Vector3 start, Vector3 end, bool continuous) + RaycastHit Physics::Linecast(Vector3 start, Vector3 end) { - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::Linecast(Convert::ToNative(start), Convert::ToNative(end))); } - List^ Physics::ColliderRaycast(GameObject object, Ray ray, bool continuous) + RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray) { - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray))); } - List^ Physics::ColliderRaycast(GameObject object, Ray ray, float distance, bool continuous) + RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance) { - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray), distance)); } - List^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, bool continuous) + RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray) { - 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(); - shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); - - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray))); } - List^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance, bool continuous) + RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance) { - 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(); - shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); - - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray), distance)); } - List^ Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end, bool continuous) + RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end) { - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, Convert::ToNative(start), Convert::ToNative(end))); } - List^ Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous) + RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end) { - 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(); - shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid()); - - 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; + return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, shapeIndex, Convert::ToNative(start), Convert::ToNative(end))); } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Physics/Physics.hxx b/SHADE_Managed/src/Physics/Physics.hxx index abbd1891..f13e5952 100644 --- a/SHADE_Managed/src/Physics/Physics.hxx +++ b/SHADE_Managed/src/Physics/Physics.hxx @@ -10,7 +10,6 @@ #pragma once - // Project Includes #include "Math/Ray.hxx" #include "RaycastHit.hxx" @@ -40,146 +39,83 @@ namespace SHADE /* Raycast Function Members */ /*---------------------------------------------------------------------------------*/ - // TODO(Diren): Add layers for raycasting - /// - /// Casts an infinite ray into the world.
- /// This raycast will stop at the first object hit. + /// Casts an infinite ray into the world. ///
/// The ray to cast. - /// - /// 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); + /// The result of the raycast. + static RaycastHit Raycast (Ray ray); /// /// Casts a ray for a given distance into the world. /// /// The ray to cast. /// The distance to cast the 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, float distance, bool continuous); + /// The result of the raycast. + static RaycastHit Raycast (Ray ray, float distance); /// /// Casts a bounded ray into the world. /// /// The start of the bounded ray. /// The end of the bounded 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^ Linecast (Vector3 start, Vector3 end, bool continuous); + /// The result of the raycast. + static RaycastHit Linecast (Vector3 start, Vector3 end); /// /// Casts an infinite ray w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// - /// 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); + /// The ray to cast. + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, Ray ray); /// /// Casts a ray for a given distance w.r.t a GameObject. /// /// The GameObject to cast the ray to. - /// - /// The ray to cast.
- /// The position of the ray is offset from the collider's position. - /// + /// The ray to cast. /// The distance to cast the 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^ ColliderRaycast (GameObject object, Ray ray, float distance, bool continuous); + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance); /// /// 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 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); + /// The ray to cast. + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray); /// /// 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 position of the ray is offset from the collider's position. - /// + /// The ray to cast. /// The distance to cast the 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^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance, bool continuous); + /// The result of the raycast. + static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance); /// /// 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 ray is offset from the collider's position. + /// The start of the bounded 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^ ColliderLineCast (GameObject object, Vector3 start, Vector3 end, bool continuous); + /// The result of the raycast. + static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end); /// /// 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 ray is offset from the collider's position. + /// The start of the bounded ray. /// The end of the bounded 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^ ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous); + /// The result of the raycast. + static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end); private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index 1393fe33..a5a0ebc7 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -30,6 +30,7 @@ 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 { @@ -604,8 +605,8 @@ namespace SHADE { auto entities = { - std::make_pair(collisionInfo.info.GetEntityA(), collisionInfo.info.GetEntityB()), - std::make_pair(collisionInfo.info.GetEntityB(), collisionInfo.info.GetEntityA()) + std::make_pair(collisionInfo.GetEntityA(), collisionInfo.GetEntityB()), + std::make_pair(collisionInfo.GetEntityB(), collisionInfo.GetEntityA()) }; for (auto entity : entities) { @@ -624,15 +625,15 @@ namespace SHADE for (int i = 0; i < entityScripts->Count; ++i) { Script^ script = entityScripts[i]; - switch (collisionInfo.state) + switch (collisionInfo.GetCollisionState()) { - case SHCollisionState::ENTER: + case SHCollisionInfo::State::ENTER: script->OnCollisionEnter(info); break; - case SHCollisionState::STAY: + case SHCollisionInfo::State::STAY: script->OnCollisionStay(info); break; - case SHCollisionState::EXIT: + case SHCollisionInfo::State::EXIT: script->OnCollisionExit(info); break; } @@ -646,8 +647,8 @@ namespace SHADE { auto entities = { - std::make_pair(triggerInfo.info.GetEntityA(), triggerInfo.info.GetEntityB()), - std::make_pair(triggerInfo.info.GetEntityB(), triggerInfo.info.GetEntityA()) + std::make_pair(triggerInfo.GetEntityA(), triggerInfo.GetEntityB()), + std::make_pair(triggerInfo.GetEntityB(), triggerInfo.GetEntityA()) }; for (auto entity : entities) { @@ -666,15 +667,15 @@ namespace SHADE for (int i = 0; i < entityScripts->Count; ++i) { Script^ script = entityScripts[i]; - switch (triggerInfo.state) + switch (triggerInfo.GetCollisionState()) { - case SHCollisionState::ENTER: + case SHCollisionInfo::State::ENTER: script->OnTriggerEnter(info); break; - case SHCollisionState::STAY: + case SHCollisionInfo::State::STAY: script->OnTriggerStay(info); break; - case SHCollisionState::EXIT: + case SHCollisionInfo::State::EXIT: script->OnTriggerExit(info); break; } diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index e3a53661..590a3cf0 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -135,7 +135,6 @@ namespace SHADE return cli; } - /*---------------------------------------------------------------------------------*/ /* Handle Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index f48eb66d..fb373c51 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -144,14 +144,14 @@ namespace SHADE /// /// Converts from a managed RaycastHit to a native SHPhysicsRaycastResult /// - /// The managed RaycastHit to convert from. + /// 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 + /// Converts from native SHPhysicsRaycastResult to a managed RaycastHit. /// - /// The native SHPhysicsRaycastResult to convert from. + /// The native SHPhysicsRaycastResult to convert from. /// Managed copy of a native SHPhysicsRaycastResult. static RaycastHit ToCLI(const SHPhysicsRaycastResult& native);