diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index b21a3e3ca8..c1eadc05da 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -30,6 +30,7 @@ namespace MWPhysics setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); const float* pos = ptr.getRefData().getPosition().pos; setOrigin(btVector3(pos[0], pos[1], pos[2])); + commitPositionChange(); } Object::~Object() @@ -45,17 +46,34 @@ namespace MWPhysics void Object::setScale(float scale) { - mShapeInstance->setLocalScaling(btVector3(scale, scale, scale)); + mScale = { scale,scale,scale }; + mScaleUpdatePending = true; } void Object::setRotation(const btQuaternion& quat) { - mCollisionObject->getWorldTransform().setRotation(quat); + mLocalTransform.setRotation(quat); + mTransformUpdatePending = true; } void Object::setOrigin(const btVector3& vec) { - mCollisionObject->getWorldTransform().setOrigin(vec); + mLocalTransform.setOrigin(vec); + mTransformUpdatePending = true; + } + + void Object::commitPositionChange() + { + if (mScaleUpdatePending) + { + mShapeInstance->setLocalScaling(mScale); + mScaleUpdatePending = false; + } + if (mTransformUpdatePending) + { + mCollisionObject->setWorldTransform(mLocalTransform); + mTransformUpdatePending = false; + } } btCollisionObject* Object::getCollisionObject() @@ -68,6 +86,11 @@ namespace MWPhysics return mCollisionObject.get(); } + btTransform Object::getTransform() const + { + return mLocalTransform; + } + bool Object::isSolid() const { return mSolid; @@ -83,10 +106,10 @@ namespace MWPhysics return !mShapeInstance->mAnimatedShapes.empty(); } - void Object::animateCollisionShapes(btCollisionWorld* collisionWorld) + bool Object::animateCollisionShapes() { if (mShapeInstance->mAnimatedShapes.empty()) - return; + return false; assert (mShapeInstance->getCollisionShape()->isCompound()); @@ -107,7 +130,7 @@ namespace MWPhysics // Remove nonexistent nodes from animated shapes map and early out mShapeInstance->mAnimatedShapes.erase(recIndex); - return; + return false; } osg::NodePath nodePath = visitor.mFoundPath; nodePath.erase(nodePath.begin()); @@ -129,7 +152,6 @@ namespace MWPhysics if (!(transform == compound->getChildTransform(shapeIndex))) compound->updateChildTransform(shapeIndex, transform); } - - collisionWorld->updateSingleAabb(mCollisionObject.get()); + return true; } } diff --git a/apps/openmw/mwphysics/object.hpp b/apps/openmw/mwphysics/object.hpp index 87d1b04330..d1f3dff745 100644 --- a/apps/openmw/mwphysics/object.hpp +++ b/apps/openmw/mwphysics/object.hpp @@ -3,6 +3,7 @@ #include "ptrholder.hpp" +#include #include #include @@ -30,13 +31,17 @@ namespace MWPhysics void setScale(float scale); void setRotation(const btQuaternion& quat); void setOrigin(const btVector3& vec); + void commitPositionChange(); btCollisionObject* getCollisionObject(); const btCollisionObject* getCollisionObject() const; + btTransform getTransform() const; /// Return solid flag. Not used by the object itself, true by default. bool isSolid() const; void setSolid(bool solid); bool isAnimated() const; - void animateCollisionShapes(btCollisionWorld* collisionWorld); + /// @brief update object shape + /// @return true if shape changed + bool animateCollisionShapes(); private: std::unique_ptr mCollisionObject; @@ -44,6 +49,10 @@ namespace MWPhysics std::map mRecIndexToNodePath; bool mSolid; btCollisionWorld* mCollisionWorld; + btVector3 mScale; + btTransform mLocalTransform; + bool mScaleUpdatePending; + bool mTransformUpdatePending; }; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 58d96de285..97be7c39ec 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -768,7 +768,12 @@ namespace MWPhysics void PhysicsSystem::stepSimulation() { for (Object* animatedObject : mAnimatedObjects) - animatedObject->animateCollisionShapes(mCollisionWorld.get()); + if (animatedObject->animateCollisionShapes()) + { + auto obj = mObjects.find(animatedObject->getPtr()); + assert(obj != mObjects.end()); + mCollisionWorld->updateSingleAabb(obj->second->getCollisionObject()); + } #ifndef BT_NO_PROFILE CProfileManager::Reset(); @@ -780,7 +785,8 @@ namespace MWPhysics { ObjectMap::iterator found = mObjects.find(object); if (found != mObjects.end()) - found->second->animateCollisionShapes(mCollisionWorld.get()); + if (found->second->animateCollisionShapes()) + mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); } void PhysicsSystem::debugDraw() diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 64316789fe..6843762260 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -152,7 +152,7 @@ namespace ? btVector3(distanceFromDoor, 0, 0) : btVector3(0, distanceFromDoor, 0); - const auto& transform = object->getCollisionObject()->getWorldTransform(); + const auto transform = object->getTransform(); const btTransform closedDoorTransform( Misc::Convert::toBullet(makeObjectOsgQuat(ptr.getCellRef().getPosition())), transform.getOrigin() @@ -187,7 +187,7 @@ namespace *object->getShapeInstance()->getCollisionShape(), object->getShapeInstance()->getAvoidCollisionShape() }, - object->getCollisionObject()->getWorldTransform() + object->getTransform() ); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e363fdd3b3..273a5f3026 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1537,7 +1537,7 @@ namespace MWWorld *object->getShapeInstance()->getCollisionShape(), object->getShapeInstance()->getAvoidCollisionShape() }; - return mNavigator->updateObject(DetourNavigator::ObjectId(object), shapes, object->getCollisionObject()->getWorldTransform()); + return mNavigator->updateObject(DetourNavigator::ObjectId(object), shapes, object->getTransform()); } const MWPhysics::RayCastingInterface* World::getRayCasting() const @@ -3880,7 +3880,7 @@ namespace MWWorld btVector3 aabbMax; object->getShapeInstance()->getCollisionShape()->getAabb(btTransform::getIdentity(), aabbMin, aabbMax); - const auto toLocal = object->getCollisionObject()->getWorldTransform().inverse(); + const auto toLocal = object->getTransform().inverse(); const auto localFrom = toLocal(Misc::Convert::toBullet(position)); const auto localTo = toLocal(Misc::Convert::toBullet(destination));