diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index bbec4d4456..06abe72403 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -190,6 +190,17 @@ void Actor::adjustPosition(const osg::Vec3f& offset) mPositionOffset += offset; } +void Actor::applyOffsetChange() +{ + if (mPositionOffset.length() == 0) + return; + mWorldPosition += mPositionOffset; + mPosition += mPositionOffset; + mPreviousPosition += mPositionOffset; + mPositionOffset = osg::Vec3f(); + mWorldPositionChanged = true; +} + osg::Vec3f Actor::getPosition() const { return mPosition; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 9d129f2ba6..031125f40d 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -96,9 +96,16 @@ namespace MWPhysics * Returns true if the new position is different. */ bool setPosition(const osg::Vec3f& position); + + // force set actor position to be as in Ptr::RefData void updatePosition(); + + // register a position offset that will be applied during simulation. void adjustPosition(const osg::Vec3f& offset); + // apply position offset. Can't be called during simulation + void applyOffsetChange(); + osg::Vec3f getPosition() const; osg::Vec3f getPreviousPosition() const; diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 754bb60afe..2b0db5b82c 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -492,6 +492,7 @@ namespace MWPhysics if (actor->setPosition(actorData.mPosition)) { std::scoped_lock lock(mCollisionWorldMutex); + actorData.mPosition = actor->getPosition(); // account for potential position change made by script actor->updateCollisionObjectPosition(); mCollisionWorld->updateSingleAabb(actor->getCollisionObject()); } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index b2decde2f0..dc9ab629a1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -961,6 +961,10 @@ namespace MWPhysics void ActorFrameData::updatePosition() { mActorRaw->updateWorldPosition(); + // If physics runs "fast enough", position are interpolated without simulation + // By calling this here, we are sure that offsets are applied at least once per frame, + // regardless of simulation speed. + mActorRaw->applyOffsetChange(); mPosition = mActorRaw->getPosition(); if (mMoveToWaterSurface) {