Merge branch 'main' into SP3-1-Rendering

This commit is contained in:
Brandon Mak 2023-02-03 19:33:22 +08:00
commit ca0b8aabb0
79 changed files with 4346 additions and 4792 deletions

View File

@ -1,4 +1,4 @@
Start in Fullscreen: false
Starting Scene ID: 97158628
Starting Scene ID: 97086054
Window Size: {x: 1920, y: 1080}
Window Title: SHADE Engine

View File

@ -1,16 +1,16 @@
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
0 1 3
1 2 65535
2 3 65534
3 4 65534
4 5 65534
5 6 65534
6 7 65534
7 8 65534
8 9 65534
9 10 65534
10 11 65534
11 12 65534
12 13 65534
13 14 65534
14 15 65534
15 16 65534

View File

@ -0,0 +1,4 @@
Start Maximized: true
Working Scene ID: 97086054
Window Size: {x: 1920, y: 1013}
Style: 0

View File

@ -20,8 +20,8 @@ Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1604,48
Size=316,941
Pos=1434,48
Size=486,941
Collapsed=0
DockId=0x00000006,0
@ -76,7 +76,7 @@ DockId=0x0000000B,0
[Window][ Viewport]
Pos=302,48
Size=1300,836
Size=1130,705
Collapsed=0
DockId=0x0000000B,0
@ -93,14 +93,14 @@ Collapsed=0
DockId=0x0000000A,0
[Window][ Asset Browser]
Pos=302,886
Size=1300,103
Pos=302,755
Size=1130,234
Collapsed=0
DockId=0x0000000C,0
[Window][Material Inspector]
Pos=1604,48
Size=316,941
Pos=1434,48
Size=486,941
Collapsed=0
DockId=0x00000006,1
@ -115,14 +115,16 @@ Size=464,144
Collapsed=0
[Window][Collider Tag Panel]
Pos=60,60
Size=625,744
Pos=302,48
Size=1130,705
Collapsed=0
DockId=0x0000000B,1
[Window][Input Bindings Panel]
Pos=60,60
Size=154,204
Pos=1434,48
Size=486,941
Collapsed=0
DockId=0x00000006,2
[Window][Save Scene As]
Pos=877,444
@ -130,36 +132,36 @@ Size=165,120
Collapsed=0
[Table][0x9D40AE32,17]
Column 0 Weight=1.0000
Column 1 Weight=1.0000
Column 2 Weight=1.0000
Column 3 Weight=1.0000
Column 4 Weight=1.0000
Column 5 Weight=1.0000
Column 6 Weight=1.0000
Column 7 Weight=1.0000
Column 8 Weight=1.0000
Column 9 Weight=1.0000
Column 10 Weight=1.0000
Column 11 Weight=1.0000
Column 12 Weight=1.0000
Column 13 Weight=1.0000
Column 14 Weight=1.0000
Column 15 Weight=1.0000
Column 16 Weight=1.0000
Column 0 Weight=0.9945
Column 1 Weight=0.9945
Column 2 Weight=0.9945
Column 3 Weight=0.9945
Column 4 Weight=0.9945
Column 5 Weight=0.9945
Column 6 Weight=0.9945
Column 7 Weight=0.9945
Column 8 Weight=0.9945
Column 9 Weight=0.9945
Column 10 Weight=0.9945
Column 11 Weight=0.9945
Column 12 Weight=1.0132
Column 13 Weight=0.8444
Column 14 Weight=0.9945
Column 15 Weight=1.2009
Column 16 Weight=1.0132
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=0,71 Size=1920,941 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1602,1036 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1432,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=300,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1300,1036 Split=Y Selected=0xB41284E7
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1130,1036 Split=Y Selected=0xB41284E7
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=1501,672 Split=Y Selected=0xB41284E7
DockNode ID=0x00000009 Parent=0x00000007 SizeRef=1501,700 Split=Y Selected=0xB41284E7
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=1501,836 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=1501,103 Selected=0xB128252A
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=1501,705 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=1501,234 Selected=0xB128252A
DockNode ID=0x0000000A Parent=0x00000007 SizeRef=1501,310 Selected=0xD446F7B6
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1501,338 Selected=0xD9F31532
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=316,1036 Selected=0xE7039252
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=486,1036 Selected=0xE7039252

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,210 @@
- EID: 0
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 7, z: 0}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 0.999999344, y: 0.999999821, z: 0.999999523}
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0.100000001
Use Gravity: false
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:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts:
- Type: PhysicsTestObj
Enabled: true
forceAmount: 50
torqueAmount: 500
- EID: 1
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.5999999, y: 1, z: 1}
IsActive: true
Collider Component:
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: 2
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Camera Component:
Position: {x: 0, y: 2, z: 7}
Pitch: 0
Yaw: 0
Roll: 0
Width: 1920
Height: 1080
Near: 0.00999999978
Far: 10000
Perspective: true
IsActive: true
Scripts: ~
- EID: 65539
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 2.70000005, y: 0.5, z: 0}
Rotate: {x: -0, y: 0, z: 0.436332315}
Scale: {x: 4.5999999, y: 1, z: 1}
IsActive: true
Collider Component:
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: 4
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -1.70000005, z: 0}
Rotate: {x: -0, y: 0, z: 0}
Scale: {x: 10, y: 0.5, z: 10}
IsActive: true
Collider Component:
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.80000019, y: 3, z: 0}
Rotate: {x: -0, y: 0, z: 1.57079637}
Scale: {x: 10, y: 0.5, z: 10}
IsActive: true
Collider Component:
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: 65542
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 4.80000019, y: 3, z: 0}
Rotate: {x: -0, y: 0, z: 1.57079637}
Scale: {x: 10, y: 0.5, z: 10}
IsActive: true
Collider Component:
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: 0, z: 3}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0.100000001
Use Gravity: true
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:
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: ~

View File

@ -0,0 +1,3 @@
Name: PhysicsTest
ID: 97086054
Type: 5

View File

@ -159,7 +159,7 @@ public partial class LeafSearch : BehaviourTreeNode
//Since transform position is often the raccoon's base and the ray needs to hit somewhere higher to be more reliable
Vector3 rayDestination = plrT.GlobalPosition + plrT.GlobalScale * playerCollider.PositionOffset;
Ray sightRay = new Ray(eyePosition, rayDestination - eyePosition);
RaycastHit sightRayHit = Physics.Raycast(sightRay);
RaycastHit sightRayHit = Physics.Raycast(sightRay, false, (ushort)65535)[0];
//As of November 2022, RaycastHit contains only the FIRST object hit by
//the ray in the Other GameObject data member
//Diren may likely add ALL objects hit by the ray over December

View File

@ -1,6 +1,7 @@
using SHADE;
using SHADE_Scripting;
using System;
using System.Collections.Generic;
using static PlayerController;
using static Item;
@ -203,11 +204,22 @@ public class PickAndThrow : Script
Vector3 playerRayPos = pc.tranform.GlobalPosition;
playerRayPos.y += 0.05f;
dirNor.Normalise();
RaycastHit ray1 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(22.5f))), rayDistance);
RaycastHit ray2 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(-22.5f))), rayDistance);
RaycastHit ray3 = Physics.Raycast(new Ray(playerRayPos, dirNor), rayDistance * 0.75f);
List<RaycastHit> rayList1 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(22.5f))), rayDistance, false, (ushort)65535);
List<RaycastHit> rayList2 = Physics.Raycast(new Ray(playerRayPos, Vector3.RotateY(dirNor, SHADE.Math.DegreesToRadians(-22.5f))), rayDistance, false, (ushort)65535);
List<RaycastHit> rayList3 = Physics.Raycast(new Ray(playerRayPos, dirNor), rayDistance * 0.75f, false, (ushort)65535);
if (rayList1.Count > 0 && rayList2.Count > 0 && rayList3.Count > 0)
{
RaycastHit ray1 = rayList1[0];
RaycastHit ray2 = rayList2[0];
RaycastHit ray3 = rayList3[0];
inRange = CheckForItem(ray1) || CheckForItem(ray2) || CheckForItem(ray3);
}
else
{
inRange = false;
}
}
}
private bool CheckForItem(RaycastHit ray)

View File

@ -0,0 +1,119 @@
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<RigidBody>();
collider = GetComponent<Collider>();
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, 8);
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;
}
}
}
}

View File

@ -0,0 +1,3 @@
Name: PhysicsTestObj
ID: 163401492
Type: 9

View File

@ -119,11 +119,11 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
#ifndef _PUBLISH
SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine>();
SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDraw>();
#endif
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
@ -206,27 +206,6 @@ namespace Sandbox
#else
SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime());
#endif
// TODO: Move into an Editor menu
static bool drawContacts = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9))
{
drawContacts = !drawContacts;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts);
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts);
}
static bool drawColliders = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10))
{
drawColliders = !drawColliders;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders);
}
static bool drawRays = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F11))
{
drawRays = !drawRays;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays);
}
}
// Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution();

View File

@ -44,23 +44,6 @@ namespace Sandbox
{
sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID);
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
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 */
/*-----------------------------------------------------------------------*/

View File

@ -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<SHRenderable, SHTransformComponent>();
@ -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.AddBoundingBox();
racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f));
racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
//racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
auto racoonItemLocation = SHEntityManager::CreateEntity<SHTransformComponent>();
auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s<SHTransformComponent>(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.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).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).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.AddBoundingBox();
AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
//AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
AIRigidBody.SetInterpolate(false);
AIRigidBody.SetFreezeRotationX(true);

View File

@ -10,7 +10,6 @@
#include "Scene/SHSceneManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Math/Geometry/SHBox.h"
#include "Math/SHRay.h"
#include "Physics/System/SHPhysicsSystem.h"
@ -162,9 +161,6 @@ namespace SHADE
SHTransformComponent* transform = SHComponentManager::GetComponent_s<SHTransformComponent>(pivot.GetEID());
auto physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (camera == nullptr || transform == nullptr)
return;
@ -180,29 +176,28 @@ namespace SHADE
camera->dirtyView = true;
}*/
pivot.ray.position = camera->GetPosition() + pivot.targetOffset;
pivot.ray.direction = SHVec3::Normalise((camera->position + offset)- pivot.ray.position);
//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");
//}
//
//
// pivot.rtMatrix = SHMatrix::Inverse(pivot.rtMatrix);

View File

@ -1,7 +1,7 @@
#include "SHpch.h"
#include "SHColliderTagPanel.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Editor/SHEditorWidgets.hpp"
namespace SHADE
@ -15,7 +15,7 @@ namespace SHADE
ImGui::TableNextRow();
ImGui::PushID("CollisionTagNames");
for (int i = SHCollisionTag::NUM_LAYERS; i >= 0; --i)
for (int i = SHCollisionTag::NUM_LAYERS; i >= 1; --i)
{
ImGui::TableNextColumn();
if(i == SHCollisionTag::NUM_LAYERS) continue;
@ -29,7 +29,7 @@ namespace SHADE
ImGui::PopID();
}
ImGui::PopID();
for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i)
for (int i = 0; i < SHCollisionTag::NUM_LAYERS - 1; ++i)
{
std::string tagName = SHCollisionTagMatrix::GetTagName(i);
auto tag = SHCollisionTagMatrix::GetTag(i);
@ -53,8 +53,8 @@ namespace SHADE
tagName2 = std::to_string(idx);
ImGui::TableNextColumn();
//if(i == idx)
// continue;
if(i == idx)
continue;
std::string label = std::format("##{} vs {}", tagName, tagName2);
SHEditorWidgets::CheckBox(label, [tag, &idx]{return tag->GetLayerState(idx);}, [tag, i, idx](bool const& value){tag->SetLayerState(idx, value); SHCollisionTagMatrix::GetTag(idx)->SetLayerState(i, value);}, label.substr(2));
}

View File

@ -18,12 +18,13 @@
#include "Physics/Interface/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Serialization/SHSerializationHelper.hpp"
#include "Tools/Utilities/SHClipboardUtilities.h"
#include "SHInspectorCommands.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Animation/SHAnimatorComponent.h"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "../SHEditorWindowManager.h"
#include "../AssetBrowser/SHAssetBrowser.h"
namespace SHADE
@ -304,7 +305,7 @@ namespace SHADE
{
SHEditorWidgets::DragVec3("Force", { "X", "Y", "Z" }, [component] {return component->GetForce(); }, [](SHVec3 const& value) {}, false, "Force", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly);
SHEditorWidgets::DragVec3("Torque", { "X", "Y", "Z" }, [component] {return component->GetTorque(); }, [](SHVec3 const& value) {}, false, "Torque", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly);
SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->GetIsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep");
SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->IsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep");
}
}
@ -336,6 +337,8 @@ namespace SHADE
{
DrawContextMenu(component);
SHEditorWidgets::CheckBox("Draw Colliders", [component] { return component->GetDebugDrawState(); }, [component](bool value) { component->SetDebugDrawState(value); });
auto& colliders = component->GetCollisionShapes();
int const size = static_cast<int>(colliders.size());
ImGui::BeginChild("Collision Shapes", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true);
@ -343,57 +346,57 @@ namespace SHADE
for (int i{}; i < size; ++i)
{
ImGui::PushID(i);
SHCollisionShape* collider = &component->GetCollisionShape(i);
SHCollisionShape* collisionShape = &component->GetCollisionShape(i);
auto cursorPos = ImGui::GetCursorPos();
if (collider->GetType() == SHCollisionShape::Type::BOX)
if (collisionShape->GetType() == SHCollisionShape::Type::BOX)
{
SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
const auto* BOX = reinterpret_cast<const SHBox*>(collider->GetShape());
auto* boxShape = dynamic_cast<SHBox*>(collisionShape);
SHEditorWidgets::DragVec3
(
"Half Extents", { "X", "Y", "Z" },
[BOX] { return BOX->GetRelativeExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
[boxShape] { return boxShape->GetRelativeExtents(); },
[boxShape](SHVec3 const& vec) { boxShape->SetRelativeExtents(vec); });
}
else if (collider->GetType() == SHCollisionShape::Type::SPHERE)
else if (collisionShape->GetType() == SHCollisionShape::Type::SPHERE)
{
SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
const auto* SPHERE = reinterpret_cast<const SHSphere*>(collider->GetShape());
auto* sphereShape = dynamic_cast<SHSphere*>(collisionShape);
SHEditorWidgets::DragFloat
(
"Radius",
[SPHERE] { return SPHERE->GetRelativeRadius(); },
[collider](float const& value) { collider->SetBoundingSphere(value); });
[sphereShape] { return sphereShape->GetRelativeRadius(); },
[sphereShape](float const& value) { sphereShape->SetRelativeRadius(value); });
}
else if (collider->GetType() == SHCollisionShape::Type::CAPSULE)
{
//else if (collisionShape->GetType() == SHCollisionShape::Type::CAPSULE)
//{
}
//}
{
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));});
SHEditorWidgets::CheckBox("Is Trigger", [collisionShape] { return collisionShape->IsTrigger(); }, [collisionShape](bool value) { collisionShape->SetIsTrigger(value); });
SHEditorWidgets::ComboBox("Tag", collisionTagNames, [collisionShape]{return SHCollisionTagMatrix::GetTagIndex(collisionShape->GetCollisionTag().GetName());}, [collisionShape](int const& value){collisionShape->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));});
if(ImGui::CollapsingHeader("Physics Material"))
{
SHEditorWidgets::DragFloat("Friction", [collider] { return collider->GetFriction(); }, [collider](float value) { collider->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f);
SHEditorWidgets::DragFloat("Bounciness", [collider] { return collider->GetBounciness(); }, [collider](float value) { collider->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f);
SHEditorWidgets::DragFloat("Mass Density", [collider] { return collider->GetDensity(); }, [collider](float value) { collider->SetDensity(value); }, "Mass Density", 0.1f, 0.0f);
SHEditorWidgets::DragFloat("Friction", [collisionShape] { return collisionShape->GetFriction(); }, [collisionShape](float value) { collisionShape->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f);
SHEditorWidgets::DragFloat("Bounciness", [collisionShape] { return collisionShape->GetBounciness(); }, [collisionShape](float value) { collisionShape->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f);
SHEditorWidgets::DragFloat("Mass Density", [collisionShape] { return collisionShape->GetDensity(); }, [collisionShape](float value) { collisionShape->SetDensity(value); }, "Mass Density", 0.1f, 0.0f);
}
SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collisionShape] {return collisionShape->GetPositionOffset(); }, [&collisionShape](SHVec3 const& vec) {collisionShape->SetPositionOffset(vec); });
SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" },
[&collider]
[&collisionShape]
{
auto offset = collider->GetRotationOffset();
auto offset = collisionShape->GetRotationOffset();
return offset;
},
[&collider](SHVec3 const& vec)
[&collisionShape](SHVec3 const& vec)
{
collider->SetRotationOffset(vec);
collisionShape->SetRotationOffset(vec);
}, true);
SHEditorWidgets::EndPanel();
}
@ -408,7 +411,7 @@ namespace SHADE
}
if (colliderToDelete.has_value())
{
component->RemoveCollider(colliderToDelete.value());
component->RemoveCollisionShape(colliderToDelete.value());
}
ImGui::EndChild();
@ -418,11 +421,11 @@ namespace SHADE
if (ImGui::Selectable("Box Collider"))
{
newColl = component->AddBoundingBox();
newColl = component->AddBoxCollisionShape(SHVec3::One);
}
if (ImGui::Selectable("Sphere Collider"))
{
newColl = component->AddBoundingSphere();
newColl = component->AddSphereCollisionShape(1.0f);
}
//No idea why this doesn't work

View File

@ -25,6 +25,7 @@
#include "Serialization/SHSerialization.h"
#include "Serialization/Configurations/SHConfigurationManager.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
#include "Physics/System/SHPhysicsDebugDrawSystem.h"
const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" };
@ -88,6 +89,7 @@ namespace SHADE
DrawThemeMenu();
DrawLayoutMenu();
DrawApplicationConfig();
DrawPhysicsSettings();
std::string const sceneName{std::format("Current Scene: {}",SHSceneManager::GetSceneName().data())};
auto const size = ImGui::CalcTextSize(sceneName.data());
@ -304,4 +306,27 @@ namespace SHADE
ImGui::EndMenu();
}
}
void SHEditorMenuBar::DrawPhysicsSettings() noexcept
{
if (ImGui::BeginMenu("Physics Settings"))
{
if (auto* physicsDebugDraw = SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>())
{
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);
}
ImGui::EndMenu();
}
}
}//namespace SHADE

View File

@ -26,6 +26,7 @@ namespace SHADE
void DrawThemeMenu() noexcept;
void DrawLayoutMenu() noexcept;
void DrawApplicationConfig() noexcept;
void DrawPhysicsSettings() noexcept;
float menuBarHeight = 20.0f;
std::vector<std::filesystem::path> layoutPaths;

View File

@ -24,4 +24,5 @@ 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 };

View File

@ -1,250 +0,0 @@
/****************************************************************************************
* \file SHBox.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation 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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHBox.h"
// Project Headers
#include "Math/SHMathHelpers.h"
#include "Math/SHRay.h"
using namespace DirectX;
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox::SHBox() noexcept
: RelativeExtents { SHVec3::One }
{
type = Type::BOX;
}
SHBox::SHBox(const SHVec3& c, const SHVec3& hE) noexcept
: RelativeExtents { SHVec3::One }
{
type = Type::BOX;
Center = c;
Extents = hE;
}
SHBox::SHBox(const SHBox& rhs) noexcept
{
if (this == &rhs)
return;
type = Type::BOX;
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
SHBox::SHBox(SHBox&& rhs) noexcept
{
type = Type::BOX;
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox& SHBox::operator=(const SHBox& rhs) noexcept
{
if (rhs.type != Type::BOX)
{
SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!")
}
else if (this != &rhs)
{
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
return *this;
}
SHBox& SHBox::operator=(SHBox&& rhs) noexcept
{
if (rhs.type != Type::BOX)
{
SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!")
}
else
{
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
return *this;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHBox::GetCenter() const noexcept
{
return Center;
}
SHVec3 SHBox::GetWorldExtents() const noexcept
{
return Extents;
}
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 SHBox::GetMax() const noexcept
{
return SHVec3{ Center.x + Extents.x, Center.y + Extents.y, Center.z + Extents.z };
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHBox::SetCenter(const SHVec3& newCenter) noexcept
{
Center = newCenter;
}
void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
{
Extents = newWorldExtents;
}
void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
{
RelativeExtents = newRelativeExtents;
}
void SHBox::SetMin(const SHVec3& min) noexcept
{
const SHVec3 MAX = GetMax();
Center = SHVec3::Lerp(min, MAX, 0.5f);
Extents = SHVec3::Abs((MAX - min) * 0.5f);
}
void SHBox::SetMax(const SHVec3& max) noexcept
{
const SHVec3 MIN = GetMin();
Center = SHVec3::Lerp(MIN, max, 0.5f);
Extents = SHVec3::Abs((max - MIN) * 0.5f);
}
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<SHVec3> SHBox::GetVertices() const noexcept
{
std::vector<SHVec3> vertices{ 8 };
GetCorners(vertices.data());
return vertices;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHBox::TestPoint(const SHVec3& point) const noexcept
{
return BoundingBox::Contains(point);
}
SHRaycastResult SHBox::Raycast(const SHRay& ray) const noexcept
{
SHRaycastResult result;
result.hit = Intersects(ray.position, ray.direction, result.distance);
if (result.hit)
{
result.position = ray.position + ray.direction * result.distance;
result.angle = SHVec3::Angle(ray.position, result.position);
}
return result;
}
bool SHBox::Contains(const SHBox& rhs) const noexcept
{
return BoundingBox::Contains(rhs);
}
float SHBox::Volume() const noexcept
{
return 8.0f * (Extents.x * Extents.y * Extents.z);
}
float SHBox::SurfaceArea() const noexcept
{
return 8.0f * ((Extents.x * Extents.y)
+ (Extents.x * Extents.z)
+ (Extents.y * Extents.z));
}
/*-----------------------------------------------------------------------------------*/
/* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox SHBox::Combine(const SHBox& lhs, const SHBox& rhs) noexcept
{
SHBox result;
CreateMerged(result, lhs, rhs);
return result;
}
bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept
{
return lhs.Intersects(rhs);
}
SHBox SHBox::BuildFromBoxes(const SHBox* boxes, size_t numBoxes) noexcept
{
SHBox result;
for (size_t i = 1; i < numBoxes; ++i)
CreateMerged(result, boxes[i - 1], boxes[i]);
return result;
}
SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
{
SHBox result;
CreateFromPoints(result, numVertices, vertices, stride);
return result;
}
} // namespace SHADE

View File

@ -1,105 +0,0 @@
/****************************************************************************************
* \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 <DirectXCollision.h>
// 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<SHVec3> 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

View File

@ -1,208 +0,0 @@
/****************************************************************************************
* \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 <SHpch.h>
// 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

View File

@ -10,6 +10,8 @@
#include <SHpch.h>
#include <reactphysics3d/mathematics/Ray.h>
// Primary Header
#include "SHRay.h"
@ -30,7 +32,7 @@ namespace SHADE
, direction { dir }
{}
SHRay::SHRay(const reactphysics3d::Ray rp3dRay) noexcept
SHRay::SHRay(const reactphysics3d::Ray& rp3dRay) noexcept
: position { rp3dRay.point1 }
, direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) }
{}

View File

@ -16,8 +16,13 @@
#include "SH_API.h"
#include "Vector/SHVec3.h"
/*-------------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-------------------------------------------------------------------------------------*/
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
@ -40,7 +45,7 @@ namespace SHADE
SHRay () noexcept;
SHRay (const SHVec3& pos, const SHVec3& dir) noexcept;
SHRay (const reactphysics3d::Ray rp3dRay) noexcept;
SHRay (const reactphysics3d::Ray& rp3dRay) noexcept;
SHRay (const SHRay&) noexcept = default;
SHRay (SHRay&& ) noexcept = default;

View File

@ -246,8 +246,6 @@ namespace SHADE
tf.world.position = SHVec3::Transform(tf.local.position, localToWorld);
tf.world.scale = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One);
if (convertRotation)
{
tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);

View File

@ -14,18 +14,36 @@
// Primary Header
#include "SHCollisionTagMatrix.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHCollisionTagMatrix::dirty = true;
SHCollisionTag SHCollisionTagMatrix::collisionTags[SHCollisionTag::NUM_LAYERS];
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHCollisionTagMatrix::IsDirty() noexcept
{
// Check if any collision tag is dirty
for (auto& tag : collisionTags)
{
if (tag.IsDirty())
{
dirty = true;
break;
}
}
return dirty;
}
const std::string& SHCollisionTagMatrix::GetTagName(int tagIndex)
{
if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS)
@ -91,6 +109,8 @@ namespace SHADE
if (collisionTag.GetName() != tagName)
continue;
dirty = true;
collisionTag = newTag;
return;
}
@ -105,6 +125,8 @@ namespace SHADE
if (collisionTag.GetName() != tagName)
continue;
dirty = true;
collisionTag.SetMask(mask);
return;
}
@ -125,6 +147,8 @@ namespace SHADE
if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS)
throw std::invalid_argument("Index out of range!");
dirty = true;
collisionTags[tagIndex] = newTag;
}
@ -133,6 +157,8 @@ namespace SHADE
if (tagIndex < 0 || tagIndex > SHCollisionTag::NUM_LAYERS)
throw std::invalid_argument("Index out of range!");
dirty = true;
collisionTags[tagIndex].SetMask(mask);
}
@ -145,8 +171,9 @@ namespace SHADE
/**
* I HATE FILE IO
*
* Each line in the file should be "index<space>tag name".
* If the line fails to follow this format, use the default tag name (index + 1)
* Each line in the file should be "index<space>tag name<space>mask".
* If the line fails to follow this format, use the default tag name (index + 1) and default mask.
* If no mask was read, use a default mask.
*/
// Populate tag names with default
@ -187,18 +214,40 @@ namespace SHADE
{
SHLOG_ERROR
(
"Collision tag file line {} does not match the required format of 'index<space>tag name'. Default tag used for index {}"
"Collision tag file line {} does not match the required format of 'index<space>tag name<space>mask'. 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<uint16_t>::max();
if (maskString.empty())
{
SHLOG_ERROR
(
"Collision tag file line {} does not match the required format of 'index<space>tag name<space>mask'. Default mask used for index {}"
, linesRead + 1
, tagIndex
)
}
else
{
mask = static_cast<uint16_t>(std::stoi(maskString));
}
collisionTags[tagIndex].SetMask(mask);
ss.clear();
}
@ -215,9 +264,19 @@ namespace SHADE
return;
}
// Index Name Mask
for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i)
collisionTagNamesFile << i << " " << collisionTags[i].GetName() << std::endl;
collisionTagNamesFile << i << " " << collisionTags[i].GetName() << " " << collisionTags[i].GetMask() << std::endl;
collisionTagNamesFile.close();
}
void SHCollisionTagMatrix::Clear() noexcept
{
dirty = false;
for (auto& tag : collisionTags)
tag.dirty = false;
}
} // namespace SHADE

View File

@ -29,6 +29,7 @@ namespace SHADE
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static bool IsDirty () noexcept;
[[nodiscard]] static const std::string& GetTagName (int tagIndex);
[[nodiscard]] static int GetTagIndex (const std::string& tagName) noexcept;
@ -57,11 +58,18 @@ namespace SHADE
static void Init (const std::filesystem::path& tagNameFilePath) noexcept;
static void Exit (const std::filesystem::path& tagNameFilePath) noexcept;
/**
* @brief
* Clears the dirty flag.
*/
static void Clear () noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static bool dirty;
static SHCollisionTag collisionTags[SHCollisionTag::NUM_LAYERS];
};
}

View File

@ -23,15 +23,18 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
SHCollisionTag::SHCollisionTag() noexcept
: mask { SHUtilities::ConvertEnum(Layer::ALL) }
: dirty { true }
, mask { SHUtilities::ConvertEnum(Layer::ALL) }
{}
SHCollisionTag::SHCollisionTag(uint16_t _mask) noexcept
: mask { _mask }
: dirty { true }
, mask { _mask }
{}
SHCollisionTag::SHCollisionTag(Layer layer) noexcept
: mask { SHUtilities::ConvertEnum(layer) }
: dirty { true }
, mask { SHUtilities::ConvertEnum(layer) }
{}
/*-----------------------------------------------------------------------------------*/
@ -57,6 +60,11 @@ namespace SHADE
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHCollisionTag::IsDirty() const noexcept
{
return dirty;
}
uint16_t SHCollisionTag::GetMask() const noexcept
{
return mask;
@ -86,6 +94,7 @@ namespace SHADE
void SHCollisionTag::SetMask(uint16_t newMask) noexcept
{
dirty = true;
mask = newMask;
}
@ -96,6 +105,8 @@ namespace SHADE
void SHCollisionTag::SetLayerState(Layer layer, bool state) noexcept
{
dirty = true;
const auto VALUE = SHUtilities::ConvertEnum(layer);
state ? mask |= VALUE : mask &= ~(VALUE);
}
@ -105,6 +116,8 @@ namespace SHADE
if (layerIndex < 0 || layerIndex > NUM_LAYERS)
throw std::invalid_argument("Index out of range!");
dirty = true;
const auto VALUE = 1U << layerIndex;
state ? mask |= (VALUE) : mask &= ~(VALUE);
}

View File

@ -23,6 +23,13 @@ namespace SHADE
class SH_API SHCollisionTag
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHCollisionTagMatrix;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -82,6 +89,7 @@ namespace SHADE
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool IsDirty () const noexcept;
[[nodiscard]] uint16_t GetMask () const noexcept;
[[nodiscard]] const std::string& GetName () const noexcept;
[[nodiscard]] bool GetLayerState (Layer layer) const noexcept;
@ -101,6 +109,7 @@ namespace SHADE
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool dirty;
uint16_t mask;
std::string name;
};

View File

@ -1,350 +0,0 @@
/****************************************************************************************
* \file SHPhysicsRaycaster.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Raycaster.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// 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<float>::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<float>::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<int>(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<float>::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<int>(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<int>(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

View File

@ -1,134 +0,0 @@
/****************************************************************************************
* \file SHPhysicsRaycaster.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Raycaster.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <vector>
#include <reactphysics3d/reactphysics3d.h>
// 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<SHRay, SHPhysicsRaycastResult>;
using RaycastPairs = std::vector<RaycastPair>;
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<float>::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<float>::infinity()
) noexcept;
SHPhysicsRaycastResult ColliderRaycast
(
EntityID eid
, int shapeIndex
, const SHRay& ray
, float distance = std::numeric_limits<float>::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

View File

@ -0,0 +1,120 @@
/****************************************************************************************
* \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 <SHpch.h>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHBox.h"
// Project Headers
#include "Math/SHMatrix.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox::SHBox() noexcept
: SHCollisionShape (Type::BOX)
, relativeExtents { SHVec3::One }
, scale { SHVec3::One }
{
if (rp3dCollider)
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(SHVec3::One * 0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHBox::GetWorldExtents() const noexcept
{
if (rp3dCollider)
return SHVec3{ dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->getHalfExtents() };
return relativeExtents * scale * 0.5f;
}
SHVec3 SHBox::GetRelativeExtents() const noexcept
{
return relativeExtents;
}
SHVec3 SHBox::GetWorldCentroid() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
return SHVec3::Transform(positionOffset, TRS);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
{
if (rp3dCollider)
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(newWorldExtents);
// Recompute Relative radius
relativeExtents = 2.0f * newWorldExtents / scale;
}
void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
{
relativeExtents = newRelativeExtents;
// Recompute world radius
if (rp3dCollider)
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(relativeExtents * scale * 0.5f);
}
void SHBox::SetScale(const SHVec3& newScale) noexcept
{
scale = SHVec3::Abs(newScale);
// Recompute world radius
if (rp3dCollider)
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(relativeExtents * scale * 0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHBox::Update() noexcept
{
const SHTransform& PARENT_TRANSFORM = collider->GetTransform();
SetScale(PARENT_TRANSFORM.scale);
SHCollisionShape::Update();
}
SHMatrix SHBox::GetTRS() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHVec3 SCALE = GetWorldExtents() * 2.0f;
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
const SHVec3 POSITION = SHVec3::Transform(positionOffset, TRS);
return SHMatrix::Transform(POSITION, ROTATION, SCALE);
}
} // namespace SHADE

View File

@ -1,7 +1,7 @@
/****************************************************************************************
* \file SHShape.h
* \file SHBox.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a shape.
* \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
@ -11,9 +11,7 @@
#pragma once
// Project Headers
#include "SH_API.h"
#include "Math/SHRay.h"
#include "SHCollisionShape.h"
namespace SHADE
{
@ -21,62 +19,61 @@ namespace SHADE
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHShape
/**
* @brief
* Encapsulate a Box Shape used for Physics Simulations.
*/
class SH_API SHBox final : public SHCollisionShape
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHColliderComponent;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Type
{
BOX
, SPHERE
, CAPSULE
, CONVEX_HULL
, COUNT
, NONE = -1
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool isIntersecting;
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
virtual ~SHShape () = default;
SHBox () noexcept;
~SHBox () override = default;
SHShape (const SHShape&) = default;
SHShape (SHShape&&) = default;
SHShape& operator=(const SHShape&) = default;
SHShape& operator=(SHShape&&) = default;
SHShape();
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] SHVec3 GetWorldExtents () const noexcept;
[[nodiscard]] SHVec3 GetRelativeExtents () const noexcept;
[[nodiscard]] SHVec3 GetWorldCentroid () 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 */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0;
[[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0;
void Update () noexcept override;
[[nodiscard]] SHMatrix GetTRS () const noexcept override;
protected:
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
Type type;
SHVec3 relativeExtents;
SHVec3 scale;
};
} // namespace SHADE

View File

@ -0,0 +1,232 @@
/****************************************************************************************
* \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 <SHpch.h>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHCollisionShape.h"
// Project Headers
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Reflection/SHReflectionMetadata.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionShape::SHCollisionShape(Type colliderType)
: rp3dCollider { nullptr }
, collider { nullptr }
, collisionTag { SHCollisionTagMatrix::GetTag(0) }
, flags { 0 }
{
flags |= 1U << SHUtilities::ConvertEnum(colliderType);
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
float SHCollisionShape::GetFriction() const noexcept
{
return material.GetFriction();
}
float SHCollisionShape::GetBounciness() const noexcept
{
return material.GetBounciness();
}
float SHCollisionShape::GetDensity() const noexcept
{
return material.GetDensity();
}
const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept
{
return material;
}
const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept
{
return positionOffset;
}
const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept
{
return rotationOffset;
}
SHCollisionShape::Type SHCollisionShape::GetType() const noexcept
{
for (int i = 0; i < SHUtilities::ConvertEnum(Type::COUNT); ++i)
{
const uint8_t FLAG_VALUE = 1U << SHUtilities::ConvertEnum(static_cast<Type>(i));
if (flags & FLAG_VALUE)
return static_cast<Type>(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;
}
SHVec3 SHCollisionShape::GetWorldCentroid() const noexcept
{
return collider->GetTransform().position;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept
{
collisionTag = newCollisionTag;
if (rp3dCollider)
rp3dCollider->setCollideWithMaskBits(collisionTag->GetMask());
}
void SHCollisionShape::SetFriction(float friction) noexcept
{
material.SetFriction(friction);
if (rp3dCollider)
rp3dCollider->getMaterial().setFrictionCoefficient(material.GetFriction());
}
void SHCollisionShape::SetBounciness(float bounciness) noexcept
{
material.SetBounciness(bounciness);
if (rp3dCollider)
rp3dCollider->getMaterial().setBounciness(material.GetBounciness());
}
void SHCollisionShape::SetDensity(float density) noexcept
{
material.SetDensity(density);
if (rp3dCollider)
rp3dCollider->getMaterial().setMassDensity(material.GetDensity());
}
void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept
{
material = newMaterial;
if (rp3dCollider)
{
auto& rp3dMaterial = rp3dCollider->getMaterial();
rp3dMaterial.setFrictionCoefficient(material.GetFriction());
rp3dMaterial.setBounciness(material.GetBounciness());
rp3dMaterial.setMassDensity(material.GetDensity());
}
}
void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept
{
positionOffset = posOffset;
Update();
}
void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept
{
rotationOffset = rotOffset;
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;
if (rp3dCollider)
rp3dCollider->setIsTrigger(isTrigger);
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::UpdateCollisionTags() noexcept
{
if (collisionTag->IsDirty())
rp3dCollider->setCollideWithMaskBits(collisionTag->GetMask());
}
void SHCollisionShape::Update() noexcept
{
if (rp3dCollider)
{
const rp3d::Transform OFFSETS{ positionOffset, SHQuaternion::FromEuler(rotationOffset) };
rp3dCollider->setLocalToBodyTransform(OFFSETS);
}
}
SHMatrix SHCollisionShape::GetTRS() const noexcept
{
return SHMatrix::Identity;
}
} // namespace SHADE
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::enumeration<SHCollisionShape::Type>("Collider Type")
(
value("Box", SHCollisionShape::Type::BOX),
value("Sphere", SHCollisionShape::Type::SPHERE)
// TODO(Diren): Add More Shapes
);
registration::class_<SHCollisionShape>("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));
}

View File

@ -0,0 +1,164 @@
/****************************************************************************************
* \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 <rttr/registration>
#include <reactphysics3d/collision/Collider.h>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "Physics/Collision/CollisionTags/SHCollisionTags.h"
#include "Physics/Collision/SHPhysicsMaterial.h"
#include "Math/Transform/SHTransform.h"
#include "Physics/Collision/SHPhysicsRaycastResult.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHColliderComponent;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHCollisionShape
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
friend class SHPhysicsObjectManager;
friend class SHColliderComponent;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Type
{
SPHERE
, BOX
, COUNT
, INVALID = -1
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHCollisionShape(Type colliderType = Type::INVALID);
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 */
/*---------------------------------------------------------------------------------*/
// 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;
[[nodiscard]] virtual SHVec3 GetWorldCentroid() const noexcept;
/*---------------------------------------------------------------------------------*/
/* 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;
// Forces rigidbody to recompute mass if one exists
void SetIsTrigger(bool isTrigger) noexcept;
/*---------------------------------------------------------------------------------*/
/* Member Functions */
/*---------------------------------------------------------------------------------*/
/**
* @brief
* Re-sets the collision tags if it is dirty.
*/
void UpdateCollisionTags() noexcept;
/**
* @brief
* Computes the transform of the shape.
*/
virtual void Update() noexcept;
/**
* @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;
protected:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
reactphysics3d::Collider* rp3dCollider;
SHColliderComponent* collider; // The collider it belongs to.
SHCollisionTag* collisionTag;
SHPhysicsMaterial material; // TODO: Change to pointer once instancing is supported
SHVec3 positionOffset;
SHVec3 rotationOffset;
uint8_t flags; // 0 0 0 trigger 0 capsule sphere box
RTTR_ENABLE()
};
}

View File

@ -0,0 +1,122 @@
/****************************************************************************************
* \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 <SHpch.h>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHSphere.h"
// Project Headers
#include "Math/SHMathHelpers.h"
#include "Math/SHMatrix.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHSphere::SHSphere() noexcept
: SHCollisionShape (Type::SPHERE)
, relativeRadius { 1.0f }
, scale { 1.0f }
{
if (rp3dCollider)
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
float SHSphere::GetWorldRadius() const noexcept
{
if (rp3dCollider)
return dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->getRadius();
return relativeRadius * scale * 0.5f;
}
float SHSphere::GetRelativeRadius() const noexcept
{
return relativeRadius;
}
SHVec3 SHSphere::GetWorldCentroid() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
return SHVec3::Transform(positionOffset, TRS);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHSphere::SetWorldRadius(float newWorldRadius) noexcept
{
if (rp3dCollider)
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(newWorldRadius);
// Recompute Relative radius
relativeRadius = 2.0f * newWorldRadius / scale;
}
void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept
{
relativeRadius = newRelativeRadius;
// Recompute world radius
if (rp3dCollider)
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(relativeRadius * scale * 0.5f);
}
void SHSphere::SetScale(float maxScale) noexcept
{
scale = std::fabs(maxScale);
// Recompute world radius
if (rp3dCollider)
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(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);
SHCollisionShape::Update();
}
SHMatrix SHSphere::GetTRS() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHVec3 SCALE = GetWorldRadius();
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
const SHVec3 POSITION = SHVec3::Transform(positionOffset, TRS);
return SHMatrix::Transform(POSITION, ROTATION, SCALE);
}
} // namespace SHADE

View File

@ -1,7 +1,7 @@
/****************************************************************************************
* \file SHBoundingSphere.h
* \file SHSphereCollisionShape.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Bounding Sphere.
* \brief Interface for a Sphere Collision Shape.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
@ -10,11 +10,8 @@
#pragma once
#include <DirectXCollision.h>
// Project Headers
#include "SHShape.h"
#include "SH_API.h"
#include "SHCollisionShape.h"
namespace SHADE
{
@ -22,71 +19,61 @@ namespace SHADE
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHSphere : public SHShape,
private DirectX::BoundingSphere
/**
* @brief
* Encapsulate a Sphere Shape used for Physics Simulations.
*/
class SH_API SHSphere final : public SHCollisionShape
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHColliderComponent;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHSphere () noexcept;
SHSphere (const SHVec3& center, float radius) noexcept;
SHSphere (const SHSphere& rhs) noexcept;
SHSphere (SHSphere&& rhs) noexcept;
~SHSphere () override = default;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHSphere& operator= (const SHSphere& rhs) noexcept;
SHSphere& operator= (SHSphere&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetCenter () const noexcept;
[[nodiscard]] float GetWorldRadius () const noexcept;
[[nodiscard]] float GetRelativeRadius () const noexcept;
[[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override;
/*---------------------------------------------------------------------------------*/
/* 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 */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override;
[[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override;
[[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept;
[[nodiscard]] float Volume () const noexcept;
[[nodiscard]] float SurfaceArea () const noexcept;
/*---------------------------------------------------------------------------------*/
/* 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;
void Update () noexcept override;
[[nodiscard]] SHMatrix GetTRS () const noexcept override;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
float RelativeRadius;
float relativeRadius;
float scale;
};
} // namespace SHADE
}

View File

@ -1,7 +1,7 @@
/****************************************************************************************
* \file SHShape.cpp
* \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a shape.
* \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
@ -11,25 +11,25 @@
#include <SHpch.h>
// Primary Header
#include "SHShape.h"
#include "SHPhysicsObject.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/* Constructor & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHShape::SHShape()
: type { Type::NONE }
SHPhysicsObject::SHPhysicsObject(EntityID eid) noexcept
: entityID { eid }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHShape::Type SHShape::GetType() const noexcept
SHPhysicsObject::~SHPhysicsObject() noexcept
{
return type;
entityID = MAX_EID;
body = nullptr;
}
} // namespace SHADE

View File

@ -0,0 +1,48 @@
/****************************************************************************************
* \file SHPhysicsObject.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Object.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
namespace SHADE
{
/*-------------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------------------*/
/**
* @brief
* Encapsulates a rigid body and a collider tied to an Entity.
*/
struct SH_API SHPhysicsObject
{
public:
/*-----------------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------------*/
// We use a rigid body all the time. Colliders without rigid bodies have a static body.
EntityID entityID = MAX_EID;
rp3d::RigidBody* body = nullptr;
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject (EntityID eid) noexcept;
~SHPhysicsObject () noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,429 @@
/****************************************************************************************
* \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 <SHpch.h>
// Primary Header
#include "SHPhysicsObjectManager.h"
// Project Headers
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::SHPhysicsObjectManager() noexcept
: factory { nullptr }
, physicsWorld { nullptr }
{}
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;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::SetFactory(rp3d::PhysicsCommon* physicsFactory) noexcept
{
factory = physicsFactory;
}
void SHPhysicsObjectManager::SetPhysicsWorld(rp3d::PhysicsWorld* world) noexcept
{
physicsWorld = world;
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::AddRigidBody(EntityID entityID) noexcept
{
SHASSERT(physicsWorld, "Physics World Missing ffrom Physics Object Manager!")
SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID);
// Get the rigidbody and transform components
auto* rigidBodyComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (!physicsObject->body)
{
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a rigid body for Entity {} with missing transform!", entityID)
return;
}
// Create a new rigidbody in the physics object
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
}
// Link with the component
rigidBodyComponent->SetRigidBody(physicsObject->body);
// Reset the type
const auto RIGID_BODY_TYPE = rigidBodyComponent->GetType();
switch (RIGID_BODY_TYPE)
{
case SHRigidBodyComponent::Type::STATIC:
physicsObject->body->setType(rp3d::BodyType::STATIC);
break;
case SHRigidBodyComponent::Type::KINEMATIC:
physicsObject->body->setType(rp3d::BodyType::KINEMATIC);
break;
case SHRigidBodyComponent::Type::DYNAMIC:
physicsObject->body->setType(rp3d::BodyType::DYNAMIC);
break;
default:
break;
}
}
void SHPhysicsObjectManager::RemoveRigidBody(EntityID entityID) noexcept
{
SHASSERT(physicsWorld, "Physics World Missing from Physics Object Manager!")
const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID);
if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end())
return;
SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second;
// If a collider component exists, we just set the body to static
if (SHComponentManager::GetComponent_s<SHColliderComponent>(entityID))
physicsObject->body->setType(rp3d::BodyType::STATIC);
else
{
physicsWorld->destroyRigidBody(physicsObject->body);
destroyPhysicsObject(entityID);
}
}
void SHPhysicsObjectManager::AddCollider(EntityID entityID) noexcept
{
SHASSERT(physicsWorld, "Physics World Missing from Physics Object Manager!")
SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID);
// Get the collider & transform component
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
// Check if a body already exists. If it does, link it with the component
if (!physicsObject->body)
{
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a collider for Entity {} with missing transform!", entityID)
return;
}
// Create a static body
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
physicsObject->body->setType(rp3d::BodyType::STATIC);
}
// Link with component
colliderComponent->SetFactory(factory);
colliderComponent->SetCollisionBody(physicsObject->body);
}
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;
// Remove all collision shapes from the body
int32_t numShapes = static_cast<int32_t>(physicsObject->body->getNbColliders());
while (--numShapes >= 0)
{
auto* rp3dCollider = physicsObject->body->getCollider(numShapes);
physicsObject->body->removeCollider(rp3dCollider);
}
// Destroy if no rigidbody component
if (!SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID))
destroyPhysicsObject(entityID);
}
}
void SHPhysicsObjectManager::RemoveAllObjects() noexcept
{
// Physics objects itself will delete the object
physicsObjects.clear();
}
void SHPhysicsObjectManager::AddRigidBodyDef(EntityID entityID) noexcept
{
auto* rigidBody = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
const SHRigidBodyDef RIGID_BODY_DEF
{
.entityID = rigidBody->GetEID()
, .bodyType = rigidBody->type
, .interpolate = rigidBody->interpolate
, .drag = rigidBody->drag
, .angularDrag = rigidBody->angularDrag
};
rigidBodyQueue.push(RIGID_BODY_DEF);
}
void SHPhysicsObjectManager::AddColliderDef(EntityID entityID) noexcept
{
auto* collider = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
SHColliderDef colliderDef
{
.entityID = collider->GetEID()
};
for (const auto* shape : collider->shapes)
{
SHColliderDef::ShapeDef shapeDef
{
.type = shape->GetType()
, .posOffset = shape->GetPositionOffset()
, .rotOffset = shape->GetRotationOffset()
};
switch (shape->GetType())
{
case SHCollisionShape::Type::SPHERE:
shapeDef.size.x = dynamic_cast<const SHSphere*>(shape)->GetWorldRadius();
break;
case SHCollisionShape::Type::BOX:
shapeDef.size = dynamic_cast<const SHBox*>(shape)->GetWorldExtents();
break;
default:
break;
}
colliderDef.shapes.emplace_back(shapeDef);
}
colliderQueue.push(colliderDef);
}
void SHPhysicsObjectManager::FlushDefinitions() noexcept
{
SHASSERT(physicsWorld, "Physics World Missing ffrom Physics Object Manager!")
// Flush all rigid bodies
while (!rigidBodyQueue.empty())
{
const SHRigidBodyDef& DEF = rigidBodyQueue.front();
SHPhysicsObject* physicsObject = ensurePhysicsObject(DEF.entityID);
// Get transform component
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(DEF.entityID);
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a rigid body for Entity {} with missing transform!", DEF.entityID)
rigidBodyQueue.pop();
continue;
}
// Create a new rigidbody in the physics object
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
// Get rigidBody component
auto* rigidBodyComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(DEF.entityID);
rigidBodyComponent->SetRigidBody(physicsObject->body);
// Set type
rigidBodyComponent->type = DEF.bodyType;
switch (DEF.bodyType)
{
case SHRigidBodyComponent::Type::STATIC:
physicsObject->body->setType(rp3d::BodyType::STATIC);
break;
case SHRigidBodyComponent::Type::KINEMATIC:
physicsObject->body->setType(rp3d::BodyType::KINEMATIC);
break;
case SHRigidBodyComponent::Type::DYNAMIC:
physicsObject->body->setType(rp3d::BodyType::DYNAMIC);
break;
default:
break;
}
// Re-set properties
rigidBodyComponent->SetGravityEnabled (rigidBodyComponent->IsGravityEnabled());
rigidBodyComponent->SetIsAllowedToSleep (rigidBodyComponent->IsAllowedToSleep());
rigidBodyComponent->SetFreezePositionX (rigidBodyComponent->GetFreezePositionX());
rigidBodyComponent->SetFreezePositionY (rigidBodyComponent->GetFreezePositionY());
rigidBodyComponent->SetFreezePositionZ (rigidBodyComponent->GetFreezePositionZ());
rigidBodyComponent->SetFreezeRotationX (rigidBodyComponent->GetFreezeRotationX());
rigidBodyComponent->SetFreezeRotationY (rigidBodyComponent->GetFreezeRotationY());
rigidBodyComponent->SetFreezeRotationZ (rigidBodyComponent->GetFreezeRotationZ());
rigidBodyComponent->SetInterpolate (DEF.interpolate);
rigidBodyComponent->SetDrag (DEF.drag);
rigidBodyComponent->SetAngularDrag (DEF.angularDrag);
rigidBodyQueue.pop();
}
// Flush all colliders
while (!colliderQueue.empty())
{
const SHColliderDef& DEF = colliderQueue.front();
SHPhysicsObject* physicsObject = ensurePhysicsObject(DEF.entityID);
// Get transform component
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(DEF.entityID);
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a collider for Entity {} with missing transform!", DEF.entityID)
colliderQueue.pop();
continue;
}
if (!physicsObject->body)
{
// Create a static body
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
physicsObject->body->setType(rp3d::BodyType::STATIC);
}
// Get rigidBody component
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(DEF.entityID);
colliderComponent->SetFactory(factory);
colliderComponent->SetCollisionBody(physicsObject->body);
// Add all shapes
for (size_t i = 0; i < colliderComponent->shapes.size(); ++i)
{
// Get the currrent shape
auto& collisionShape = colliderComponent->shapes[i];
// Add the rp3d collider to the shade collision shape
switch (collisionShape->GetType())
{
case SHCollisionShape::Type::SPHERE:
{
auto* sphereShape = dynamic_cast<SHSphere*>(collisionShape);
const float SPHERE_SCALE = std::fabs(SHMath::Max({ colliderComponent->transform.scale.x, colliderComponent->transform.scale.y, colliderComponent->transform.scale.z }));
rp3d::SphereShape* rp3dSphere = factory->createSphereShape(sphereShape->GetRelativeRadius() * SPHERE_SCALE * 0.5f);
const rp3d::Transform OFFSETS{ sphereShape->GetPositionOffset(), SHQuaternion::FromEuler(sphereShape->GetRotationOffset()) };
sphereShape->rp3dCollider = physicsObject->body->addCollider(rp3dSphere, OFFSETS);
sphereShape->rp3dCollider->setIsTrigger(sphereShape->IsTrigger());
break;
}
case SHCollisionShape::Type::BOX:
{
auto* boxShape = dynamic_cast<SHBox*>(collisionShape);
rp3d::BoxShape* rp3dBox = factory->createBoxShape(boxShape->GetRelativeExtents() * colliderComponent->transform.scale * 0.5f);
const rp3d::Transform OFFSETS{ boxShape->GetPositionOffset(), SHQuaternion::FromEuler(boxShape->GetRotationOffset()) };
boxShape->rp3dCollider = physicsObject->body->addCollider(rp3dBox, OFFSETS);
boxShape->rp3dCollider->setIsTrigger(boxShape->IsTrigger());
break;
}
default: break;
}
collisionShape->SetMaterial(collisionShape->GetMaterial());
const auto& COLLISION_TAG = collisionShape->GetCollisionTag();
collisionShape->SetCollisionTag(SHCollisionTagMatrix::GetTag(COLLISION_TAG.GetName()));
}
physicsObject->body->updateMassPropertiesFromColliders();
colliderQueue.pop();
}
}
/*-----------------------------------------------------------------------------------*/
/* 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

View File

@ -0,0 +1,182 @@
/****************************************************************************************
* \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 <vector>
#include <queue>
#include <unordered_map>
// Project Headers
#include "SHPhysicsObject.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.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<EntityID, SHPhysicsObject>;
public:
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHRigidBodyDef
{
EntityID entityID = MAX_EID;
SHRigidBodyComponent::Type bodyType = SHRigidBodyComponent::Type::STATIC;
bool interpolate = true;
float drag = 0.0f;
float angularDrag = 0.0f;
};
struct SHColliderDef
{
struct ShapeDef
{
SHCollisionShape::Type type = SHCollisionShape::Type::SPHERE;
SHVec3 posOffset = SHVec3::Zero;
SHVec3 rotOffset = SHVec3::Zero;
SHVec3 size = SHVec3::Zero; // x for sphere radius, all 3 for box extents
};
EntityID entityID = MAX_EID;
std::vector<ShapeDef> shapes;
};
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager () noexcept;
~SHPhysicsObjectManager () noexcept;
/*-----------------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------------*/
[[nodiscard]] EntityObjectMap& GetPhysicsObjects () noexcept;
[[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
/*-----------------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------------*/
void SetFactory (rp3d::PhysicsCommon* physicsFactory) noexcept;
void SetPhysicsWorld(rp3d::PhysicsWorld* world) 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) 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;
/**
* @brief Adds a rigidbody definition to add to the physics world.
* @param rigidBody
* The rigidbody component
*/
void AddRigidBodyDef (EntityID entityID) noexcept;
/**
* @brief Adds a collider definition to add to the physics world.
* @param collider
* The collider component
*/
void AddColliderDef (EntityID entityID) noexcept;
/**
* @brief Adds all loaded definitions into the physics world.
*/
void FlushDefinitions () noexcept;
private:
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
using RigidBodyQueue = std::queue<SHRigidBodyDef>;
using ColliderQueue = std::queue<SHColliderDef>;
/*-----------------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------------*/
rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* physicsWorld;
EntityObjectMap physicsObjects;
RigidBodyQueue rigidBodyQueue;
ColliderQueue colliderQueue;
/*-----------------------------------------------------------------------------------*/
/* Member Functions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* createPhysicsObject (EntityID entityID);
SHPhysicsObject* ensurePhysicsObject (EntityID entityID);
void destroyPhysicsObject (EntityID entityID);
};
} // namespace SHADE

View File

@ -9,6 +9,7 @@
****************************************************************************************/
#include <SHpch.h>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHColliderComponent.h"
@ -16,7 +17,9 @@
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Physics/SHPhysicsEvents.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "Physics/Collision/Shapes/SHBox.h"
namespace SHADE
{
@ -25,185 +28,257 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
SHColliderComponent::SHColliderComponent() noexcept
: system { nullptr }
: flags { ACTIVE_FLAG | MOVED_FLAG }
, factory { nullptr }
, collisionBody { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHColliderComponent::GetDebugDrawState() const noexcept
{
return flags & DRAW_FLAG;
}
const SHTransform& SHColliderComponent::GetTransform() const noexcept
{
return transform;
}
const SHVec3& SHColliderComponent::GetPosition() const noexcept
{
return position;
return transform.position;
}
const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept
{
return orientation;
}
SHVec3 SHColliderComponent::GetRotation() const noexcept
{
return orientation.ToEuler();
return transform.orientation;
}
const SHVec3& SHColliderComponent::GetScale() const noexcept
{
return scale;
return transform.scale;
}
const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept
{
return collisionShapes;
return shapes;
}
SHCollisionShape& SHColliderComponent::GetCollisionShape(int index)
{
if (index < 0 || static_cast<size_t>(index) >= collisionShapes.size())
throw std::invalid_argument("Out-of-range access!");
const int NUM_SHAPES = static_cast<int>(shapes.size());
return collisionShapes[index];
if (index < 0 || index >= NUM_SHAPES)
throw std::invalid_argument("Out-of-range index!");
return *shapes[index];
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHColliderComponent::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 = GetEID()
, .debugDrawState = state
};
SHEventManager::BroadcastEvent<SHColliderOnDebugDrawEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_DRAW_EVENT);
#endif
}
void SHColliderComponent::SetFactory(rp3d::PhysicsCommon* physicsCommon) noexcept
{
factory = physicsCommon;
}
void SHColliderComponent::SetCollisionBody(rp3d::CollisionBody* body) noexcept
{
collisionBody = body;
}
void SHColliderComponent::SetTransform(const SHTransform& newTransform) noexcept
{
flags |= MOVED_FLAG;
transform = newTransform;
}
void SHColliderComponent::SetPosition(const SHVec3& newPosition) noexcept
{
flags |= MOVED_FLAG;
transform.position = newPosition;
}
void SHColliderComponent::SetOrientation(const SHQuaternion& newOrientation) noexcept
{
flags |= MOVED_FLAG;
transform.orientation = newOrientation;
}
void SHColliderComponent::SetScale(const SHVec3& newScale) noexcept
{
flags |= MOVED_FLAG;
transform.scale = newScale;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHColliderComponent::OnCreate()
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
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<SHTransformComponent>(GetEID()); transformComponent)
{
position = transformComponent->GetWorldPosition();
orientation = transformComponent->GetWorldOrientation();
scale = transformComponent->GetWorldScale();
}
}
void SHColliderComponent::OnDestroy()
{
int32_t numShapes = static_cast<int32_t>(shapes.size());
while (--numShapes >= 0)
{
delete shapes[numShapes];
shapes[numShapes] = nullptr;
}
void SHColliderComponent::RecomputeCollisionShapes() noexcept
{
for (auto& collisionShape : collisionShapes)
{
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX:
{
auto* box = reinterpret_cast<SHBox*>(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<SHSphere*>(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;
}
}
shapes.clear();
}
int SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset, const SHVec3& rotOffset) noexcept
const SHMatrix& SHColliderComponent::ComputeTRS() noexcept
{
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
return -1;
return transform.ComputeTRS();
}
static constexpr auto TYPE = SHCollisionShape::Type::BOX;
int SHColliderComponent::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset)
{
const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z }));
auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE });
const uint32_t NEW_INDEX = static_cast<uint32_t>(shapes.size());
collider.entityID = GetEID();
collider.SetPositionOffset(posOffset);
collider.SetRotationOffset(rotOffset);
collider.SetBoundingBox(halfExtents);
// Create collision shape
shapes.emplace_back(new SHSphere{});
auto* newSphere = dynamic_cast<SHSphere*>(shapes.back());
// Notify Physics System
const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
newSphere->collider = this;
newSphere->positionOffset = posOffset;
newSphere->rotationOffset = rotOffset;
newSphere->relativeRadius = relativeRadius;
newSphere->scale = SPHERE_SCALE;
system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
// Broadcast Event for adding a shape
const SHPhysicsColliderAddedEvent EVENT_DATA
{
.entityID = GetEID()
, .colliderType = SHCollisionShape::Type::BOX
, .colliderIndex = static_cast<int>(NEW_INDEX)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
// Only link with react if a factory is present.
// Otherwise, it will be linked through the physics object manager once the definitions are flushed.
if (factory)
{
rp3d::SphereShape* rp3dSphere = factory->createSphereShape(relativeRadius * SPHERE_SCALE * 0.5f);
const rp3d::Transform OFFSETS{ posOffset, SHQuaternion::FromEuler(rotOffset) };
newSphere->rp3dCollider = collisionBody->addCollider(rp3dSphere, OFFSETS);
dynamic_cast<rp3d::RigidBody*>(collisionBody)->updateMassPropertiesFromColliders();
}
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;
return static_cast<int>(NEW_INDEX);
}
static constexpr auto TYPE = SHCollisionShape::Type::SPHERE;
int SHColliderComponent::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset)
{
const uint32_t NEW_INDEX = static_cast<uint32_t>(shapes.size());
auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE });
// Create collision shape
shapes.emplace_back(new SHBox{});
auto* newBox = dynamic_cast<SHBox*>(shapes.back());
collider.entityID = GetEID();
collider.SetPositionOffset(posOffset);
collider.SetBoundingSphere(radius);
newBox->collider = this;
newBox->positionOffset = posOffset;
newBox->rotationOffset = rotOffset;
newBox->relativeExtents = relativeExtents;
newBox->scale = SHVec3::Abs(transform.scale);
// Notify Physics System
const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
// Broadcast Event for adding a shape
const SHPhysicsColliderAddedEvent EVENT_DATA
{
.entityID = GetEID()
, .colliderType = SHCollisionShape::Type::BOX
, .colliderIndex = static_cast<int>(NEW_INDEX)
};
system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
if (factory)
{
rp3d::BoxShape* rp3dBox = factory->createBoxShape(relativeExtents * newBox->scale * 0.5f);
const rp3d::Transform OFFSETS{ posOffset, SHQuaternion::FromEuler(rotOffset) };
newBox->rp3dCollider = collisionBody->addCollider(rp3dBox, OFFSETS);
dynamic_cast<rp3d::RigidBody*>(collisionBody)->updateMassPropertiesFromColliders();
}
void SHColliderComponent::RemoveCollider(int index)
{
if (index < 0 || static_cast<size_t>(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;
return static_cast<int>(NEW_INDEX);
}
it = collisionShapes.erase(it);
// Notify Physics System
if (!system)
void SHColliderComponent::RemoveCollisionShape(int index)
{
SHLOG_ERROR("Physics system does not exist, unable to remove Collider!")
const int NUM_SHAPES = static_cast<int>(shapes.size());
if (index < 0 || index >= NUM_SHAPES)
throw std::invalid_argument("Out-of-range index!");
int i = 0;
for (auto shapeIter = shapes.begin(); shapeIter != shapes.end(); ++i, ++shapeIter)
{
if (i == index)
{
collisionBody->removeCollider((*shapeIter)->rp3dCollider);
dynamic_cast<rp3d::RigidBody*>(collisionBody)->updateMassPropertiesFromColliders();
const SHPhysicsColliderRemovedEvent EVENT_DATA
{
.entityID = GetEID()
, .colliderType = (*shapeIter)->GetType()
, .colliderIndex = index
};
// Broadcast Event for removing a shape
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, GetEID())
delete *shapeIter;
shapeIter = shapes.erase(shapeIter);
return;
}
system->RemoveCollisionShape(GetEID(), index);
}
}
void SHColliderComponent::Update() noexcept
{
for (auto& shape : shapes)
shape->Update();
}
void SHColliderComponent::UpdateCollisionTags() noexcept
{
for (auto& shape : shapes)
shape->UpdateCollisionTags();
}
} // namespace SHADE

View File

@ -10,18 +10,24 @@
#pragma once
#include <vector>
#include <rttr/registration>
// Project Headers
#include "ECS_Base/Components/SHComponent.h"
#include "Math/Geometry/SHBox.h"
#include "Math/Geometry/SHSphere.h"
#include "SHCollisionShape.h"
#include "Math/Transform/SHTransform.h"
#include "Physics/Collision/Shapes/SHCollisionShape.h"
//namespace SHADE
//{
// class SHPhysicsSystem;
//}
/*-------------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-------------------------------------------------------------------------------------*/
namespace reactphysics3d
{
class PhysicsCommon;
class CollisionBody;
}
namespace SHADE
{
@ -37,13 +43,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
friend class SHPhysicsObject;
friend class SHPhysicsObjectManager;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using CollisionShapes = std::vector<SHCollisionShape>;
using CollisionShapes = std::vector<SHCollisionShape*>;
public:
@ -67,29 +73,96 @@ namespace SHADE
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool HasChanged () 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]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] const SHVec3& GetScale () const noexcept;
[[nodiscard]] const CollisionShapes& GetCollisionShapes() const noexcept;
[[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept;
[[nodiscard]] SHCollisionShape& GetCollisionShape (int index);
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetDebugDrawState (bool state) noexcept;
void SetFactory (reactphysics3d::PhysicsCommon* physicsCommon) noexcept;
void SetCollisionBody (reactphysics3d::CollisionBody* body) 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;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void OnCreate () override;
void OnDestroy () override;
void OnDestroy() override;
void RecomputeCollisionShapes () noexcept;
/**
* @brief
* Computes the TRS for the collider's transform
* @return
* The computed TRS.
*/
const SHMatrix& ComputeTRS() noexcept;
void RemoveCollider (int index);
/**
* @brief
* Adds a sphere collision shape.
* @param relativeRadius
* The relative radius is constructed with respect to the world scale. <br/>
* 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);
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;
/**
* @brief
* Adds a box collision shape.
* @param relativeExtents
* The relative extents are constructed with respect to the world scale. <br/>
* 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);
/**
* @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;
/**
* @brief
* Re-sets any dirty collision tags on collision shapes.
*/
void UpdateCollisionTags () noexcept;
private:
@ -97,12 +170,15 @@ namespace SHADE
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem* system;
static constexpr uint8_t ACTIVE_FLAG = 1U << 0;
static constexpr uint8_t DRAW_FLAG = 1U << 1;
static constexpr uint8_t MOVED_FLAG = 1U << 2;
SHVec3 position;
SHQuaternion orientation;
SHVec3 scale;
CollisionShapes collisionShapes;
uint8_t flags; // 0 0 0 0 0 hasMoved debugDraw active
reactphysics3d::PhysicsCommon* factory;
reactphysics3d::CollisionBody* collisionBody;
SHTransform transform;
CollisionShapes shapes;
RTTR_ENABLE()
};

View File

@ -1,368 +0,0 @@
/****************************************************************************************
* \file SHCollider.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Collider.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// 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<SHColliderComponent>(entityID);
auto* box = reinterpret_cast<SHBox*>(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<SHSphere*>(shape);
const auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(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<SHBox*>(shape)->SetCenter(positionOffset);
break;
}
case Type::SPHERE:
{
reinterpret_cast<SHSphere*>(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<const SHBox*>(rhs);
shape = new SHBox{ positionOffset, RHS_BOX->GetWorldExtents() };
auto* lhsBox = reinterpret_cast<SHBox*>(shape);
lhsBox->SetRelativeExtents(RHS_BOX->GetRelativeExtents());
break;
}
case Type::SPHERE:
{
const auto* RHS_SPHERE = reinterpret_cast<const SHSphere*>(rhs);
shape = new SHSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() };
auto* lhsSphere = reinterpret_cast<SHSphere*>(shape);
lhsSphere->SetRelativeRadius(RHS_SPHERE->GetRelativeRadius());
break;
}
default: break;
}
}
} // namespace SHADE
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::enumeration<SHCollisionShape::Type>("Collider Type")
(
value("Box", SHCollisionShape::Type::BOX),
value("Sphere", SHCollisionShape::Type::SPHERE)
// TODO(Diren): Add More Shapes
);
registration::class_<SHCollisionShape>("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));
}

View File

@ -1,134 +0,0 @@
/****************************************************************************************
* \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 <rttr/registration>
// 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

View File

@ -20,6 +20,7 @@
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
@ -29,99 +30,78 @@ namespace SHADE
SHRigidBodyComponent::SHRigidBodyComponent() noexcept
: type { Type::DYNAMIC }
, interpolate { true }
, flags { 0 }
, dirtyFlags { std::numeric_limits<uint16_t>::max() }
, mass { 1.0f }
, drag { 0.01f }
, angularDrag { 0.01f }
, system { nullptr }
, angularDrag { 0.1f }
, rigidBody { nullptr }
{
// Initialise default flags
flags |= 1U << 0; // Gravity set to true
flags |= 1U << 1; // Sleeping allowed
flags |= 1U << 8; // Interpolate by default
// Default flags
flags |= 1U << 0; // enable gravity
}
/*-----------------------------------------------------------------------------------*/
/* 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 flags & SHUtilities::ConvertEnum(Flags::GRAVITY);
}
bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept
{
return flags & SHUtilities::ConvertEnum(Flags::SLEEPING);
}
bool SHRigidBodyComponent::IsInterpolating() const noexcept
{
return interpolate;
}
bool SHRigidBodyComponent::IsSleeping() const noexcept
{
return rigidBody ? rigidBody->isSleeping() : false;
}
bool SHRigidBodyComponent::GetFreezePositionX() const noexcept
{
static constexpr int FLAG_POS = 2;
return flags & (1U << FLAG_POS);
return flags & SHUtilities::ConvertEnum(Flags::LINEAR_X);
}
bool SHRigidBodyComponent::GetFreezePositionY() const noexcept
{
static constexpr int FLAG_POS = 3;
return flags & (1U << FLAG_POS);
return flags & SHUtilities::ConvertEnum(Flags::LINEAR_Y);
}
bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept
{
static constexpr int FLAG_POS = 4;
return flags & (1U << FLAG_POS);
return flags & SHUtilities::ConvertEnum(Flags::LINEAR_Z);
}
bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept
{
static constexpr int FLAG_POS = 5;
return flags & (1U << FLAG_POS);
return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_X);
}
bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept
{
static constexpr int FLAG_POS = 6;
return flags & (1U << FLAG_POS);
return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_Y);
}
bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept
{
static constexpr int FLAG_POS = 7;
return flags & (1U << FLAG_POS);
return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_Z);
}
//bool SHRigidBodyComponent::GetAutoMass() const noexcept
//{
// static constexpr int FLAG_POS = 9;
// return flags & (1U << FLAG_POS);
//}
float SHRigidBodyComponent::GetMass() const noexcept
{
return mass;
return rigidBody ? rigidBody->getMass() : 0.0f;
}
float SHRigidBodyComponent::GetDrag() const noexcept
@ -136,49 +116,32 @@ namespace SHADE
SHVec3 SHRigidBodyComponent::GetForce() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
return physicsObject->GetRigidBody()->getForce();
return SHVec3::Zero;
return rigidBody ? SHVec3{ rigidBody->getForce() } : SHVec3::Zero;
}
SHVec3 SHRigidBodyComponent::GetTorque() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
return physicsObject->GetRigidBody()->getTorque();
return SHVec3::Zero;
return rigidBody ? SHVec3{ rigidBody->getTorque() } : SHVec3::Zero;
}
SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
return physicsObject->GetRigidBody()->getLinearVelocity();
return SHVec3::Zero;
return rigidBody ? SHVec3{ rigidBody->getLinearVelocity() } : SHVec3::Zero;
}
SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
return physicsObject->GetRigidBody()->getAngularVelocity();
return SHVec3::Zero;
return rigidBody ? SHVec3{ rigidBody->getAngularVelocity() } : SHVec3::Zero;
}
const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept
SHVec3 SHRigidBodyComponent::GetPosition() const noexcept
{
return position;
}
const SHQuaternion& SHRigidBodyComponent::GetOrientation() const noexcept
{
return orientation;
return rigidBody ? SHVec3{ rigidBody->getTransform().getPosition() } : SHVec3::Zero;
}
SHVec3 SHRigidBodyComponent::GetRotation() const noexcept
{
return orientation.ToEuler();
return rigidBody ? SHQuaternion{ rigidBody->getTransform().getOrientation() }.ToEuler() : SHVec3::Zero;
}
/*-----------------------------------------------------------------------------------*/
@ -187,224 +150,175 @@ namespace SHADE
void SHRigidBodyComponent::SetType(Type newType) noexcept
{
static constexpr int FLAG_POS = 8;
if (type == newType)
return;
type = newType;
dirtyFlags |= 1U << FLAG_POS;
if (rigidBody)
{
switch (type)
{
case Type::STATIC:
rigidBody->setType(rp3d::BodyType::STATIC);
break;
case Type::KINEMATIC:
rigidBody->setType(rp3d::BodyType::KINEMATIC);
break;
case Type::DYNAMIC:
rigidBody->setType(rp3d::BodyType::DYNAMIC);
break;
default:
break;
}
}
}
void SHRigidBodyComponent::SetRigidBody(rp3d::RigidBody* body) noexcept
{
rigidBody = body;
}
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
{
static constexpr int FLAG_POS = 0;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::GRAVITY);
enableGravity ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
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);
if (rigidBody)
rigidBody->enableGravity(enableGravity);
}
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
{
static constexpr int FLAG_POS = 1;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::SLEEPING);
isAllowedToSleep ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
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);
if (rigidBody)
rigidBody->setIsAllowedToSleep(isAllowedToSleep);
}
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{
static constexpr int FLAG_POS = 2;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_X);
freezePositionX ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC)
if (rigidBody)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor();
linearLock.x = freezePositionX ? 0.0f : 1.0f;
rigidBody->setLinearLockAxisFactor(linearLock);
}
dirtyFlags |= 1U << FLAG_POS;
freezePositionX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
}
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{
static constexpr int FLAG_POS = 3;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_Y);
freezePositionY ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC)
if (rigidBody)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor();
linearLock.y = freezePositionY ? 0.0f : 1.0f;
rigidBody->setLinearLockAxisFactor(linearLock);
}
dirtyFlags |= 1U << FLAG_POS;
freezePositionY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
}
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{
static constexpr int FLAG_POS = 4;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_Z);
freezePositionZ ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC)
if (rigidBody)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor();
linearLock.z = freezePositionZ ? 0.0f : 1.0f;
rigidBody->setLinearLockAxisFactor(linearLock);
}
dirtyFlags |= 1U << FLAG_POS;
freezePositionZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
}
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{
static constexpr int FLAG_POS = 5;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_X);
freezeRotationX ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC)
if (rigidBody)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor();
angularLock.x = freezeRotationX ? 0.0f : 1.0f;
rigidBody->setAngularLockAxisFactor(angularLock);
}
dirtyFlags |= 1U << FLAG_POS;
freezeRotationX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
}
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{
static constexpr int FLAG_POS = 6;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_Y);
freezeRotationY ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC)
if (rigidBody)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor();
angularLock.y = freezeRotationY ? 0.0f : 1.0f;
rigidBody->setAngularLockAxisFactor(angularLock);
}
dirtyFlags |= 1U << FLAG_POS;
freezeRotationY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
}
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{
static constexpr int FLAG_POS = 7;
constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_Z);
freezeRotationZ ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC)
if (rigidBody)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor();
angularLock.z = freezeRotationZ ? 0.0f : 1.0f;
rigidBody->setAngularLockAxisFactor(angularLock);
}
dirtyFlags |= 1U << FLAG_POS;
freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
}
void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept
{
static constexpr int FLAG_POS = 8;
allowInterpolation ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
interpolate = allowInterpolation;
}
//void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept
//{
// static constexpr int FLAG_POS = 9;
// autoMass ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
// dirtyFlags |= 1U << FLAG_POS;
//}
//void SHRigidBodyComponent::SetMass(float newMass) noexcept
//{
// static constexpr int FLAG_POS = 9;
// if (newMass < 0.0f)
// return;
// if (type != Type::DYNAMIC)
// {
// SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
// return;
// }
// dirtyFlags |= 1U << FLAG_POS;
// mass = newMass;
// // Turn off automass
// flags &= ~(1U << FLAG_POS);
//}
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
{
static constexpr int FLAG_POS = 10;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
drag = newDrag;
if (rigidBody)
rigidBody->setLinearDamping(newDrag);
}
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
{
static constexpr int FLAG_POS = 11;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
angularDrag = newAngularDrag;
if (rigidBody)
rigidBody->setAngularDamping(newAngularDrag);
}
void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
{
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID())
return;
}
auto* physicsObject = system->GetPhysicsObject(GetEID());
if (!physicsObject)
{
SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID())
return;
}
physicsObject->GetRigidBody()->setLinearVelocity(newLinearVelocity);
if (rigidBody)
rigidBody->setLinearVelocity(newLinearVelocity);
}
void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
{
static constexpr int FLAG_POS = 13;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID())
return;
}
auto* physicsObject = system->GetPhysicsObject(GetEID());
if (!physicsObject)
{
SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID())
return;
}
physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity);
if (rigidBody)
rigidBody->setAngularVelocity(newAngularVelocity);
}
/*-----------------------------------------------------------------------------------*/
@ -413,81 +327,67 @@ namespace SHADE
void SHRigidBodyComponent::OnCreate()
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
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<SHTransformComponent>(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);
if (rigidBody)
rigidBody->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);
if (rigidBody)
rigidBody->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);
if (rigidBody)
rigidBody->applyWorldForceAtWorldPosition(force, worldPos);
}
void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
physicsObject->GetRigidBody()->applyLocalForceAtCenterOfMass(relativeForce);
if (rigidBody)
rigidBody->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);
if (rigidBody)
rigidBody->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);
if (rigidBody)
rigidBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
}
void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
physicsObject->GetRigidBody()->applyWorldTorque(torque);
if (rigidBody)
rigidBody->applyWorldTorque(torque);
}
void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
physicsObject->GetRigidBody()->applyLocalTorque(relativeTorque);
if (rigidBody)
rigidBody->applyLocalTorque(relativeTorque);
}
void SHRigidBodyComponent::ClearForces() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
physicsObject->GetRigidBody()->resetForce();
if (rigidBody)
rigidBody->resetForce();
}
void SHRigidBodyComponent::ClearTorque() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
physicsObject->GetRigidBody()->resetTorque();
if (rigidBody)
rigidBody->resetTorque();
}
} // namespace SHADE
@ -506,13 +406,11 @@ RTTR_REGISTRATION
registration::class_<SHRigidBodyComponent>("RigidBody Component")
.property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType )
//.property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass )
.property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag )
.property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag )
.property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled )
.property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate )
.property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep)
//.property("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 )

View File

@ -17,6 +17,15 @@
#include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
/*-------------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-------------------------------------------------------------------------------------*/
namespace reactphysics3d
{
class RigidBody;
}
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
@ -31,7 +40,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
friend class SHPhysicsObject;
friend class SHPhysicsObjectManager;
public:
/*---------------------------------------------------------------------------------*/
@ -67,13 +76,12 @@ namespace SHADE
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] bool IsGravityEnabled () const noexcept;
[[nodiscard]] bool IsAllowedToSleep () const noexcept;
[[nodiscard]] bool IsInterpolating () const noexcept;
[[nodiscard]] bool GetIsSleeping () const noexcept;
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] bool IsSleeping () const noexcept;
[[nodiscard]] bool GetFreezePositionX () const noexcept;
[[nodiscard]] bool GetFreezePositionY () const noexcept;
@ -82,8 +90,6 @@ namespace SHADE
[[nodiscard]] bool GetFreezeRotationY () const noexcept;
[[nodiscard]] bool GetFreezeRotationZ () const noexcept;
//[[nodiscard]] bool GetAutoMass () const noexcept;
[[nodiscard]] float GetMass () const noexcept;
[[nodiscard]] float GetDrag () const noexcept;
[[nodiscard]] float GetAngularDrag () const noexcept;
@ -93,8 +99,7 @@ namespace SHADE
[[nodiscard]] SHVec3 GetLinearVelocity () const noexcept;
[[nodiscard]] SHVec3 GetAngularVelocity () const noexcept;
[[nodiscard]] const SHVec3& GetPosition () const noexcept;
[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetPosition () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept;
/*---------------------------------------------------------------------------------*/
@ -103,8 +108,11 @@ namespace SHADE
void SetType (Type newType) noexcept;
void SetRigidBody (reactphysics3d::RigidBody* body) noexcept;
void SetGravityEnabled (bool enableGravity) noexcept;
void SetIsAllowedToSleep (bool isAllowedToSleep) noexcept;
void SetFreezePositionX (bool freezePositionX) noexcept;
void SetFreezePositionY (bool freezePositionY) noexcept;
void SetFreezePositionZ (bool freezePositionZ) noexcept;
@ -112,9 +120,7 @@ namespace SHADE
void SetFreezeRotationY (bool freezeRotationY) noexcept;
void SetFreezeRotationZ (bool freezeRotationZ) noexcept;
void SetInterpolate (bool allowInterpolation) noexcept;
//void SetAutoMass (bool autoMass) noexcept;
//void SetMass (float newMass) noexcept;
void SetDrag (float newDrag) noexcept;
void SetAngularDrag (float newAngularDrag) noexcept;
@ -140,30 +146,43 @@ namespace SHADE
void ClearTorque () const noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Flags : uint8_t
{
GRAVITY = 0x1
, SLEEPING = 0x2
, LINEAR_X = 0x4
, LINEAR_Y = 0x8
, LINEAR_Z = 0x10
, ANGULAR_X = 0x20
, ANGULAR_Y = 0x40
, ANGULAR_Z = 0x80
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static constexpr size_t NUM_FLAGS = 8;
static constexpr size_t NUM_DIRTY_FLAGS = 12;
Type type;
bool interpolate;
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;
// Used for storing serialised data
uint8_t flags; // aZ aY aX lZ lY lX sleepEnabled gravity
float drag;
float angularDrag;
SHVec3 linearVelocity;
SHVec3 angularVelocity;
SHPhysicsSystem* system;
// For interpolation
SHVec3 position;
SHQuaternion orientation;
reactphysics3d::RigidBody* rigidBody;
RTTR_ENABLE()
};
} // namespace SHADE

View File

@ -1,431 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// 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<SHTransformComponent>(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<SHColliderComponent>(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<SHRigidBodyComponent>(entityID); rigidBodyComponent)
rigidBodyComponent->mass = rp3dBody->getMass();
}
return index;
}
void SHPhysicsObject::RemoveCollisionShape(int index)
{
const int NUM_COLLIDERS = static_cast<int>(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<SHRigidBodyComponent>(entityID);
if (rigidBodyComponent)
rigidBodyComponent->mass = rp3dBody->getMass();
}
}
void SHPhysicsObject::RemoveAllCollisionShapes() const noexcept
{
int numColliders = static_cast<int>(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<rp3d::BodyType>(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<int>(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<SHRigidBodyComponent>(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<const SHBox*>(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<const SHBox*>(boxShape.GetShape());
auto* rp3dCollider = rp3dBody->getCollider(index);
auto* rp3dBox = reinterpret_cast<rp3d::BoxShape*>(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<const SHSphere*>(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<const SHSphere*>(sphereShape.GetShape());
auto* rp3dCollider = rp3dBody->getCollider(index);
auto* rp3dSphere = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
const rp3d::Transform OFFSETS
{
sphereShape.GetPositionOffset()
, sphereShape.GetRotationOffset()
};
rp3dCollider->setIsTrigger(sphereShape.IsTrigger());
rp3dCollider->setLocalToBodyTransform(OFFSETS);
rp3dSphere->setRadius(SPHERE->GetWorldRadius());
}
} // namespace SHADE

View File

@ -1,111 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObject.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Object.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsObject
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
friend class SHPhysicsObjectManager;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject (EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept;
SHPhysicsObject (const SHPhysicsObject& rhs) noexcept = default;
SHPhysicsObject (SHPhysicsObject&& rhs) noexcept = default;
virtual ~SHPhysicsObject () noexcept;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept = default;
SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept = default;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetPosition () const noexcept;
[[nodiscard]] SHQuaternion GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] rp3d::CollisionBody* GetCollisionBody () const noexcept;
[[nodiscard]] rp3d::RigidBody* GetRigidBody () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetStaticBody () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
int AddCollisionShape (int index);
void RemoveCollisionShape (int index);
void RemoveAllCollisionShapes () const noexcept;
void SyncRigidBody (SHRigidBodyComponent& component) const noexcept;
void SyncColliders (SHColliderComponent& component) const noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
EntityID entityID;
bool collidersActive; // Only used to sync with SHADE components
rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* world;
rp3d::RigidBody* rp3dBody;
rp3d::Transform prevTransform; // Cached transform for interpolation
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void syncColliderProperties (const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept;
// Box Shapes
void addBoxShape (const SHCollisionShape& boxShape) const noexcept;
void syncBoxShape (int index, const SHCollisionShape& boxShape) const noexcept;
// Sphere Shapes
void addSphereShape (const SHCollisionShape& sphereShape) const noexcept;
void syncSphereShape (int index, const SHCollisionShape& sphereShape) const noexcept;
};
} // namespace SHADE

View File

@ -1,309 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObjectManager.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object Manager.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// 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<SHRigidBodyComponent>(COMMAND.eid)
, .colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(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<SHTransformComponent>(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<int>(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

View File

@ -1,181 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObjectManager.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Object Manager.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <unordered_map>
#include <queue>
#include <reactphysics3d/reactphysics3d.h>
// 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<EntityID, SHPhysicsObject>;
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<QueueCommand> 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

View File

@ -15,7 +15,7 @@
// Project Headers
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Physics/PhysicsObject/SHPhysicsObject.h"
#include "Physics/Interface/PhysicsObject/SHPhysicsObject.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Scene/SHSceneManager.h"
@ -25,9 +25,9 @@
uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID)
{
for (uint32_t i = 0; i < physicsObject.GetCollisionBody()->getNbColliders(); ++i)
for (uint32_t i = 0; i < physicsObject.body->getNbColliders(); ++i)
{
const auto* collider = physicsObject.GetCollisionBody()->getCollider(i);
const auto* collider = physicsObject.body->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
@ -178,10 +178,10 @@ namespace SHADE
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : system->GetPhysicsObjects())
for (auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects())
{
// Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1)
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.body->getEntity() == body1)
{
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
@ -190,7 +190,7 @@ namespace SHADE
}
// Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2)
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.body->getEntity() == body2)
{
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);
@ -222,10 +222,10 @@ namespace SHADE
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : system->GetPhysicsObjects())
for (auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects())
{
// Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1)
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.body->getEntity() == body1)
{
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
@ -234,7 +234,7 @@ namespace SHADE
}
// Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2)
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.body->getEntity() == body2)
{
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);

View File

@ -15,7 +15,7 @@
// Project Headers
#include "SH_API.h"
#include "SHCollisionInfo.h"
#include "Physics/Collision/SHCollisionInfo.h"
namespace SHADE
{

View File

@ -13,8 +13,7 @@
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/SHMath.h"
#include "SH_API.h"
#include "Math/Vector/SHVec3.h"
namespace SHADE
{

View File

@ -0,0 +1,132 @@
/****************************************************************************************
* \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 <SHpch.h>
// Primary Header
#include "SHRaycaster.h"
#include "Physics/System/SHPhysicsSystem.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 */
/*-----------------------------------------------------------------------------------*/
SHRaycaster::SHRaycaster() noexcept
: system { nullptr }
, world { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHRaycaster::BindToSystem(SHPhysicsSystem* physicsSystem) noexcept
{
system = physicsSystem;
}
void SHRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept
{
world = physicsWorld;
}
const SHRaycaster::RaycastResults& SHRaycaster::Raycast(const RaycastInfo& info) noexcept
{
results.clear();
currentInfo = info;
SHASSERT(world, "Physics World missing link with Raycaster!")
// Clamp distance to 2km
const float DISTANCE = std::clamp(info.distance, 0.0f, SHRay::MAX_RAYCAST_DIST);
const rp3d::Ray RP3D_RAY = { info.ray.position, info.ray.position + info.ray.direction * DISTANCE };
world->raycast(RP3D_RAY, this, info.layers);
// Reset
currentInfo.reset();
return results;
}
rp3d::decimal SHRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo)
{
SHASSERT(system, "Physics System unlinked with Raycaster!")
SHPhysicsRaycastResult result;
// Compare body IDs to find the matching physics object
const auto HIT_BODY_EID = raycastInfo.body->getEntity();
for (const auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects())
{
// Match rp3d bodies
if (physicsObject.body->getEntity() != HIT_BODY_EID)
continue;
// Skip ignored entity
if (currentInfo->colliderEntityID.has_value())
if (entityID == currentInfo->colliderEntityID)
return 1.0f;
result.entityHit = entityID;
// Find collider index
if (const int INDEX = findColliderIndex(physicsObject.body, raycastInfo.collider->getEntity()); INDEX > -1)
{
result.shapeIndex = INDEX;
break;
}
}
result.hit = true;
result.position = raycastInfo.worldPoint;
result.normal = raycastInfo.worldNormal;
result.distance = SHVec3::Distance(currentInfo->ray.position, result.position);
result.angle = SHVec3::Angle(currentInfo->ray.position, result.position);
results.emplace_back(result);
if (currentInfo->continuous)
return 1.0f;
return 0.0f;
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
int SHRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept
{
const int NUM_COLLISION_SHAPES = static_cast<int>(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

View File

@ -0,0 +1,133 @@
/****************************************************************************************
* \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 <vector>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/SHRay.h"
#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Physics/Collision/SHPhysicsRaycastResult.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHPhysicsSystem;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHRaycaster : public reactphysics3d::RaycastCallback
{
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using RaycastResults = std::vector<SHPhysicsRaycastResult>;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct RaycastInfo
{
private:
/*-------------------------------------------------------------------------------*/
/* Friends */
/*-------------------------------------------------------------------------------*/
friend class SHRaycaster;
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
bool continuous = false;
uint16_t layers = static_cast<uint16_t>(SHCollisionTag::Layer::ALL);
float distance = std::numeric_limits<float>::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<EntityID> colliderEntityID;
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHRaycaster() noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept;
void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept;
rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override;
/**
* @brief
* Casts a ray into the physics world.
* @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:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem* system;
rp3d::PhysicsWorld* world;
RaycastResults results; // Holds the temporary result after casting into the world
std::optional<RaycastInfo> currentInfo; // Hold the state of the current raycast.
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept;
};
} // namespace SHADE

View File

@ -11,8 +11,7 @@
#pragma once
// Project Headers
#include "Interface/SHCollisionShape.h"
#include "Collision/Shapes/SHCollisionShape.h"
namespace SHADE
{
@ -30,8 +29,15 @@ namespace SHADE
struct SHPhysicsColliderRemovedEvent
{
EntityID entityID;
SHCollisionShape::Type colliderType;
int colliderIndex;
};
struct SHColliderOnDebugDrawEvent
{
EntityID entityID;
bool debugDrawState;
};
} // namespace SHADE

View File

@ -0,0 +1,113 @@
/****************************************************************************************
* \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 <SHpch.h>
// 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<SHPhysicsDebugDrawSystem*>(GetSystem());
if (!physicsDebugDrawSystem->IsDebugDrawActive())
return;
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS);
const bool DRAW_CONTACTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::CONTACTS);
const bool DRAW_RAYCASTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::RAYCASTS);
\
// 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<SHColliderComponent>();
for (const auto& COLLIDER_COMPONENT : COLLIDER_COMPONENT_DENSE)
drawCollider(debugDrawSystem, COLLIDER_COMPONENT);
}
else if (!physicsDebugDrawSystem->collidersToDraw.empty())
{
for (const auto EID : physicsDebugDrawSystem->collidersToDraw)
drawCollider(debugDrawSystem, *SHComponentManager::GetComponent<SHColliderComponent>(EID));
}
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
return;
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();
}
rp3d::DebugRenderer* rp3dRenderer = nullptr;
if (physicsSystem->worldState.world)
rp3dRenderer = &physicsSystem->worldState.world->getDebugRenderer();
// No world exists, nothing else to be drawn
if (!rp3dRenderer)
return;
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, DRAW_CONTACTS);
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, DRAW_CONTACTS);
if (DRAW_CONTACTS)
{
const SHColour& CONTACT_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)];
const int NUM_TRIS = static_cast<int>(rp3dRenderer->getNbTriangles());
if (NUM_TRIS == 0) // No contact points
return;
// Draw contacts
const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray();
for (int i = 0; i < NUM_TRIS; ++i)
debugDrawSystem->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, CONTACT_COLOUR, true);
// Draw normals
const int NUM_LINES = static_cast<int>(rp3dRenderer->getNbLines());
const auto& LINE_ARRAY = rp3dRenderer->getLinesArray();
for (int i = 0; i < NUM_LINES; ++i)
debugDrawSystem->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, CONTACT_COLOUR, true);
}
}
} // namespace SHADE

View File

@ -0,0 +1,120 @@
/****************************************************************************************
* \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 <SHpch.h>
// 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<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
const float FACTOR = static_cast<float>(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)
{
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.GetPhysicsObjects())
{
// Skip missing transforms
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (!transformComponent)
continue;
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
// Skip invalid bodies (Should not occur)
if (!rigidBodyComponent || !rigidBodyComponent->rigidBody)
continue;
// Skip inactive bodies
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID);
if (!IS_ACTIVE || rigidBodyComponent->type == SHRigidBodyComponent::Type::STATIC)
continue;
const rp3d::Transform& CURRENT_TF = physicsObject.body->getTransform();
if (rigidBodyComponent->IsInterpolating())
{
const rp3d::Transform PREV_TF
{
rigidBodyComponent->position
, rigidBodyComponent->orientation
};
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(FACTOR));
const SHVec3 RENDER_POSITION = INTERPOLATED_TF.getPosition();
const SHQuaternion RENDER_ORIENTATION = INTERPOLATED_TF.getOrientation();
transformComponent->SetWorldPosition(RENDER_POSITION);
transformComponent->SetWorldOrientation(RENDER_ORIENTATION);
}
else
{
transformComponent->SetWorldPosition(CURRENT_TF.getPosition());
transformComponent->SetWorldOrientation(CURRENT_TF.getOrientation());
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
// Set colliders transform if exists
if (auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID); colliderComponent)
{
colliderComponent->transform.position = CURRENT_TF.getPosition();
colliderComponent->transform.orientation = CURRENT_TF.getOrientation();
}
/*
* TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy.
*/
}
// Since this function never runs when editor in not in play, execute the function anyway
physicsSystem->collisionListener.CleanContainers();
}
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
}
} // namespace SHADE

View File

@ -0,0 +1,107 @@
/****************************************************************************************
* \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 <SHpch.h>
// 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<SHPhysicsSystem*>(GetSystem());
// Update colliders since collision tag has changed
const bool UPDATE_COLLISION_TAGS = SHCollisionTagMatrix::IsDirty();
// Get all physics objects & sync transforms
auto& physicsObjects = physicsSystem->objectManager.GetPhysicsObjects();
for (auto& [entityID, physicsObject] : physicsObjects)
{
const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(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.body)
continue;
auto* shadeBody = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* shadeCollider = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (UPDATE_TRANSFORM)
{
// Set body transform
const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition();
const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation();
const rp3d::Transform NEW_TRANSFORM{ WORLD_POS, WORLD_ROT };
physicsObject.body->setTransform(NEW_TRANSFORM);
// Sync rigid body active states if one exists
if (shadeBody)
{
const bool SHADE_BODY_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID);
const bool RP3D_BODY_ACTIVE = physicsObject.body->isActive();
if (SHADE_BODY_ACTIVE != RP3D_BODY_ACTIVE)
physicsObject.body->setIsActive(SHADE_BODY_ACTIVE);
shadeBody->position = WORLD_POS;
shadeBody->orientation = WORLD_ROT;
}
// Sync collider active states if one exists
if (shadeCollider)
{
const bool SHADE_COLLIDER_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(entityID);
const bool RP3D_COLLIDERS_ACTIVE = shadeCollider->flags & SHColliderComponent::ACTIVE_FLAG;
// Modify the static body's active state
// The collision listener & raycaster will handle culling inactive colliders.
if (SHADE_COLLIDER_ACTIVE != RP3D_COLLIDERS_ACTIVE)
physicsObject.body->setIsActive(SHADE_COLLIDER_ACTIVE);
shadeCollider->transform.position = WORLD_POS;
shadeCollider->transform.orientation = WORLD_ROT;
shadeCollider->transform.scale = TRANSFORM_COMPONENT->GetWorldScale();
shadeCollider->Update();
}
}
if (UPDATE_COLLISION_TAGS && shadeCollider)
shadeCollider->UpdateCollisionTags();
}
// Clear collision tag dirty flags
SHCollisionTagMatrix::Clear();
}
} // namespace SHADE

View File

@ -0,0 +1,66 @@
/****************************************************************************************
* \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 <SHpch.h>
// 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<SHPhysicsSystem*>(GetSystem());
auto* scriptEngine = SHSystemManager::GetSystem<SHScriptEngine>();
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->worldState.world)
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(FIXED_DT));
accumulatedTime -= FIXED_DT;
++count;
}
stats.numSteps = count;
physicsSystem->worldUpdated = count > 0;
physicsSystem->interpolationFactor = physicsSystem->worldUpdated ? accumulatedTime / FIXED_DT : 0.0;
}
} // namespace SHADE

View File

@ -13,79 +13,59 @@
// Primary Header
#include "SHPhysicsDebugDrawSystem.h"
// Project Headers
// Project Header
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/SHPhysicsEvents.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[NUM_FLAGS] =
const SHColour SHPhysicsDebugDrawSystem::DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::COUNT)]
{
drawColliders
, drawColliderAABBs
, drawBroadPhaseAABBs
, drawContactPoints
, drawContactNormals
, drawRaycasts
SHColour::GREEN // Colliders
, SHColour::PURPLE // Triggers
, SHColour::RED // Contacts
, SHColour::ORANGE // Raycasts
};
SHVec3 SHPhysicsDebugDrawSystem::boxVertices[NUM_BOX_VERTICES];
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept
: debugDrawFlags { 0 }
, physicsSystem { nullptr }
: flags { 0 }
{
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;
collidersToDraw.clear();
}
SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine()
: SHSystemRoutine { "Physics Debug Draw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept
bool SHPhysicsDebugDrawSystem::IsDebugDrawActive() const noexcept
{
const auto INT_FLAG = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS)
{
SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to get debug draw state!", INT_FLAG)
return false;
return flags & ACTIVE_FLAG;
}
return debugDrawFlags & 1U << SHUtilities::ConvertEnum(flag);
bool SHPhysicsDebugDrawSystem::GetFlagState(DebugDrawFlags flag) const noexcept
{
const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag);
return flags & ENUM_VALUE;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept
void SHPhysicsDebugDrawSystem::SetFlagState(DebugDrawFlags flag, bool state) noexcept
{
const auto INT_FLAG = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS)
{
SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to set debug draw state!", INT_FLAG)
return;
}
const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag);
state ? flags |= ENUM_VALUE : flags &= ~ENUM_VALUE;
value ? (debugDrawFlags |= 1U << INT_FLAG) : (debugDrawFlags &= ~(1U << INT_FLAG));
// 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;
}
/*-----------------------------------------------------------------------------------*/
@ -96,240 +76,76 @@ namespace SHADE
{
SystemFamily::GetID<SHPhysicsDebugDrawSystem>();
SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!")
physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
// Register collider draw event
const std::shared_ptr EVENT_RECEIVER = std::make_shared<SHEventReceiverSpec<SHPhysicsDebugDrawSystem>>(this, &SHPhysicsDebugDrawSystem::onColliderDraw);
const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EVENT_RECEIVER);
// Generate shapes
generateBox();
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_DRAW_EVENT, EVENT_RECEIVER_PTR);
}
void SHPhysicsDebugDrawSystem::Exit()
{
physicsSystem = nullptr;
}
void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem());
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
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();
void SHPhysicsDebugDrawSystem::AddRaycast(const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept
{
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::drawColliders(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
SHEventHandle SHPhysicsDebugDrawSystem::onColliderDraw(SHEventPtr onColliderDrawEvent)
{
const auto& COLLIDER_SET = SHComponentManager::GetDense<SHColliderComponent>();
for (const auto& COLLIDER : COLLIDER_SET)
{
// Skip inactive colliders
if (!SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(COLLIDER.GetEID()))
continue;
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHColliderOnDebugDrawEvent>*>(onColliderDrawEvent.get())->data;
for (auto& collisionShape : COLLIDER.GetCollisionShapes())
// Add to the container to draw all colliders
if (EVENT_DATA->debugDrawState)
{
switch (collisionShape.GetType())
if (collidersToDraw.empty())
flags |= ACTIVE_FLAG;
collidersToDraw.emplace(EVENT_DATA->entityID);
}
else
{
case SHCollisionShape::Type::BOX: debugDrawBox(debugRenderer, COLLIDER, collisionShape); break;
case SHCollisionShape::Type::SPHERE: debugDrawSphere(debugRenderer, COLLIDER, collisionShape); break;
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 SHColliderComponent& 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())
{
case SHCollisionShape::Type::SPHERE:
{
debugDrawSystem->DrawWireSphere(SHAPE->GetTRS(), DRAW_COLOUR, true);
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<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
{
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true);
const int NUM_TRIS = static_cast<int>(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<int>(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<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
{
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true);
const int NUM_LINES = static_cast<int>(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<int>(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<SHPhysicsSystem>();
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<float>::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<const SHBox*>(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<SHVec3, NUM_BOX_VERTICES> 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<const SHSphere*>(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

View File

@ -10,14 +10,16 @@
#pragma once
#include <reactphysics3d/reactphysics3d.h>
#include <unordered_set>
// 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 "Math/SHColour.h"
#include "SHPhysicsSystem.h"
#include "Tools/Utilities/SHUtilities.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/Collision/SHPhysicsRaycastResult.h"
namespace SHADE
{
@ -28,63 +30,54 @@ namespace SHADE
class SH_API SHPhysicsDebugDrawSystem final : public SHSystem
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class DebugDrawFlags
enum class DebugDrawFlags : uint8_t
{
COLLIDER
, COLLIDER_AABB
, BROAD_PHASE_AABB
, CONTACT_POINTS
, CONTACT_NORMALS
, RAYCASTS
, NUM_FLAGS
COLLIDERS = 0x02
, CONTACTS = 0x04
, RAYCASTS = 0x08
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem() noexcept;
SHPhysicsDebugDrawSystem () noexcept;
~SHPhysicsDebugDrawSystem() noexcept = default;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept;
[[nodiscard]] bool IsDebugDrawActive () const noexcept;
[[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept;
void SetFlagState (DebugDrawFlags flag, bool state) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/* Member Functions */
/*---------------------------------------------------------------------------------*/
void Init() override;
void Exit() override;
void Init () override;
void Exit () override;
void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine
/**
* @brief
* If the editor is enabled, this routine invokes debug drawing for colliders and collision information.
*/
class SH_API PhysicsDebugDraw final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsDebugDrawRoutine();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
PhysicsDebugDraw();
void Execute(double dt) noexcept override;
};
@ -93,46 +86,58 @@ namespace SHADE
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using DebugDrawFunction = void(*)(SHDebugDrawSystem*, rp3d::DebugRenderer*) noexcept;
union DebugDrawInfo
{
struct Contact
{
SHVec3 worldPos;
SHVec3 normal;
} contact;
struct Raycast
{
SHVec3 start;
SHVec3 end;
} raycast;
};
using Colliders = std::unordered_set<EntityID>;
using Raycasts = std::vector<DebugDrawInfo>;
using Contacts = std::vector<DebugDrawInfo>;
enum class Colours
{
COLLIDER
, TRIGGER
, CONTACT
, RAYCAST
, COUNT
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS);
static const DebugDrawFunction drawFunctions[NUM_FLAGS];
static constexpr uint8_t ACTIVE_FLAG = 0x01;
// SHAPES INFO
static const SHColour DEBUG_DRAW_COLOURS[static_cast<int>(Colours::COUNT)];
static constexpr size_t NUM_BOX_VERTICES = 8;
static SHVec3 boxVertices[NUM_BOX_VERTICES];
// 0 0 0 drawBroadphase drawRaycasts drawContacts drawAllColliders debugDrawActive
uint8_t flags;
uint8_t debugDrawFlags;
SHPhysicsSystem* physicsSystem;
SHColour debugColours[NUM_FLAGS];
Colliders collidersToDraw;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/* Member Functions */
/*---------------------------------------------------------------------------------*/
// Generic Draw Functions
SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent);
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;
static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHColliderComponent& collider) noexcept;
static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) 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

View File

@ -19,8 +19,9 @@
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Physics/SHPhysicsEvents.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
@ -30,11 +31,23 @@ namespace SHADE
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::SHPhysicsSystem()
SHPhysicsSystem::SHPhysicsSystem() noexcept
: worldUpdated { false }
, interpolationFactor { 0.0 }
, fixedDT { DEFAULT_FIXED_STEP }
{}
{
// Add more events here to register them
eventFunctions[0] = { &SHPhysicsSystem::onComponentAdded , SH_COMPONENT_ADDED_EVENT };
eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT };
eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST };
eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST };
}
SHPhysicsSystem::~SHPhysicsSystem()
{
worldState.DestroyWorld(factory);
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
@ -45,9 +58,9 @@ namespace SHADE
return 1.0 / fixedDT;
}
const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept
double SHPhysicsSystem::GetFixedDT() const noexcept
{
return worldState.settings;
return fixedDT;
}
const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllCollisionInfo() const noexcept
@ -60,30 +73,43 @@ namespace SHADE
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
{
fixedDT = 1.0 / fixedUpdateRate;
// Handle invalid input
if (fixedUpdateRate <= 0.0)
{
SHLOGV_WARNING("Invalid value for setting fixed update rate! Fixed update rate unchanged.")
return;
}
void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept
fixedDT = 1.0 / fixedUpdateRate;
// Handle potential incorrect / unintended input
if (fixedDT > 1.0)
{
worldState.settings = settings;
worldState.UpdateSettings();
SHLOGV_WARNING("Fixed Update Rate Time is set below 1. This may result in undesirable behaviour.")
}
}
void SHPhysicsSystem::SetFixedDT(double fixedDt) noexcept
{
if (fixedDt <= 0.0)
{
SHLOGV_WARNING("Invalid value for setting fixed delta time! Fixed delta time unchanged.")
return;
}
fixedDT = fixedDt;
// Handle potential incorrect / unintended input
if (fixedDT > 1.0)
{
SHLOGV_WARNING("Fixed Delta Time is set above 1. This may result in undesirable behaviour.")
}
}
/*-----------------------------------------------------------------------------------*/
@ -92,40 +118,24 @@ namespace SHADE
void SHPhysicsSystem::Init()
{
// TODO(Diren): Consider using a non-static collision tag matrix.
// Initialise collision tags
std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT };
defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig");
SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath);
// Link Physics Object Manager with System & Raycaster
objectManager.SetFactory(factory);
raycaster.SetObjectManager(&objectManager);
// Register Events
for (int i = 0; i < NUM_EVENT_FUNCTIONS; ++i)
{
const std::shared_ptr EVENT_RECEIVER = std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, eventFunctions[i].first);
const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EVENT_RECEIVER);
// Link Collision Listener with System
SHEventManager::SubscribeTo(eventFunctions[i].second, EVENT_RECEIVER_PTR);
}
objectManager.SetFactory(&factory);
collisionListener.BindToSystem(this);
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::addPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::removePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(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<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::onPlay) };
const ReceiverPtr ON_PLAY_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ON_PLAY_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, ON_PLAY_RECEIVER_PTR);
const std::shared_ptr ON_STOP_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::onStop) };
const ReceiverPtr ON_STOP_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ON_STOP_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, ON_STOP_RECEIVER_PTR);
#endif
raycaster.BindToSystem(this);
}
void SHPhysicsSystem::Exit()
@ -138,344 +148,166 @@ namespace SHADE
SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath);
}
void SHPhysicsSystem::BuildScene(SHSceneGraph& sceneGraph)
const std::vector<SHPhysicsRaycastResult>& SHPhysicsSystem::Raycast(const SHRaycaster::RaycastInfo& info) noexcept
{
static const auto BUILD_NEW_SCENE_PHYSICS_OBJECT = [&](SHSceneNode* node)
{
const EntityID EID = node->GetEntityID();
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(EID))
objectManager.AddRigidBody(EID);
if (SHComponentManager::HasComponent<SHColliderComponent>(EID))
{
objectManager.AddCollider(EID);
auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(EID);
for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i)
objectManager.AddCollisionShape(EID, i);
}
};
////////////////////////////////
// Destroy an existing world
if (worldState.world != nullptr)
{
objectManager.RemoveAllObjects();
objectManager.SetWorld(nullptr);
collisionListener.ClearContainers();
raycaster.ClearFrame();
worldState.DestroyWorld(factory);
}
worldState.CreateWorld(factory);
#ifdef _PUBLISH
worldState.world->setIsDebugRenderingEnabled(false);
#else
worldState.world->setIsDebugRenderingEnabled(true);
#endif
// Link Collision Listener & Raycaster
collisionListener.BindToWorld(worldState.world);
raycaster.BindToWorld(worldState.world);
// Link with object manager & create all physics objects
objectManager.SetWorld(worldState.world);
// When building a scene, clear the object manager command queue and build scene objects again.
// This is done to avoid duplicate adds.
while (!objectManager.commandQueue.empty())
objectManager.commandQueue.pop();
sceneGraph.Traverse(BUILD_NEW_SCENE_PHYSICS_OBJECT);
objectManager.UpdateCommands();
}
void SHPhysicsSystem::ForceBuild(SHSceneGraph& sceneGraph)
{
// HACK: Band-aid fix. To be removed.
objectManager.UpdateCommands();
}
void SHPhysicsSystem::ForceUpdate()
{
if (!worldState.world)
{
SHLOGV_ERROR("Unable to force update without a Physics world!")
return;
}
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
// Force the physics world to update once
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
worldState.world->update(static_cast<rp3d::decimal>(fixedDT));
// Sync transforms. No interpolation applied here
for (auto& [entityID, physicsObject] : objectManager.physicsObjects)
{
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
const auto& CURRENT_TF = physicsObject.GetRigidBody()->getTransform();
const auto& RENDER_POS = CURRENT_TF.getPosition();
const auto& RENDER_ROT = CURRENT_TF.getOrientation();
// Cache transform
physicsObject.prevTransform = CURRENT_TF;
// Sync with physics components
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID))
{
rigidBodyComponent->position = RENDER_POS;
rigidBodyComponent->orientation = RENDER_ROT;
}
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(entityID))
{
colliderComponent->position = RENDER_POS;
colliderComponent->orientation = RENDER_ROT;
}
// Set transform for rendering
if (transformComponent)
{
transformComponent->SetWorldPosition(RENDER_POS);
transformComponent->SetWorldOrientation(RENDER_ROT);
}
}
}
SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept
{
return raycaster.Raycast(ray, distance, collisionTag);
}
SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept
{
return raycaster.Linecast(start, end, collisionTag);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept
{
return raycaster.ColliderRaycast(eid, ray, distance);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept
{
return raycaster.ColliderRaycast(eid, shapeIndex, ray, distance);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept
{
return raycaster.ColliderLinecast(eid, start, end);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept
{
return raycaster.ColliderLinecast(eid, shapeIndex, start, end);
}
void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex)
{
static const auto ADD_SHAPE = [&](EntityID entityID, int index)
{
objectManager.AddCollisionShape(entityID, index);
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
auto& collisionShape = colliderComponent->GetCollisionShape(index);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = collisionShape.GetType()
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
};
auto& results = raycaster.Raycast(info);
// Load start and end points into the container for debug drawing
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
ADD_SHAPE(eid, shapeIndex);
SHVec3 endPos = info.ray.position + info.ray.direction * SHRay::MAX_RAYCAST_DIST;
#else
if (!results.empty())
endPos = results.back().position;
ADD_SHAPE(eid, shapeIndex);
raycastHits.emplace_back(info.ray.position, endPos);
#endif
return results;
}
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<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
};
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
REMOVE_SHAPE(eid, shapeIndex);
#else
REMOVE_SHAPE(eid, shapeIndex);
#endif
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept
SHEventHandle SHPhysicsSystem::onSceneInit(SHEventPtr onSceneInitEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
/*
* 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.
*/
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
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)
// Destroy an existing world if there is one.
//! This should almost never happen.
if (worldState.world)
{
const EntityID EID = EVENT_DATA->data->eid;
// We only add tell the physics object manager to add a component if the scene is played
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
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
// Remove all references of physics objects from the world
for (const auto& PHYSICS_OBJECT : objectManager.GetPhysicsObjects() | std::views::values)
{
if (PHYSICS_OBJECT.body)
{
// Remove all colliders and destroy world
int32_t numShapes = static_cast<int32_t>(PHYSICS_OBJECT.body->getNbColliders());
while (--numShapes >= 0)
{
auto* rp3dCollider = PHYSICS_OBJECT.body->getCollider(numShapes);
PHYSICS_OBJECT.body->removeCollider(rp3dCollider);
}
return EVENT_DATA->handle;
worldState.world->destroyRigidBody(PHYSICS_OBJECT.body);
}
}
SHEventHandle SHPhysicsSystem::removePhysicsComponent(SHEventPtr removeComponentEvent) noexcept
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID EID = EVENT_DATA->data->eid;
// We only add tell the physics object manager to remove a component if the scene is played
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
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
worldState.DestroyWorld(factory);
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::onPlay(SHEventPtr onPlayEvent)
{
static const auto BUILD_PHYSICS_OBJECT = [&](SHSceneNode* node)
{
const EntityID EID = node->GetEntityID();
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(EID))
objectManager.AddRigidBody(EID);
if (SHComponentManager::HasComponent<SHColliderComponent>(EID))
{
objectManager.AddCollider(EID);
auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(EID);
for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i)
objectManager.AddCollisionShape(EID, i);
}
};
////////////////////////////////
// Create physics world
if (worldState.world != nullptr)
return onPlayEvent->handle;
// Create the physics world & collision space
worldState.CreateWorld(factory);
#ifdef _PUBLISH
worldState.world->setIsDebugRenderingEnabled(false);
#else
worldState.world->setIsDebugRenderingEnabled(true);
#endif
// Link Collision Listener & Raycaster
// Link with managers
objectManager.SetPhysicsWorld(worldState.world);
objectManager.FlushDefinitions();
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;
return onSceneInitEvent.get()->handle;
}
SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent)
SHEventHandle SHPhysicsSystem::onSceneExit(SHEventPtr onSceneExitEvent)
{
// Remove all physics objects
objectManager.RemoveAllObjects();
objectManager.SetWorld(nullptr);
/*
* Destroy the physics world.
* Destroy all physics objects.
*/
// Clear all collision info
// Collision listener is automatically unbound when world is destroyed
collisionListener.ClearContainers();
raycaster.ClearFrame();
// Destroy the world
worldState.DestroyWorld(factory);
return onStopEvent->handle;
if (worldState.world)
{
// Remove all references of physics objects from the world
for (const auto& PHYSICS_OBJECT : objectManager.GetPhysicsObjects() | std::views::values)
{
if (PHYSICS_OBJECT.body)
worldState.world->destroyRigidBody(PHYSICS_OBJECT.body);
}
worldState.DestroyWorld(factory);
}
// Unlink with managers
objectManager.SetPhysicsWorld(nullptr);
return onSceneExitEvent.get()->handle;
}
SHEventHandle SHPhysicsSystem::onComponentAdded(SHEventPtr onComponentAddedEvent)
{
static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(onComponentAddedEvent.get())->data;
const auto ADDED_ID = EVENT_DATA->addedComponentType;
const bool IS_RIGID_BODY = ADDED_ID == RIGID_BODY_COMPONENT_ID;
const bool IS_COLLIDER = ADDED_ID == COLLIDER_COMPONENT_ID;
// Check if its a physics component
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)
{
if (worldState.world)
objectManager.AddRigidBody(EID);
else
objectManager.AddRigidBodyDef(EID);
}
if (IS_COLLIDER)
{
if (worldState.world)
objectManager.AddCollider(EID);
else
objectManager.AddColliderDef(EID);
}
return onComponentAddedEvent.get()->handle;
}
SHEventHandle SHPhysicsSystem::onComponentRemoved(SHEventPtr onComponentRemovedEvent)
{
static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(onComponentRemovedEvent.get())->data;
const auto REMOVED_DATA = EVENT_DATA->removedComponentType;
const bool IS_RIGID_BODY = REMOVED_DATA == RIGID_BODY_COMPONENT_ID;
const bool IS_COLLIDER = REMOVED_DATA == COLLIDER_COMPONENT_ID;
// Check if its a physics component
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)
objectManager.RemoveRigidBody(EID);
if (IS_COLLIDER)
objectManager.RemoveCollider(EID);
return onComponentRemovedEvent.get()->handle;
}
} // namespace SHADE

View File

@ -10,8 +10,7 @@
#pragma once
#include <queue>
#include <unordered_map>
#include <utility>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
@ -19,14 +18,11 @@
// Project Headers
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/Collision/SHCollisionListener.h"
#include "Physics/Collision/SHPhysicsRaycaster.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h"
#include "Physics/Collision/SHCollisionInfo.h"
#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/RP3DWrapper/SHPhysicsWorld.h"
#include "Physics/RP3DWrapper/SHCollisionListener.h"
#include "Physics/RP3DWrapper/SHRaycaster.h"
#include "Scene/SHSceneGraph.h"
namespace SHADE
@ -43,254 +39,150 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsDebugDrawSystem;
friend class SHCollisionListener;
friend class SHRaycaster;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem();
SHPhysicsSystem () noexcept;
~SHPhysicsSystem() noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedUpdateRate () const noexcept;
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept;
[[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllTriggerInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFixedUpdateRate (double fixedUpdateRate) noexcept;
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
void SetFixedDT (double fixedDt) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init () override;
void Exit () override;
void BuildScene (SHSceneGraph& sceneGraph);
void ForceBuild (SHSceneGraph& sceneGraph);
void ForceUpdate ();
/**
* @brief Casts a ray into the world.
* @param ray The ray to cast.
* @param distance The distance to cast the ray. Defaults to infinity.
* @param collisionTag The collision tag to use for filtering the raycast.
* @return The result of the raycast.
* @brief
* - Initialises the static collision tag matrix.
* - Registers the system to catch specific events.
*/
SHPhysicsRaycastResult Raycast
(
const SHRay& ray
, float distance = std::numeric_limits<float>::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<float>::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<float>::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;
void Init() override;
void Exit() override;
/**
* @brief
* @param eid
* @param shapeIndex
* @param start
* @param end
* @return The result of the raycast.
* 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.
*/
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);
[[nodiscard]] const std::vector<SHPhysicsRaycastResult>& Raycast(const SHRaycaster::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.
* <br/>
* This update game logic is applied before the simulation runs.
*/
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPreUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void 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
/**
* @brief
* The physics update routine that runs at a fixed rate. This is where the main
* simulation runs. If delta time is large enough, this may run more than once per
* frame. If delta time is small enough, this may not run at all.
*/
class SH_API PhysicsUpdate final : public SHFixedSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsFixedUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute (double dt) noexcept override;
PhysicsUpdate();
void Execute(double dt) noexcept override;
};
/**
* @brief
* The physics update that runs after the simulation. This sets the rendering
* transforms and sends messages to scripting system for collision & trigger events. <br/>
*
*/
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:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using EventFunctionPair = std::pair<SHEventHandle(SHPhysicsSystem::*)(SHEventPtr), SHEventIdentifier>;
struct RaycastHit
{
SHVec3 start;
SHVec3 end;
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// System data
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;
// rp3d
// Sub-systems / managers
rp3d::PhysicsCommon factory;
// Interface objects
SHPhysicsWorldState worldState;
SHPhysicsObjectManager objectManager;
SHCollisionListener collisionListener;
SHPhysicsRaycaster raycaster;
SHRaycaster raycaster;
// For the debug drawer to draw rays
#ifdef SHEDITOR
std::vector<RaycastHit> raycastHits;
#endif
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept;
SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept;
SHEventHandle onSceneInit (SHEventPtr onSceneInitEvent);
SHEventHandle onSceneExit (SHEventPtr onSceneExitEvent);
SHEventHandle onPlay (SHEventPtr onPlayEvent);
SHEventHandle onStop (SHEventPtr onStopEvent);
SHEventHandle buildScene (SHEventPtr onSceneChangeEvent);
SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent);
SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent);
};
} // namespace SHADE

View File

@ -52,85 +52,43 @@ namespace SHADE
double SHPhysicsSystemInterface::GetFixedDT() noexcept
{
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem)
{
return 1.0 / phySystem->GetFixedUpdateRate();
}
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
return physicsSystem->GetFixedDT();
SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead.");
return 0.0;
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::Raycast(const SHRay& ray, float distance) noexcept
int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->Raycast(ray, distance);
return physicsSystem->GetFixedUpdateRate();
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{};
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::Linecast(const SHVec3& start, const SHVec3& end) noexcept
const std::vector<SHPhysicsRaycastResult>& SHPhysicsSystemInterface::Raycast(const RaycastInfo& info) noexcept
{
static std::vector<SHPhysicsRaycastResult> emptyVec;
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->Linecast(start, end);
SHRaycaster::RaycastInfo raycastInfo;
raycastInfo.continuous = info.continuous;
raycastInfo.distance = info.distance;
raycastInfo.layers = info.layers;
raycastInfo.ray = info.ray;
if (info.colliderEntityID.has_value())
raycastInfo.SetColliderID(info.colliderEntityID.value());
return physicsSystem->Raycast(raycastInfo);
}
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<SHPhysicsSystem>();
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<SHPhysicsSystem>();
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<SHPhysicsSystem>();
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<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->ColliderLinecast(eid, shapeIndex, start, end);
}
SHLOGV_WARNING("Failed to get the physics system. No ray was casted.");
return SHPhysicsRaycastResult{};
return emptyVec;
}
}

View File

@ -12,11 +12,13 @@ of DigiPen Institute of Technology is prohibited.
#pragma once
// STL Includes
#include <optional>
#include <vector>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "Math/SHRay.h"
#include "Physics/Collision/CollisionTags/SHCollisionTags.h"
namespace SHADE
{
@ -25,11 +27,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
class SHCollisionInfo;
class SHVec3;
struct SHRay;
struct SHPhysicsRaycastResult;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
@ -40,6 +39,48 @@ namespace SHADE
class SH_API SHPhysicsSystemInterface final
{
public:
struct RaycastInfo
{
private:
/*-------------------------------------------------------------------------------*/
/* Friends */
/*-------------------------------------------------------------------------------*/
friend class SHPhysicsSystemInterface;
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
bool continuous = false;
uint16_t layers = static_cast<uint16_t>(SHCollisionTag::Layer::ALL);
float distance = std::numeric_limits<float>::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<EntityID> colliderEntityID;
};
/*---------------------------------------------------------------------------------*/
/* Constructor */
/*---------------------------------------------------------------------------------*/
@ -49,15 +90,11 @@ namespace SHADE
/* Static Usage Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo() noexcept;
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo () noexcept;
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo () noexcept;
[[nodiscard]] static double GetFixedDT () noexcept;
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
[[nodiscard]] static const std::vector<SHPhysicsRaycastResult>& Raycast (const RaycastInfo& info) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult Raycast (const SHRay& ray, float distance = std::numeric_limits<float>::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<float>::infinity()) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, int shapeIndex, const SHRay& ray, float distance = std::numeric_limits<float>::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;
};
}

View File

@ -1,412 +0,0 @@
/****************************************************************************************
* \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 <SHpch.h>
// 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<SHPhysicsSystem*>(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<SHEditor>();
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<SHRigidBodyComponent>();
auto& colliderDense = SHComponentManager::GetDense<SHColliderComponent>();
for (auto& rigidBodyComponent : rigidBodyDense)
{
const auto* TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(rigidBodyComponent.GetEID());
if (TRANSFORM && TRANSFORM->HasChanged())
{
rigidBodyComponent.position = TRANSFORM->GetWorldPosition();
rigidBodyComponent.orientation = TRANSFORM->GetWorldOrientation();
}
}
for (auto& colliderComponent : colliderDense)
{
const auto* TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(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<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
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<rp3d::decimal>(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<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
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<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(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<SHRigidBodyComponent>(eid))
return;
const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(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<SHColliderComponent>(eid);
if (!COLLIDER)
return;
const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(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<SHPhysicsSystem*>(GetSystem());
const int NUM_SHAPES = static_cast<int>(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<SHTransformComponent>(eid);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(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<SHRigidBodyComponent>(physicsObject.entityID))
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(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<SHRigidBodyComponent>(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<rp3d::decimal>(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<SHColliderComponent>(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<SHRigidBodyComponent>(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<SHPhysicsSystem>();
physicsSystem->Raycast(ray, std::numeric_limits<float>::infinity(), *tag);
}

View File

@ -261,6 +261,7 @@ namespace SHADE
<TargetFramework>net5.0</TargetFramework>\n\
<Platforms>x64</Platforms>\n\
<Configurations>Release;Debug</Configurations>\n\
<DefaultItemExcludes>$(DefaultItemExcludes);**/*.shmeta</DefaultItemExcludes>\n\
</PropertyGroup>\n\
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n\
<OutputPath>.\\bin\\Release</OutputPath>\n\
@ -283,7 +284,6 @@ namespace SHADE
<ItemGroup>\n\
<None Remove=\".gitignore\" />\n\
<None Remove=\".gitmodules\" />\n\
<None Remove=\"*.shmeta\" />\n\
</ItemGroup>\n\
<ItemGroup>\n\
<Reference Include=\"SHADE_Managed\">\n";

View File

@ -3,9 +3,8 @@
#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 "Physics/Collision/Shapes/SHSphere.h"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Resource/SHResourceManager.h"
#include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h"
@ -15,7 +14,7 @@
#include "SHSerializationTools.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h"
#include "Animation/SHAnimatorComponent.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
namespace YAML
{
@ -149,17 +148,17 @@ namespace YAML
{
case SHCollisionShape::Type::BOX:
{
const auto* BOX = reinterpret_cast<const SHBox*>(rhs.GetShape());
node[HalfExtents] = BOX->GetRelativeExtents();
const auto& BOX_SHAPE = dynamic_cast<SHBox&>(rhs);
node[HalfExtents] = BOX_SHAPE.GetRelativeExtents();
}
break;
case SHCollisionShape::Type::SPHERE:
{
const auto* SPHERE = reinterpret_cast<const SHSphere*>(rhs.GetShape());
node[Radius] = SPHERE->GetRelativeRadius();
const auto& SPHERE_SHAPE = dynamic_cast<SHSphere&>(rhs);
node[Radius] = SPHERE_SHAPE.GetRelativeRadius();
}
break;
case SHCollisionShape::Type::CAPSULE: break;
//case SHCollisionShape::Type::CAPSULE: break;
default:;
}
@ -192,16 +191,16 @@ namespace YAML
case SHCollisionShape::Type::BOX:
{
if (node[HalfExtents].IsDefined())
rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>());
dynamic_cast<SHBox&>(rhs).SetRelativeExtents(node[HalfExtents].as<SHVec3>());
}
break;
case SHCollisionShape::Type::SPHERE:
{
if (node[Radius].IsDefined())
rhs.SetBoundingSphere(node[Radius].as<float>());
dynamic_cast<SHSphere&>(rhs).SetRelativeRadius(node[Radius].as<float>());
}
break;
case SHCollisionShape::Type::CAPSULE: break;
//case SHCollisionShape::Type::CAPSULE: break;
default:;
}
if (node[Friction].IsDefined())
@ -254,9 +253,9 @@ namespace YAML
switch (colliderType)
{
case SHCollisionShape::Type::BOX: rhs.AddBoundingBox(); break;
case SHCollisionShape::Type::SPHERE: rhs.AddBoundingSphere(); break;
case SHCollisionShape::Type::CAPSULE: break;
case SHCollisionShape::Type::BOX: rhs.AddBoxCollisionShape(SHVec3::One); break;
case SHCollisionShape::Type::SPHERE: rhs.AddSphereCollisionShape(1.0f); break;
//case SHCollisionShape::Type::CAPSULE: break;
default:;
}
YAML::convert<SHCollisionShape>::decode(colliderNode, rhs.GetCollisionShape(numColliders++));

View File

@ -4,7 +4,6 @@
\par email: kahwei.tng\@digipen.edu
\date Oct 20, 2022
\brief Contains the definition of the functions of the managed Collider class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 DigiPen Institute of Technology.
@ -15,6 +14,9 @@ of DigiPen Institute of Technology is prohibited.
#include "SHpch.h"
// Primary Header
#include "Collider.hxx"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "Utility/Debug.hxx"
namespace SHADE
@ -120,7 +122,7 @@ namespace SHADE
/* BoxCollider - Constructors */
/*---------------------------------------------------------------------------------*/
BoxCollider::BoxCollider(int arrayIdx, Entity attachedEntity)
: CollisionShape { arrayIndex, attachedEntity }
: CollisionShape { arrayIdx, attachedEntity }
{}
/*---------------------------------------------------------------------------------*/
@ -128,11 +130,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
Vector3 BoxCollider::Center::get()
{
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetCenter());
}
void BoxCollider::Center::set(Vector3 value)
{
getNativeCollisionShape<SHBox>().SetCenter(Convert::ToNative(value));
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetWorldCentroid());
}
Vector3 BoxCollider::HalfExtents::get()
{
@ -142,21 +140,10 @@ namespace SHADE
{
getNativeCollisionShape<SHBox>().SetWorldExtents(Convert::ToNative(value));
}
Vector3 BoxCollider::Min::get()
Quaternion BoxCollider::Orientation::get()
{
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetMin());
}
void BoxCollider::Min::set(Vector3 value)
{
getNativeCollisionShape<SHBox>().SetMin(Convert::ToNative(value));
}
Vector3 BoxCollider::Max::get()
{
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetMax());
}
void BoxCollider::Max::set(Vector3 value)
{
getNativeCollisionShape<SHBox>().SetMax(Convert::ToNative(value));
//return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetWorldOrientation());
return Quaternion::Identity;
}
/*---------------------------------------------------------------------------------*/
@ -164,11 +151,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
bool BoxCollider::TestPoint(Vector3 point)
{
return getNativeCollisionShape<SHBox>().TestPoint(Convert::ToNative(point));
//return getNativeCollisionShape<SHAABB>().TestPoint(Convert::ToNative(point));
return false;
}
bool BoxCollider::Raycast(Ray ray, float maxDistance)
{
return getNativeCollisionShape<SHBox>().Raycast(Convert::ToNative(ray));
//return getNativeCollisionShape<SHAABB>().Raycast(Convert::ToNative(ray));
return false;
}
/*---------------------------------------------------------------------------------*/
@ -176,11 +165,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
Vector3 SphereCollider::Center::get()
{
return Convert::ToCLI(getNativeCollisionShape<SHSphere>().GetCenter());
}
void SphereCollider::Center::set(Vector3 value)
{
getNativeCollisionShape<SHSphere>().SetCenter(Convert::ToNative(value));
return Convert::ToCLI(getNativeCollisionShape<SHSphere>().GetWorldCentroid());
}
float SphereCollider::Radius::get()
{
@ -196,11 +181,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
bool SphereCollider::TestPoint(Vector3 point)
{
return getNativeCollisionShape<SHBox>().TestPoint(Convert::ToNative(point));
//return getNativeCollisionShape<SHSphere>().TestPoint(Convert::ToNative(point));
return false;
}
bool SphereCollider::Raycast(Ray ray, float maxDistance)
{
return getNativeCollisionShape<SHBox>().Raycast(Convert::ToNative(ray));
//return getNativeCollisionShape<SHSphere>().Raycast(Convert::ToNative(ray));
return false;
}
/*---------------------------------------------------------------------------------*/
@ -231,7 +218,10 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
int Collider::CollisionShapeCount::get()
{
return static_cast<int>(GetNativeComponent()->GetCollisionShapes().size());
if (const auto* nativeComponent = GetNativeComponent(); nativeComponent)
return static_cast<int>(nativeComponent->GetCollisionShapes().size());
return -1;
}
/*---------------------------------------------------------------------------------*/
@ -314,7 +304,7 @@ namespace SHADE
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());
@ -322,9 +312,9 @@ namespace SHADE
case SHCollisionShape::Type::SPHERE:
bound = gcnew SphereCollider(i, Owner.GetEntity());
break;
case SHCollisionShape::Type::CAPSULE:
// TODO
break;
//case SHCollisionShape::Type::CAPSULE:
// // TODO
// break;
default:
Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping.");
break;

View File

@ -31,7 +31,7 @@ namespace SHADE
if (shape.GetType() != SHCollisionShape::Type::BOX)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
return reinterpret_cast<CollisionShapeType&>(shape);
return dynamic_cast<CollisionShapeType&>(shape);
}
catch (std::invalid_argument&)
{

View File

@ -1,7 +1,9 @@
/************************************************************************************//*!
\file Collider.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
Diren D Bharwani, diren.dbharwani, 390002520
\par email: kahwei.tng\@digipen.edu
email: diren.dbharwani\@digipen.edu
\date Oct 20, 2022
\brief Contains the definition of the managed Collider class with the
declaration of functions for working with it.
@ -142,15 +144,14 @@ namespace SHADE
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Box formed by this bound.
/// Center of the box collider.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Half of the scale of the Bounding Box formed by this bound.
/// Half of the scale of the box collider.
/// </summary>
property Vector3 HalfExtents
{
@ -158,22 +159,11 @@ namespace SHADE
void set(Vector3 value);
}
/// <summary>
/// Position of the bottom left back corner of the Bounding Box formed by this
/// bound.
/// The orientation of the box.
/// </summary>
property Vector3 Min
property Quaternion Orientation
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Position of the top right front corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Max
{
Vector3 get();
void set(Vector3 value);
Quaternion get();
}
/*-----------------------------------------------------------------------------*/
@ -201,12 +191,11 @@ namespace SHADE
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Sphere formed by this bound.
/// Center of the sphere.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Radius of the Bounding Sphere formed by this bound.

View File

@ -15,10 +15,14 @@
// External Dependencies
#include "Physics/System/SHPhysicsSystemInterface.h"
// Project Header
#include "Components/Collider.hxx"
#include "Components/Transform.hxx"
#include "Engine/GameObject.hxx"
#include "Utility/Convert.hxx"
#include "Utility/Debug.hxx"
using namespace System::Collections::Generic;
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
@ -41,49 +45,271 @@ namespace SHADE
/* Raycast Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
RaycastHit Physics::Raycast(Ray ray)
List<RaycastHit>^ Physics::Raycast(Ray ray, bool continuous, unsigned short layer)
{
return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray)));
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
RaycastHit Physics::Raycast(Ray ray, float distance)
{
return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray), distance));
return results;
}
RaycastHit Physics::Linecast(Vector3 start, Vector3 end)
List<RaycastHit>^ Physics::Raycast(Ray ray, float distance, bool continuous, unsigned short layer)
{
return Convert::ToCLI(SHPhysicsSystemInterface::Linecast(Convert::ToNative(start), Convert::ToNative(end)));
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.distance = distance;
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray)
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray)));
return results;
}
RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance)
List<RaycastHit>^ Physics::Linecast(Vector3 start, Vector3 end, bool continuous, unsigned short layer)
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray), distance));
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray)
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray)));
return results;
}
RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance)
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, Ray ray, bool continuous, unsigned short layer)
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray), distance));
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
ray.Position += COLLIDER_POS;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
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));
}
RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end)
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, Convert::ToNative(start), Convert::ToNative(end)));
return results;
}
RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end)
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, Ray ray, float distance, bool continuous, unsigned short layer)
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, shapeIndex, Convert::ToNative(start), Convert::ToNative(end)));
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
ray.Position += COLLIDER_POS;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.distance = distance;
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
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;
}
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, bool continuous, unsigned short layer)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
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;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
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;
}
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance, bool continuous, unsigned short layer)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
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;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.distance = distance;
raycastInfo.layers = layer;
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;
}
List<RaycastHit>^ Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end, bool continuous, unsigned short layer)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
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 );
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.continuous = continuous;
raycastInfo.layers = layer;
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;
}
List<RaycastHit>^ Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous, unsigned short layer)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
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 );
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.continuous = continuous;
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.layers = layer;
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;
}
/*-----------------------------------------------------------------------------------*/

View File

@ -40,82 +40,146 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Casts an infinite ray into the world.
/// Casts an infinite ray into the world. <br/>
/// This raycast will stop at the first object hit.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit Raycast (Ray ray);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <param name="layer">
/// The layers to cast the ray on.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Raycast (Ray ray, bool continuous, unsigned short layer);
/// <summary>
/// Casts a ray for a given distance into the world.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit Raycast (Ray ray, float distance);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Raycast (Ray ray, float distance, bool continuous, unsigned short layer);
/// <summary>
/// Casts a bounded ray into the world.
/// </summary>
/// <param name="start">The start of the bounded ray.</param>
/// <param name="end">The end of the bounded ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit Linecast (Vector3 start, Vector3 end);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Linecast (Vector3 start, Vector3 end, bool continuous, unsigned short layer);
/// <summary>
/// Casts an infinite ray w.r.t a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, Ray ray);
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, Ray ray, bool continuous, unsigned short layer);
/// <summary>
/// Casts a ray for a given distance w.r.t a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="ray">The ray to cast.</param>
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, Ray ray, float distance, bool continuous, unsigned short layer);
/// <summary>
/// Casts an infinite ray w.r.t a specific collider on a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray);
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, bool continuous, unsigned short layer);
/// <summary>
/// Casts a ray for a given distance w.r.t a specific collider on a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="ray">The ray to cast.</param>
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance, bool continuous, unsigned short layer);
/// <summary>
/// Casts a bounded ray w.r.t a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="start">The start of the bounded ray.</param>
/// <param name="start">
/// The start of the bounded ray. <br/>
/// The start of the ray is offset from the collider's position. </param>
/// <param name="end"></param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderLineCast (GameObject object, Vector3 start, Vector3 end, bool continuous, unsigned short layer);
/// <summary>
/// Casts a bounded ray w.r.t a specific collider on a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="start">The start of the bounded ray.</param>
/// <param name="start">
/// The start of the bounded ray. <br/>
/// The start of the ray is offset from the collider's position. </param>
/// <param name="end">The end of the bounded ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned./// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous, unsigned short layer);
private:
/*---------------------------------------------------------------------------------*/