Merge branch 'interleaved_movements' into 'master'

Unbreak lifts & conveyors in Sotha Sil Expanded

See merge request OpenMW/openmw!410
pull/593/head
psi29a 4 years ago
commit 5362146d24

@ -75,9 +75,10 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
updateRotation();
updateScale();
updatePosition();
setPosition(mWorldPosition, true);
addCollisionMask(getCollisionMask());
commitPositionChange();
updateCollisionObjectPosition();
}
Actor::~Actor()
@ -122,88 +123,77 @@ int Actor::getCollisionMask() const
void Actor::updatePosition()
{
std::unique_lock<std::mutex> lock(mPositionMutex);
osg::Vec3f position = mPtr.getRefData().getPosition().asVec3();
std::scoped_lock lock(mPositionMutex);
mWorldPosition = mPtr.getRefData().getPosition().asVec3();
}
mPosition = position;
mPreviousPosition = position;
osg::Vec3f Actor::getWorldPosition() const
{
std::scoped_lock lock(mPositionMutex);
return mWorldPosition;
}
mTransformUpdatePending = true;
updateCollisionObjectPosition();
void Actor::setNextPosition(const osg::Vec3f& position)
{
mNextPosition = position;
}
osg::Vec3f Actor::getNextPosition() const
{
return mNextPosition;
}
void Actor::updateCollisionObjectPosition()
{
std::scoped_lock lock(mPositionMutex);
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale);
osg::Vec3f newPosition = scaledTranslation + mPosition;
mLocalTransform.setOrigin(Misc::Convert::toBullet(newPosition));
mLocalTransform.setRotation(Misc::Convert::toBullet(mRotation));
}
void Actor::commitPositionChange()
{
std::unique_lock<std::mutex> lock(mPositionMutex);
if (mScaleUpdatePending)
{
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
mScaleUpdatePending = false;
}
if (mTransformUpdatePending)
{
mCollisionObject->setWorldTransform(mLocalTransform);
mTransformUpdatePending = false;
}
mCollisionObject->setWorldTransform(mLocalTransform);
}
osg::Vec3f Actor::getCollisionObjectPosition() const
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
return Misc::Convert::toOsg(mLocalTransform.getOrigin());
}
void Actor::setPosition(const osg::Vec3f &position, bool updateCollisionObject)
void Actor::setPosition(const osg::Vec3f& position, bool reset)
{
std::unique_lock<std::mutex> lock(mPositionMutex);
if (mTransformUpdatePending)
if (reset)
{
mCollisionObject->setWorldTransform(mLocalTransform);
mTransformUpdatePending = false;
mPreviousPosition = position;
mNextPosition = position;
}
else
{
mPreviousPosition = mPosition;
mPosition = position;
}
mPosition = position;
if (updateCollisionObject)
{
updateCollisionObjectPosition();
mCollisionObject->setWorldTransform(mLocalTransform);
}
}
void Actor::adjustPosition(const osg::Vec3f& offset)
{
mPosition += offset;
mPreviousPosition += offset;
}
osg::Vec3f Actor::getPosition() const
{
std::unique_lock<std::mutex> lock(mPositionMutex);
return mPosition;
}
osg::Vec3f Actor::getPreviousPosition() const
{
std::unique_lock<std::mutex> lock(mPositionMutex);
return mPreviousPosition;
}
void Actor::updateRotation ()
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
if (mRotation == mPtr.getRefData().getBaseNode()->getAttitude())
return;
mRotation = mPtr.getRefData().getBaseNode()->getAttitude();
mTransformUpdatePending = true;
updateCollisionObjectPosition();
}
bool Actor::isRotationallyInvariant() const
@ -213,37 +203,33 @@ bool Actor::isRotationallyInvariant() const
void Actor::updateScale()
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
float scale = mPtr.getCellRef().getScale();
osg::Vec3f scaleVec(scale,scale,scale);
mPtr.getClass().adjustScale(mPtr, scaleVec, false);
mScale = scaleVec;
mScaleUpdatePending = true;
scaleVec = osg::Vec3f(scale,scale,scale);
mPtr.getClass().adjustScale(mPtr, scaleVec, true);
mRenderingScale = scaleVec;
mTransformUpdatePending = true;
updateCollisionObjectPosition();
}
osg::Vec3f Actor::getHalfExtents() const
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
return osg::componentMultiply(mHalfExtents, mScale);
}
osg::Vec3f Actor::getOriginalHalfExtents() const
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
return mHalfExtents;
}
osg::Vec3f Actor::getRenderingHalfExtents() const
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
return osg::componentMultiply(mHalfExtents, mRenderingScale);
}
@ -274,7 +260,7 @@ void Actor::setWalkingOnWater(bool walkingOnWater)
void Actor::setCanWaterWalk(bool waterWalk)
{
std::unique_lock<std::mutex> lock(mPositionMutex);
std::scoped_lock lock(mPositionMutex);
if (waterWalk != mCanWaterWalk)
{
mCanWaterWalk = waterWalk;

@ -57,13 +57,20 @@ namespace MWPhysics
bool isRotationallyInvariant() const;
/**
* Set mPosition and mPreviousPosition to the position in the Ptr's RefData. This should be used
* Set mWorldPosition to the position in the Ptr's RefData. This is used by the physics simulation to account for
* when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation.
*/
void updatePosition();
osg::Vec3f getWorldPosition() const;
/**
* Used by the physics simulation to store the simulation result. Used in conjunction with mWorldPosition
* to account for e.g. scripted movements
*/
void setNextPosition(const osg::Vec3f& position);
osg::Vec3f getNextPosition() const;
void updateCollisionObjectPosition();
void commitPositionChange();
/**
* Returns the half extents of the collision body (scaled according to collision scale)
@ -83,9 +90,9 @@ namespace MWPhysics
/**
* Store the current position into mPreviousPosition, then move to this position.
* Optionally, inform the physics engine about the change of position.
*/
void setPosition(const osg::Vec3f& position, bool updateCollisionObject=true);
void setPosition(const osg::Vec3f& position, bool reset=false);
void adjustPosition(const osg::Vec3f& offset);
osg::Vec3f getPosition() const;
@ -159,11 +166,11 @@ namespace MWPhysics
osg::Vec3f mScale;
osg::Vec3f mRenderingScale;
osg::Vec3f mWorldPosition;
osg::Vec3f mNextPosition;
osg::Vec3f mPosition;
osg::Vec3f mPreviousPosition;
btTransform mLocalTransform;
bool mScaleUpdatePending;
bool mTransformUpdatePending;
mutable std::mutex mPositionMutex;
osg::Vec3f mForce;

@ -102,9 +102,18 @@ namespace
stats.addToFallHeight(-actorData.mFallHeight);
}
osg::Vec3f interpolateMovements(const MWPhysics::ActorFrameData& actorData, float timeAccum, float physicsDt)
osg::Vec3f interpolateMovements(MWPhysics::ActorFrameData& actorData, float timeAccum, float physicsDt)
{
const float interpolationFactor = timeAccum / physicsDt;
// account for force change of actor's position in the main thread
const auto correction = actorData.mActorRaw->getWorldPosition() - actorData.mOrigin;
if (correction.length() != 0)
{
actorData.mActorRaw->adjustPosition(correction);
actorData.mPosition = actorData.mActorRaw->getPosition();
}
return actorData.mPosition * interpolationFactor + actorData.mActorRaw->getPreviousPosition() * (1.f - interpolationFactor);
}
@ -182,7 +191,6 @@ namespace MWPhysics
mPostSimBarrier = std::make_unique<Misc::Barrier>(mNumThreads, [&]()
{
udpateActorsAabbs();
mNewFrame = false;
if (mLOSCacheExpiry >= 0)
{
@ -229,6 +237,9 @@ namespace MWPhysics
updateMechanics(data);
if (mAdvanceSimulation)
updateStandingCollision(data, standingCollisions);
if (mMovementResults.find(data.mPtr) != mMovementResults.end())
data.mActorRaw->setNextPosition(mMovementResults[data.mPtr]);
}
}
@ -245,10 +256,6 @@ namespace MWPhysics
if (mAdvanceSimulation)
mWorldFrameData = std::make_unique<WorldFrameData>();
// update each actor position based on latest data
for (auto& data : mActorsFrameData)
data.updatePosition();
// we are asked to skip the simulation (load a savegame for instance)
// just return the actors' reference position without applying the movements
if (skipSimulation)
@ -256,7 +263,10 @@ namespace MWPhysics
standingCollisions.clear();
mMovementResults.clear();
for (const auto& m : mActorsFrameData)
mMovementResults[m.mPtr] = m.mPosition;
{
m.mActorRaw->setPosition(m.mActorRaw->getWorldPosition(), true);
mMovementResults[m.mPtr] = m.mActorRaw->getWorldPosition();
}
return mMovementResults;
}
@ -271,6 +281,11 @@ namespace MWPhysics
for (auto& data : mActorsFrameData)
updateStandingCollision(data, standingCollisions);
}
for (auto& data : mActorsFrameData)
{
if (mMovementResults.find(data.mPtr) != mMovementResults.end())
data.mActorRaw->setNextPosition(mMovementResults[data.mPtr]);
}
return mMovementResults;
}
@ -427,7 +442,7 @@ namespace MWPhysics
{
if (const auto actor = std::dynamic_pointer_cast<Actor>(p))
{
actor->commitPositionChange();
actor->updateCollisionObjectPosition();
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
}
else if (const auto object = std::dynamic_pointer_cast<Object>(p))
@ -485,28 +500,17 @@ namespace MWPhysics
{
if(const auto actor = actorData.mActor.lock())
{
if (actorData.mPosition == actor->getPosition())
actor->setPosition(actorData.mPosition, false); // update previous position to make sure interpolation is correct
else
bool positionChanged = actorData.mPosition != actorData.mActorRaw->getPosition();
actorData.mActorRaw->setPosition(actorData.mPosition);
if (positionChanged)
{
actorData.mPositionChanged = true;
actor->setPosition(actorData.mPosition);
actor->updateCollisionObjectPosition();
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
}
}
}
}
void PhysicsTaskScheduler::udpateActorsAabbs()
{
std::unique_lock lock(mCollisionWorldMutex);
for (const auto& actorData : mActorsFrameData)
if (actorData.mPositionChanged)
{
if(const auto actor = actorData.mActor.lock())
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
}
}
bool PhysicsTaskScheduler::hasLineOfSight(const Actor* actor1, const Actor* actor2)
{
btVector3 pos1 = Misc::Convert::toBullet(actor1->getCollisionObjectPosition() + osg::Vec3f(0,0,actor1->getHalfExtents().z() * 0.9)); // eye level
@ -538,6 +542,5 @@ namespace MWPhysics
mMovementResults[actorData.mPtr] = interpolateMovements(actorData, mTimeAccum, mPhysicsDt);
updateMechanics(actorData);
}
udpateActorsAabbs();
}
}

@ -49,7 +49,6 @@ namespace MWPhysics
void syncComputation();
void worker();
void updateActorsPositions();
void udpateActorsAabbs();
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
void refreshLOSCache();
void updateAabbs();

@ -883,7 +883,7 @@ namespace MWPhysics
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn,
bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel)
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
mPositionChanged(false), mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface),
mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface),
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos()
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
@ -893,10 +893,9 @@ namespace MWPhysics
mWantJump = mPtr.getClass().getMovementSettings(mPtr).mPosition[2] != 0;
mIsDead = mPtr.getClass().getCreatureStats(mPtr).isDead();
mWasOnGround = actor->getOnGround();
}
void ActorFrameData::updatePosition()
{
mActorRaw->updatePosition();
mOrigin = mActorRaw->getNextPosition();
mPosition = mActorRaw->getPosition();
if (mMoveToWaterSurface)
{

@ -78,14 +78,12 @@ namespace MWPhysics
struct ActorFrameData
{
ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel);
void updatePosition();
std::weak_ptr<Actor> mActor;
Actor* mActorRaw;
MWWorld::Ptr mPtr;
MWWorld::Ptr mStandingOn;
bool mFlying;
bool mSwimming;
bool mPositionChanged;
bool mWasOnGround;
bool mWantJump;
bool mDidJump;
@ -97,6 +95,7 @@ namespace MWPhysics
float mOldHeight;
float mFallHeight;
osg::Vec3f mMovement;
osg::Vec3f mOrigin;
osg::Vec3f mPosition;
ESM::Position mRefpos;
};

@ -32,7 +32,11 @@ namespace MWScript
std::vector<MWWorld::Ptr> actors;
MWBase::Environment::get().getWorld()->getActorsStandingOn (ptr, actors);
for (auto& actor : actors)
MWBase::Environment::get().getWorld()->queueMovement(actor, diff);
{
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
actorPos += diff;
MWBase::Environment::get().getWorld()->moveObject(actor, actorPos.x(), actorPos.y(), actorPos.z());
}
}
template<class R>

@ -1504,11 +1504,11 @@ namespace MWWorld
const auto results = mPhysics->applyQueuedMovement(duration, mDiscardMovements);
mDiscardMovements = false;
for(const auto& result : results)
for(const auto& [actor, position]: results)
{
// Handle player last, in case a cell transition occurs
if(result.first != getPlayerPtr())
moveObjectImp(result.first, result.second.x(), result.second.y(), result.second.z(), false);
if(actor != getPlayerPtr())
moveObjectImp(actor, position.x(), position.y(), position.z(), false);
}
const auto player = results.find(getPlayerPtr());

Loading…
Cancel
Save