Added a forced update to the physics system

This commit is contained in:
Diren D Bharwani 2022-11-14 00:20:54 +08:00
parent c98693c6bc
commit d36d70e3eb
7 changed files with 194 additions and 142 deletions

View File

@ -16,6 +16,7 @@
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Scene/SHSceneManager.h"
namespace SHADE
@ -148,6 +149,10 @@ namespace SHADE
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;
@ -267,6 +272,10 @@ namespace SHADE
void SHPhysicsObject::SyncColliders(SHColliderComponent& component) const noexcept
{
// This state is synced in the pre-update routine
if (!rp3dBody->isActive())
return;
int index = 0;
for (auto& collisionShape : component.collisionShapes)
{

View File

@ -167,6 +167,7 @@ namespace SHADE
if (!COMPONENT_GROUP.rigidBodyComponent && !COMPONENT_GROUP.colliderComponent)
{
destroyPhysicsObject(COMMAND.eid);
wakeAllObjects();
continue;
}
@ -176,6 +177,10 @@ namespace SHADE
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();
}
}
@ -297,5 +302,11 @@ namespace SHADE
physicsObject->RemoveCollisionShape(command.shapeIndex);
}
void SHPhysicsObjectManager::wakeAllObjects() noexcept
{
for (auto& physicsObject : physicsObjects | std::views::values)
physicsObject.GetRigidBody()->setIsSleeping(false);
}
} // namespace SHADE

View File

@ -165,6 +165,8 @@ namespace SHADE
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);
@ -172,6 +174,8 @@ namespace SHADE
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

@ -20,6 +20,7 @@
#include "Editor/SHEditor.h"
#include "Physics/SHPhysicsEvents.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
/*-------------------------------------------------------------------------------------*/
/* Local Helper Functions */
@ -34,16 +35,16 @@ namespace SHADE
SHPhysicsSystem::SHPhysicsSystem()
: worldUpdated { false }
, interpolationFactor { 0.0 }
, fixedDT { 60.0 }
, fixedDT { DEFAULT_FIXED_STEP }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
double SHPhysicsSystem::GetFixedDT() const noexcept
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
{
return fixedDT;
return 1.0 / fixedDT;
}
const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept
@ -76,9 +77,9 @@ namespace SHADE
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept
void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept
{
fixedDT = fixedUpdateRate;
fixedDT = 1.0 / fixedUpdateRate;
}
void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept
@ -126,6 +127,45 @@ namespace SHADE
worldState.DestroyWorld(factory);
}
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);
postUpdateSyncTransforms
(
physicsObject
, transformComponent
, rigidBodyComponent
, colliderComponent
, 1.0 // We use 1.0 here to avoid any interpolation
);
}
}
void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex)
{
static const auto ADD_SHAPE = [&](EntityID entityID, int index)
@ -339,5 +379,92 @@ namespace SHADE
return onStopEvent->handle;
}
void SHPhysicsSystem::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);
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
colliderComponent->scale = WORLD_SCL;
colliderComponent->RecomputeCollisionShapes();
}
}
void SHPhysicsSystem::postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent* transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept
{
const rp3d::Transform& CURRENT_TF = physicsObject.rp3dBody->getTransform();
auto renderPos = CURRENT_TF.getPosition();
auto renderRot = CURRENT_TF.getOrientation();
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
// Sync with rigid bodies
if (rigidBodyComponent)
{
// 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)
{
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
// Set transform for rendering
if (transformComponent)
{
transformComponent->SetWorldPosition(renderPos);
transformComponent->SetWorldOrientation(renderRot);
}
}
} // namespace SHADE

View File

@ -55,7 +55,7 @@ namespace SHADE
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] double GetFixedUpdateRate () const noexcept;
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
@ -67,8 +67,8 @@ namespace SHADE
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFixedDT (double fixedUpdateRate) noexcept;
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
void SetFixedUpdateRate (double fixedUpdateRate) noexcept;
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
@ -77,6 +77,8 @@ namespace SHADE
void Init () override;
void Exit () override;
void ForceUpdate ();
// Specific Handling for Collision Shapes as they are not under the Component System
void AddCollisionShape (EntityID eid, int shapeIndex);
@ -121,14 +123,6 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/
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
@ -161,20 +155,6 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept;
};
private:
@ -208,5 +188,24 @@ namespace SHADE
SHEventHandle onPlay (SHEventPtr onPlayEvent);
SHEventHandle onStop (SHEventPtr onStopEvent);
static void preUpdateSyncTransform
(
SHPhysicsObject& physicsObject
, SHTransformComponent* transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
) noexcept;
static void postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent* transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept;
};
} // namespace SHADE

View File

@ -55,7 +55,7 @@ namespace SHADE
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem)
{
return phySystem->GetFixedDT();
return phySystem->GetFixedUpdateRate();
}
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get fixed delta time. 0.0 returned instead.");

View File

@ -125,18 +125,18 @@ namespace SHADE
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
const double FIXED_DT = physicsSystem->fixedDT;
accumulatedTime += dt;
int count = 0;
while (accumulatedTime > fixedTimeStep)
while (accumulatedTime > FIXED_DT)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(fixedTimeStep));
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(FIXED_DT));
accumulatedTime -= fixedTimeStep;
accumulatedTime -= FIXED_DT;
++count;
}
@ -165,17 +165,14 @@ namespace SHADE
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (transformComponent)
{
postUpdateSyncTransforms
(
physicsObject
, *transformComponent
, rigidBodyComponent
, colliderComponent
, physicsSystem->interpolationFactor
);
}
postUpdateSyncTransforms
(
physicsObject
, transformComponent
, rigidBodyComponent
, colliderComponent
, physicsSystem->interpolationFactor
);
}
// Collision & Trigger messages
@ -203,7 +200,7 @@ namespace SHADE
preUpdateSyncTransform
(
physicsObject
, *transformComponent
, transformComponent
, rigidBodyComponent
, colliderComponent
);
@ -217,99 +214,4 @@ namespace SHADE
if (colliderComponent)
physicsObject.SyncColliders(*colliderComponent);
}
void SHPhysicsSystem::PhysicsPreUpdate::preUpdateSyncTransform
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
) noexcept
{
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);
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
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
{
rp3d::Vector3 rp3dPos;
rp3d::Quaternion rp3dRot;
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
// Check if transform should be interpolated
if (rigidBodyComponent)
{
// Skip static bodies
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
return;
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));
rp3dPos = INTERPOLATED_TF.getPosition();
rp3dRot = INTERPOLATED_TF.getOrientation();
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (colliderComponent)
{
// Sync with colliders
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
// Convert RP3D Transform to SHADE
transformComponent.SetWorldPosition(rp3dPos);
transformComponent.SetWorldOrientation(rp3dRot);
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
}
} // namespace SHADE