mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-06 01:49:42 +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);
|
||||
}
|
||||
|
||||
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.
|
||||
// While the mSimulationMutex is held, background physics threads can't run.
|
||||
|
@ -239,8 +239,6 @@ namespace MWPhysics
|
|||
|
||||
double timeStart = mTimer->tick();
|
||||
|
||||
mMovedActors.clear();
|
||||
|
||||
// start by finishing previous background computation
|
||||
if (mNumThreads != 0)
|
||||
{
|
||||
|
@ -260,7 +258,6 @@ namespace MWPhysics
|
|||
if (mAdvanceSimulation)
|
||||
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
|
||||
data.mActorRaw->setSimulationPosition(interpolateMovements(data, mTimeAccum, mPhysicsDt));
|
||||
mMovedActors.emplace_back(data.mActorRaw->getPtr());
|
||||
}
|
||||
}
|
||||
if(mAdvanceSimulation)
|
||||
|
@ -296,7 +293,7 @@ namespace MWPhysics
|
|||
syncComputation();
|
||||
if(mAdvanceSimulation)
|
||||
mBudget.update(mTimer->delta_s(timeStart, mTimer->tick()), numSteps, mBudgetCursor);
|
||||
return mMovedActors;
|
||||
return;
|
||||
}
|
||||
|
||||
mAsyncStartTime = mTimer->tick();
|
||||
|
@ -304,23 +301,19 @@ namespace MWPhysics
|
|||
mHasJob.notify_all();
|
||||
if (mAdvanceSimulation)
|
||||
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);
|
||||
mBudget.reset(mDefaultPhysicsDt);
|
||||
mAsyncBudget.reset(0.0f);
|
||||
mMovedActors.clear();
|
||||
mActorsFrameData.clear();
|
||||
for (const auto& [_, actor] : actors)
|
||||
{
|
||||
actor->updatePosition();
|
||||
actor->updateCollisionObjectPosition();
|
||||
mMovedActors.emplace_back(actor->getPtr());
|
||||
}
|
||||
return mMovedActors;
|
||||
}
|
||||
|
||||
void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
|
||||
|
@ -561,7 +554,6 @@ namespace MWPhysics
|
|||
handleFall(actorData, mAdvanceSimulation);
|
||||
actorData.mActorRaw->setSimulationPosition(interpolateMovements(actorData, mTimeAccum, mPhysicsDt));
|
||||
updateMechanics(actorData);
|
||||
mMovedActors.emplace_back(actorData.mActorRaw->getPtr());
|
||||
if (mAdvanceSimulation)
|
||||
actorData.mActorRaw->setStandingOnPtr(actorData.mStandingOn);
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ namespace MWPhysics
|
|||
/// @param timeAccum accumulated time from previous run to interpolate movements
|
||||
/// @param actorsData per actor data needed to compute new positions
|
||||
/// @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
|
||||
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
|
||||
|
@ -72,7 +72,6 @@ namespace MWPhysics
|
|||
|
||||
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
||||
std::vector<ActorFrameData> mActorsFrameData;
|
||||
std::vector<MWWorld::Ptr> mMovedActors;
|
||||
float mDefaultPhysicsDt;
|
||||
float mPhysicsDt;
|
||||
float mTimeAccum;
|
||||
|
|
|
@ -751,17 +751,6 @@ namespace MWPhysics
|
|||
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> actorsFrameData;
|
||||
|
@ -798,20 +787,43 @@ namespace MWPhysics
|
|||
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)
|
||||
{
|
||||
if (animatedObject->animateCollisionShapes())
|
||||
{
|
||||
auto obj = mObjects.find(animatedObject->getPtr());
|
||||
assert(obj != mObjects.end());
|
||||
mTaskScheduler->updateSingleAabb(obj->second);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BT_NO_PROFILE
|
||||
CProfileManager::Reset();
|
||||
CProfileManager::Increment_Frame_Counter();
|
||||
#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)
|
||||
|
|
|
@ -154,7 +154,11 @@ namespace MWPhysics
|
|||
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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.
|
||||
void clearQueuedMovement();
|
||||
|
||||
|
|
|
@ -1508,35 +1508,12 @@ namespace MWWorld
|
|||
|
||||
void World::doPhysics(float duration, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||
{
|
||||
mPhysics->stepSimulation();
|
||||
processDoors(duration);
|
||||
|
||||
mProjectileManager->update(duration);
|
||||
|
||||
const auto& results = mPhysics->applyQueuedMovement(duration, mDiscardMovements, frameStart, frameNumber, stats);
|
||||
mPhysics->stepSimulation(duration, mDiscardMovements, frameStart, frameNumber, stats);
|
||||
mProjectileManager->processHits();
|
||||
mDiscardMovements = false;
|
||||
|
||||
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);
|
||||
}
|
||||
mPhysics->moveActors();
|
||||
}
|
||||
|
||||
void World::updateNavigator()
|
||||
|
|
Loading…
Reference in a new issue