1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-05 06:40:09 +00:00

Merge branch 'simulationresultinactor' into 'master'

Embed physics simulation results inside of actor class.

See merge request OpenMW/openmw!478
This commit is contained in:
psi29a 2020-12-18 12:50:20 +00:00
commit 327df7457b
7 changed files with 74 additions and 76 deletions

View File

@ -76,6 +76,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
updateScale();
resetPosition();
addCollisionMask(getCollisionMask());
updateCollisionObjectPosition();
}
Actor::~Actor()
@ -139,7 +140,9 @@ osg::Vec3f Actor::getWorldPosition() const
void Actor::setSimulationPosition(const osg::Vec3f& position)
{
mSimulationPosition = position;
if (!mResetSimulation)
mSimulationPosition = position;
mResetSimulation = false;
}
osg::Vec3f Actor::getSimulationPosition() const
@ -193,9 +196,9 @@ void Actor::resetPosition()
mPreviousPosition = mWorldPosition;
mPosition = mWorldPosition;
mSimulationPosition = mWorldPosition;
updateCollisionObjectPositionUnsafe();
mStandingOnPtr = nullptr;
mWorldPositionChanged = false;
mResetSimulation = true;
}
osg::Vec3f Actor::getPosition() const

View File

@ -180,6 +180,7 @@ namespace MWPhysics
osg::Vec3f mPreviousPosition;
osg::Vec3f mPositionOffset;
bool mWorldPositionChanged;
bool mResetSimulation;
btTransform mLocalTransform;
mutable std::mutex mPositionMutex;

View File

@ -204,31 +204,31 @@ namespace MWPhysics
thread.join();
}
const PtrPositionList& PhysicsTaskScheduler::moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
const std::vector<MWWorld::Ptr>& PhysicsTaskScheduler::moveActors(int numSteps, 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.
std::unique_lock lock(mSimulationMutex);
for (auto& data : actorsData)
data.updatePosition();
mMovedActors.clear();
// start by finishing previous background computation
if (mNumThreads != 0)
{
for (auto& data : mActorsFrameData)
{
// Ignore actors that were deleted while the background thread was running
if (!data.mActor.lock())
continue;
// Only return actors that are still part of the scene
if (std::any_of(actorsData.begin(), actorsData.end(), [&data](const auto& newFrameData) { return data.mActorRaw->getPtr() == newFrameData.mActorRaw->getPtr(); }))
{
updateMechanics(data);
updateMechanics(data);
if (mAdvanceSimulation)
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
if (mMovementResults.find(data.mPtr) != mMovementResults.end())
data.mActorRaw->setSimulationPosition(mMovementResults[data.mPtr]);
// these variables are accessed directly from the main thread, update them here to prevent accessing "too new" values
if (mAdvanceSimulation)
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
data.mActorRaw->setSimulationPosition(interpolateMovements(data, mTimeAccum, mPhysicsDt));
mMovedActors.emplace_back(data.mActorRaw->getPtr());
}
}
if (mFrameNumber == frameNumber - 1)
@ -243,6 +243,8 @@ namespace MWPhysics
}
// init
for (auto& data : actorsData)
data.updatePosition();
mRemainingSteps = numSteps;
mTimeAccum = timeAccum;
mActorsFrameData = std::move(actorsData);
@ -257,52 +259,28 @@ namespace MWPhysics
if (mNumThreads == 0)
{
mMovementResults.clear();
syncComputation();
for (auto& data : mActorsFrameData)
{
if (mAdvanceSimulation)
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
if (mMovementResults.find(data.mPtr) != mMovementResults.end())
data.mActorRaw->setSimulationPosition(mMovementResults[data.mPtr]);
}
return mMovementResults;
return mMovedActors;
}
// Remove actors that were deleted while the background thread was running
for (auto& data : mActorsFrameData)
{
if (!data.mActor.lock())
mMovementResults.erase(data.mPtr);
}
std::swap(mMovementResults, mPreviousMovementResults);
// mMovementResults is shared between all workers instance
// pre-allocate all nodes so that we don't need synchronization
mMovementResults.clear();
for (const auto& m : mActorsFrameData)
mMovementResults[m.mPtr] = m.mPosition;
lock.unlock();
mHasJob.notify_all();
return mPreviousMovementResults;
return mMovedActors;
}
const PtrPositionList& PhysicsTaskScheduler::resetSimulation(const ActorMap& actors)
const std::vector<MWWorld::Ptr>& PhysicsTaskScheduler::resetSimulation(const ActorMap& actors)
{
std::unique_lock lock(mSimulationMutex);
mMovementResults.clear();
mPreviousMovementResults.clear();
mMovedActors.clear();
mActorsFrameData.clear();
for (const auto& [_, actor] : actors)
{
actor->resetPosition();
actor->setStandingOnPtr(nullptr);
mMovementResults[actor->getPtr()] = actor->getWorldPosition();
actor->setSimulationPosition(actor->getWorldPosition()); // resetPosition skip next simulation, now we need to "consume" it
actor->updateCollisionObjectPosition();
mMovedActors.emplace_back(actor->getPtr());
}
return mMovementResults;
return mMovedActors;
}
void PhysicsTaskScheduler::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
@ -370,18 +348,18 @@ namespace MWPhysics
mCollisionWorld->removeCollisionObject(collisionObject);
}
void PhysicsTaskScheduler::updateSingleAabb(std::weak_ptr<PtrHolder> ptr)
void PhysicsTaskScheduler::updateSingleAabb(std::weak_ptr<PtrHolder> ptr, bool immediate)
{
if (mDeferAabbUpdate)
{
std::unique_lock lock(mUpdateAabbMutex);
mUpdateAabb.insert(std::move(ptr));
}
else
if (!mDeferAabbUpdate || immediate)
{
std::unique_lock lock(mCollisionWorldMutex);
updatePtrAabb(ptr);
}
else
{
std::unique_lock lock(mUpdateAabbMutex);
mUpdateAabb.insert(std::move(ptr));
}
}
bool PhysicsTaskScheduler::getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2)
@ -484,7 +462,6 @@ namespace MWPhysics
{
auto& actorData = mActorsFrameData[job];
handleFall(actorData, mAdvanceSimulation);
mMovementResults[actorData.mPtr] = interpolateMovements(actorData, mTimeAccum, mPhysicsDt);
}
}
@ -539,8 +516,11 @@ namespace MWPhysics
for (auto& actorData : mActorsFrameData)
{
handleFall(actorData, mAdvanceSimulation);
mMovementResults[actorData.mPtr] = interpolateMovements(actorData, mTimeAccum, mPhysicsDt);
actorData.mActorRaw->setSimulationPosition(interpolateMovements(actorData, mTimeAccum, mPhysicsDt));
updateMechanics(actorData);
mMovedActors.emplace_back(actorData.mActorRaw->getPtr());
if (mAdvanceSimulation)
actorData.mActorRaw->setStandingOnPtr(actorData.mStandingOn);
}
}
}

View File

@ -32,9 +32,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 PtrPositionList& moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
const std::vector<MWWorld::Ptr>& moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
const PtrPositionList& resetSimulation(const ActorMap& actors);
const std::vector<MWWorld::Ptr>& resetSimulation(const ActorMap& actors);
// Thread safe wrappers
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
@ -46,7 +46,7 @@ namespace MWPhysics
void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask);
void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask);
void removeCollisionObject(btCollisionObject* collisionObject);
void updateSingleAabb(std::weak_ptr<PtrHolder> ptr);
void updateSingleAabb(std::weak_ptr<PtrHolder> ptr, bool immediate=false);
bool getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2);
private:
@ -60,8 +60,7 @@ namespace MWPhysics
std::unique_ptr<WorldFrameData> mWorldFrameData;
std::vector<ActorFrameData> mActorsFrameData;
PtrPositionList mMovementResults;
PtrPositionList mPreviousMovementResults;
std::vector<MWWorld::Ptr> mMovedActors;
const float mPhysicsDt;
float mTimeAccum;
std::shared_ptr<btCollisionWorld> mCollisionWorld;

View File

@ -437,7 +437,7 @@ namespace MWPhysics
ActorMap::iterator found = mActors.find(ptr);
if (found == mActors.end())
return ptr.getRefData().getPosition().asVec3();
found->second->resetPosition();
resetPosition(ptr);
return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight);
}
@ -647,6 +647,17 @@ namespace MWPhysics
}
}
void PhysicsSystem::resetPosition(const MWWorld::ConstPtr &ptr)
{
ActorMap::iterator foundActor = mActors.find(ptr);
if (foundActor != mActors.end())
{
foundActor->second->resetPosition();
mTaskScheduler->updateSingleAabb(foundActor->second, true);
return;
}
}
void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh)
{
osg::ref_ptr<const Resource::BulletShape> shape = mShapeManager->getShape(mesh);
@ -683,6 +694,8 @@ namespace MWPhysics
if (found != mActors.end())
{
bool cmode = found->second->getCollisionMode();
if (cmode)
resetPosition(found->first);
cmode = !cmode;
found->second->enableCollisionMode(cmode);
// NB: Collision body isn't disabled for vanilla TCL compatibility
@ -711,7 +724,7 @@ namespace MWPhysics
mMovementQueue.clear();
}
const PtrPositionList& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
const std::vector<MWWorld::Ptr>& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
{
mTimeAccum += dt;
@ -930,7 +943,6 @@ namespace MWPhysics
void ActorFrameData::updatePosition()
{
mActorRaw->updatePosition();
mOrigin = mActorRaw->getSimulationPosition();
mPosition = mActorRaw->getPosition();
if (mMoveToWaterSurface)
{

View File

@ -50,8 +50,6 @@ class btVector3;
namespace MWPhysics
{
using PtrPositionList = std::map<MWWorld::Ptr, osg::Vec3f>;
class HeightField;
class Object;
class Actor;
@ -99,7 +97,6 @@ namespace MWPhysics
float mOldHeight;
float mFallHeight;
osg::Vec3f mMovement;
osg::Vec3f mOrigin;
osg::Vec3f mPosition;
ESM::Position mRefpos;
};
@ -147,6 +144,7 @@ namespace MWPhysics
void updateScale (const MWWorld::Ptr& ptr);
void updateRotation (const MWWorld::Ptr& ptr);
void updatePosition (const MWWorld::Ptr& ptr);
void resetPosition(const MWWorld::ConstPtr &ptr);
void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject);
@ -210,7 +208,7 @@ namespace MWPhysics
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
/// Apply all queued movements, then clear the list.
const PtrPositionList& applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
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();

View File

@ -1356,12 +1356,7 @@ namespace MWWorld
}
moveObject(ptr, ptr.getCell(), pos.x(), pos.y(), pos.z());
if (ptr.getClass().isActor())
{
MWPhysics::Actor* actor = mPhysics->getActor(ptr);
if (actor)
actor->resetPosition();
}
mPhysics->resetPosition(ptr);
}
void World::fixPosition()
@ -1512,16 +1507,26 @@ namespace MWWorld
mProjectileManager->processHits();
mDiscardMovements = false;
for(const auto& [actor, position]: results)
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();
moveObjectImp(actor, position.x(), position.y(), position.z(), false);
}
}
const auto player = results.find(getPlayerPtr());
const auto player = std::find(results.begin(), results.end(), getPlayerPtr());
if (player != results.end())
moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false);
{
auto* physactor = mPhysics->getActor(*player);
assert(physactor);
const auto position = physactor->getSimulationPosition();
moveObjectImp(*player, position.x(), position.y(), position.z(), false);
}
}
void World::updateNavigator()