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:
parent
ca011927f3
commit
35928cf4d3
5 changed files with 37 additions and 56 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue