mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
Merge branch 'interleaved_movements' into 'master'
Unbreak lifts & conveyors in Sotha Sil Expanded See merge request OpenMW/openmw!410
This commit is contained in:
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…
x
Reference in New Issue
Block a user