1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-31 14:36:39 +00:00

Refactor a bit the physics simulation to make it not actor centric:

- inline PhysicsSystem::applyQueuedMovements() into PhysicsSystem::stepSimulation()
- rename PhysicsTaskScheduler::moveActors() to PhysicsTaskScheduler::applyQueuedMovements()
- move the actor movement code from World::doPhysics() to
  PhysicsSystem::moveActors() (analogically to the projectile manager)
This commit is contained in:
fredzio 2021-07-31 23:26:10 +02:00
parent ca011927f3
commit 35928cf4d3
5 changed files with 37 additions and 56 deletions

View file

@ -230,7 +230,7 @@ namespace MWPhysics
return std::make_tuple(numSteps, actualDelta); return std::make_tuple(numSteps, actualDelta);
} }
const std::vector<MWWorld::Ptr>& PhysicsTaskScheduler::moveActors(float & timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats) void PhysicsTaskScheduler::applyQueuedMovements(float & timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{ {
// This function run in the main thread. // This function run in the main thread.
// While the mSimulationMutex is held, background physics threads can't run. // While the mSimulationMutex is held, background physics threads can't run.
@ -239,8 +239,6 @@ namespace MWPhysics
double timeStart = mTimer->tick(); double timeStart = mTimer->tick();
mMovedActors.clear();
// start by finishing previous background computation // start by finishing previous background computation
if (mNumThreads != 0) if (mNumThreads != 0)
{ {
@ -260,7 +258,6 @@ namespace MWPhysics
if (mAdvanceSimulation) if (mAdvanceSimulation)
data.mActorRaw->setStandingOnPtr(data.mStandingOn); data.mActorRaw->setStandingOnPtr(data.mStandingOn);
data.mActorRaw->setSimulationPosition(interpolateMovements(data, mTimeAccum, mPhysicsDt)); data.mActorRaw->setSimulationPosition(interpolateMovements(data, mTimeAccum, mPhysicsDt));
mMovedActors.emplace_back(data.mActorRaw->getPtr());
} }
} }
if(mAdvanceSimulation) if(mAdvanceSimulation)
@ -296,7 +293,7 @@ namespace MWPhysics
syncComputation(); syncComputation();
if(mAdvanceSimulation) if(mAdvanceSimulation)
mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), numSteps, mBudgetCursor); mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), numSteps, mBudgetCursor);
return mMovedActors; return;
} }
mAsyncStartTime = mTimer->tick(); mAsyncStartTime = mTimer->tick();
@ -304,23 +301,19 @@ namespace MWPhysics
mHasJob.notify_all(); mHasJob.notify_all();
if (mAdvanceSimulation) if (mAdvanceSimulation)
mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), 1, mBudgetCursor); mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), 1, mBudgetCursor);
return mMovedActors;
} }
const std::vector<MWWorld::Ptr>& PhysicsTaskScheduler::resetSimulation(const ActorMap& actors) void PhysicsTaskScheduler::resetSimulation(const ActorMap& actors)
{ {
std::unique_lock lock(mSimulationMutex); std::unique_lock lock(mSimulationMutex);
mBudget.reset(mDefaultPhysicsDt); mBudget.reset(mDefaultPhysicsDt);
mAsyncBudget.reset(0.0f); mAsyncBudget.reset(0.0f);
mMovedActors.clear();
mActorsFrameData.clear(); mActorsFrameData.clear();
for (const auto& [_, actor] : actors) for (const auto& [_, actor] : actors)
{ {
actor->updatePosition(); actor->updatePosition();
actor->updateCollisionObjectPosition(); actor->updateCollisionObjectPosition();
mMovedActors.emplace_back(actor->getPtr());
} }
return mMovedActors;
} }
void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
@ -561,7 +554,6 @@ namespace MWPhysics
handleFall(actorData, mAdvanceSimulation); handleFall(actorData, mAdvanceSimulation);
actorData.mActorRaw->setSimulationPosition(interpolateMovements(actorData, mTimeAccum, mPhysicsDt)); actorData.mActorRaw->setSimulationPosition(interpolateMovements(actorData, mTimeAccum, mPhysicsDt));
updateMechanics(actorData); updateMechanics(actorData);
mMovedActors.emplace_back(actorData.mActorRaw->getPtr());
if (mAdvanceSimulation) if (mAdvanceSimulation)
actorData.mActorRaw->setStandingOnPtr(actorData.mStandingOn); actorData.mActorRaw->setStandingOnPtr(actorData.mStandingOn);
} }

View file

@ -38,9 +38,9 @@ namespace MWPhysics
/// @param timeAccum accumulated time from previous run to interpolate movements /// @param timeAccum accumulated time from previous run to interpolate movements
/// @param actorsData per actor data needed to compute new positions /// @param actorsData per actor data needed to compute new positions
/// @return new position of each actor /// @return new position of each actor
const std::vector<MWWorld::Ptr>& moveActors(float & timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats); void applyQueuedMovements(float & timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
const std::vector<MWWorld::Ptr>& resetSimulation(const ActorMap& actors); void resetSimulation(const ActorMap& actors);
// Thread safe wrappers // Thread safe wrappers
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const; void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
@ -72,7 +72,6 @@ namespace MWPhysics
std::unique_ptr<WorldFrameData> mWorldFrameData; std::unique_ptr<WorldFrameData> mWorldFrameData;
std::vector<ActorFrameData> mActorsFrameData; std::vector<ActorFrameData> mActorsFrameData;
std::vector<MWWorld::Ptr> mMovedActors;
float mDefaultPhysicsDt; float mDefaultPhysicsDt;
float mPhysicsDt; float mPhysicsDt;
float mTimeAccum; float mTimeAccum;

View file

@ -751,17 +751,6 @@ namespace MWPhysics
actor->setVelocity(osg::Vec3f()); actor->setVelocity(osg::Vec3f());
} }
const std::vector<MWWorld::Ptr>& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{
mTimeAccum += dt;
if (skipSimulation)
return mTaskScheduler->resetSimulation(mActors);
// modifies mTimeAccum
return mTaskScheduler->moveActors(mTimeAccum, prepareFrameData(mTimeAccum >= mPhysicsDt), frameStart, frameNumber, stats);
}
std::vector<ActorFrameData> PhysicsSystem::prepareFrameData(bool willSimulate) std::vector<ActorFrameData> PhysicsSystem::prepareFrameData(bool willSimulate)
{ {
std::vector<ActorFrameData> actorsFrameData; std::vector<ActorFrameData> actorsFrameData;
@ -798,20 +787,43 @@ namespace MWPhysics
return actorsFrameData; return actorsFrameData;
} }
void PhysicsSystem::stepSimulation() void PhysicsSystem::stepSimulation(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{ {
for (Object* animatedObject : mAnimatedObjects) for (Object* animatedObject : mAnimatedObjects)
{
if (animatedObject->animateCollisionShapes()) if (animatedObject->animateCollisionShapes())
{ {
auto obj = mObjects.find(animatedObject->getPtr()); auto obj = mObjects.find(animatedObject->getPtr());
assert(obj != mObjects.end()); assert(obj != mObjects.end());
mTaskScheduler->updateSingleAabb(obj->second); mTaskScheduler->updateSingleAabb(obj->second);
} }
}
#ifndef BT_NO_PROFILE #ifndef BT_NO_PROFILE
CProfileManager::Reset(); CProfileManager::Reset();
CProfileManager::Increment_Frame_Counter(); CProfileManager::Increment_Frame_Counter();
#endif #endif
mTimeAccum += dt;
if (skipSimulation)
mTaskScheduler->resetSimulation(mActors);
else
// modifies mTimeAccum
mTaskScheduler->applyQueuedMovements(mTimeAccum, prepareFrameData(mTimeAccum >= mPhysicsDt), frameStart, frameNumber, stats);
}
void PhysicsSystem::moveActors()
{
auto* player = getActor(MWMechanics::getPlayer());
auto* world = MWBase::Environment::get().getWorld();
for (auto& [ptr, physicActor] : mActors)
{
if (physicActor.get() == player)
continue;
world->moveObject(physicActor->getPtr(), physicActor->getSimulationPosition(), false, false);
}
world->moveObject(player->getPtr(), player->getSimulationPosition(), false, false);
} }
void PhysicsSystem::updateAnimatedCollisionShape(const MWWorld::Ptr& object) void PhysicsSystem::updateAnimatedCollisionShape(const MWWorld::Ptr& object)

View file

@ -154,7 +154,11 @@ namespace MWPhysics
bool toggleCollisionMode(); bool toggleCollisionMode();
void stepSimulation(); /// Determine new position based on all queued movements, then clear the list.
void stepSimulation(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
/// Apply new positions to actors
void moveActors();
void debugDraw(); void debugDraw();
std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with
@ -204,12 +208,9 @@ namespace MWPhysics
osg::BoundingBox getBoundingBox(const MWWorld::ConstPtr &object) const; osg::BoundingBox getBoundingBox(const MWWorld::ConstPtr &object) const;
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
/// be overwritten. Valid until the next call to applyQueuedMovement. /// be overwritten. Valid until the next call to stepSimulation
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
/// Apply all queued movements, then clear the list.
const std::vector<MWWorld::Ptr>& applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
/// Clear the queued movements list without applying. /// Clear the queued movements list without applying.
void clearQueuedMovement(); void clearQueuedMovement();

View file

@ -1508,35 +1508,12 @@ namespace MWWorld
void World::doPhysics(float duration, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats) void World::doPhysics(float duration, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{ {
mPhysics->stepSimulation();
processDoors(duration); processDoors(duration);
mProjectileManager->update(duration); mProjectileManager->update(duration);
mPhysics->stepSimulation(duration, mDiscardMovements, frameStart, frameNumber, stats);
const auto& results = mPhysics->applyQueuedMovement(duration, mDiscardMovements, frameStart, frameNumber, stats);
mProjectileManager->processHits(); mProjectileManager->processHits();
mDiscardMovements = false; mDiscardMovements = false;
mPhysics->moveActors();
for(const auto& actor : results)
{
// Handle player last, in case a cell transition occurs
if(actor != getPlayerPtr())
{
auto* physactor = mPhysics->getActor(actor);
assert(physactor);
const auto position = physactor->getSimulationPosition();
moveObject(actor, position, false, false);
}
}
const auto player = std::find(results.begin(), results.end(), getPlayerPtr());
if (player != results.end())
{
auto* physactor = mPhysics->getActor(*player);
assert(physactor);
const auto position = physactor->getSimulationPosition();
moveObject(*player, position, false, false);
}
} }
void World::updateNavigator() void World::updateNavigator()