From 3750eb9cd85ca3cbaaa150bda8159d653833bf1d Mon Sep 17 00:00:00 2001 From: fredzio Date: Sat, 9 Oct 2021 18:16:29 +0200 Subject: [PATCH] Move Projectile simulation to the background thread. --- apps/openmw/mwphysics/movementsolver.cpp | 26 ++++++++++++++ apps/openmw/mwphysics/movementsolver.hpp | 2 ++ apps/openmw/mwphysics/mtphysics.cpp | 22 ++++++++++++ apps/openmw/mwphysics/physicssystem.cpp | 44 +++++++++-------------- apps/openmw/mwphysics/physicssystem.hpp | 14 ++++++-- apps/openmw/mwworld/projectilemanager.cpp | 12 +++---- 6 files changed, 82 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index 29810e9085..0585fe91f3 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,8 @@ #include "constants.hpp" #include "contacttestwrapper.h" #include "physicssystem.hpp" +#include "projectile.hpp" +#include "projectileconvexcallback.hpp" #include "stepper.hpp" #include "trace.h" @@ -398,6 +401,29 @@ namespace MWPhysics actor.mPosition.z() -= actor.mHalfExtentsZ; // vanilla-accurate } + void MovementSolver::move(ProjectileFrameData& projectile, float time, const btCollisionWorld* collisionWorld) + { + btVector3 btFrom = Misc::Convert::toBullet(projectile.mPosition); + btVector3 btTo = Misc::Convert::toBullet(projectile.mPosition + projectile.mMovement * time); + + if (btFrom == btTo) + return; + + ProjectileConvexCallback resultCallback(projectile.mCaster, projectile.mCollisionObject, btFrom, btTo, projectile.mProjectile); + resultCallback.m_collisionFilterMask = 0xff; + resultCallback.m_collisionFilterGroup = CollisionType_Projectile; + + const btQuaternion btrot = btQuaternion::getIdentity(); + btTransform from_ (btrot, btFrom); + btTransform to_ (btrot, btTo); + + const btCollisionShape* shape = projectile.mCollisionObject->getCollisionShape(); + assert(shape->isConvex()); + collisionWorld->convexSweepTest(static_cast(shape), from_, to_, resultCallback); + + projectile.mPosition = Misc::Convert::toOsg(projectile.mProjectile->isActive() ? btTo : resultCallback.m_hitPointWorld); + } + btVector3 addMarginToDelta(btVector3 delta) { if(delta.length2() == 0.0) diff --git a/apps/openmw/mwphysics/movementsolver.hpp b/apps/openmw/mwphysics/movementsolver.hpp index 837004f232..1bbe76cbec 100644 --- a/apps/openmw/mwphysics/movementsolver.hpp +++ b/apps/openmw/mwphysics/movementsolver.hpp @@ -37,6 +37,7 @@ namespace MWPhysics class Actor; struct ActorFrameData; + struct ProjectileFrameData; struct WorldFrameData; class MovementSolver @@ -44,6 +45,7 @@ namespace MWPhysics public: static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight); static void move(ActorFrameData& actor, float time, const btCollisionWorld* collisionWorld, const WorldFrameData& worldData); + static void move(ProjectileFrameData& projectile, float time, const btCollisionWorld* collisionWorld); static void unstuck(ActorFrameData& actor, const btCollisionWorld* collisionWorld); }; } diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 525647230f..a989493f4d 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -133,6 +133,9 @@ namespace frameData.mStuckFrames = actor->getStuckFrames(); frameData.mLastStuckPosition = actor->getLastStuckPosition(); } + void operator()(MWPhysics::ProjectileSimulation& sim) const + { + } }; struct PreStep @@ -142,6 +145,9 @@ namespace { MWPhysics::MovementSolver::unstuck(sim.second, mCollisionWorld); } + void operator()(MWPhysics::ProjectileSimulation& sim) const + { + } }; struct UpdatePosition @@ -157,6 +163,13 @@ namespace mCollisionWorld->updateSingleAabb(actor->getCollisionObject()); } } + void operator()(MWPhysics::ProjectileSimulation& sim) const + { + auto& [proj, frameData] = sim; + proj->setPosition(frameData.mPosition); + proj->updateCollisionObjectPosition(); + mCollisionWorld->updateSingleAabb(proj->getCollisionObject()); + } }; struct Move @@ -168,6 +181,10 @@ namespace { MWPhysics::MovementSolver::move(sim.second, mPhysicsDt, mCollisionWorld, mWorldFrameData); } + void operator()(MWPhysics::ProjectileSimulation& sim) const + { + MWPhysics::MovementSolver::move(sim.second, mPhysicsDt, mCollisionWorld); + } }; struct Sync @@ -208,6 +225,11 @@ namespace actor->setInertialForce(frameData.mInertia); } } + void operator()(MWPhysics::ProjectileSimulation& sim) const + { + auto& [proj, frameData] = sim; + proj->setSimulationPosition(::interpolateMovements(*proj, mTimeAccum, mPhysicsDt)); + } }; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f6fc3902e7..786378eb8c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -580,33 +580,6 @@ namespace MWPhysics } } - void PhysicsSystem::updateProjectile(const int projectileId, const osg::Vec3f &position) const - { - const auto foundProjectile = mProjectiles.find(projectileId); - assert(foundProjectile != mProjectiles.end()); - auto* projectile = foundProjectile->second.get(); - - btVector3 btFrom = Misc::Convert::toBullet(projectile->getPosition()); - btVector3 btTo = Misc::Convert::toBullet(position); - - if (btFrom == btTo) - return; - - ProjectileConvexCallback resultCallback(projectile->getCasterCollisionObject(), projectile->getCollisionObject(), btFrom, btTo, projectile); - resultCallback.m_collisionFilterMask = 0xff; - resultCallback.m_collisionFilterGroup = CollisionType_Projectile; - - const btQuaternion btrot = btQuaternion::getIdentity(); - btTransform from_ (btrot, btFrom); - btTransform to_ (btrot, btTo); - - mTaskScheduler->convexSweepTest(projectile->getConvexShape(), from_, to_, resultCallback); - - const auto newpos = projectile->isActive() ? position : Misc::Convert::toOsg(projectile->getHitPosition()); - projectile->setPosition(newpos); - mTaskScheduler->updateSingleAabb(foundProjectile->second); - } - void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr, osg::Quat rotate) { if (auto foundObject = mObjects.find(ptr.mRef); foundObject != mObjects.end()) @@ -718,7 +691,7 @@ namespace MWPhysics std::vector PhysicsSystem::prepareSimulation(bool willSimulate) { std::vector simulations; - simulations.reserve(mActors.size()); + simulations.reserve(mActors.size() + mProjectiles.size()); const MWBase::World *world = MWBase::Environment::get().getWorld(); for (const auto& [ref, physicActor] : mActors) { @@ -753,6 +726,12 @@ namespace MWPhysics if (willSimulate) handleJump(ptr); } + + for (const auto& [id, projectile] : mProjectiles) + { + simulations.emplace_back(ProjectileSimulation{projectile, ProjectileFrameData{*projectile}}); + } + return simulations; } @@ -981,6 +960,15 @@ namespace MWPhysics mLastStuckPosition = actor.getLastStuckPosition(); } + ProjectileFrameData::ProjectileFrameData(Projectile& projectile) + : mPosition(projectile.getPosition()) + , mMovement(projectile.velocity()) + , mCaster(projectile.getCasterCollisionObject()) + , mCollisionObject(projectile.getCollisionObject()) + , mProjectile(&projectile) + { + } + WorldFrameData::WorldFrameData() : mIsInStorm(MWBase::Environment::get().getWorld()->isInStorm()) , mStormDirection(MWBase::Environment::get().getWorld()->getStormDirection()) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index be9fa10aa6..a025f1cc8b 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -101,6 +101,16 @@ namespace MWPhysics const bool mSkipCollisionDetection; }; + struct ProjectileFrameData + { + explicit ProjectileFrameData(Projectile& projectile); + osg::Vec3f mPosition; + osg::Vec3f mMovement; + const btCollisionObject* mCaster; + const btCollisionObject* mCollisionObject; + Projectile* mProjectile; + }; + struct WorldFrameData { WorldFrameData(); @@ -109,7 +119,8 @@ namespace MWPhysics }; using ActorSimulation = std::pair, ActorFrameData>; - using Simulation = std::variant; + using ProjectileSimulation = std::pair, ProjectileFrameData>; + using Simulation = std::variant; class PhysicsSystem : public RayCastingInterface { @@ -128,7 +139,6 @@ namespace MWPhysics int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius); void setCaster(int projectileId, const MWWorld::Ptr& caster); - void updateProjectile(const int projectileId, const osg::Vec3f &position) const; void removeProjectile(const int projectileId); void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 9ee137fab6..ea1d6bde1a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -432,7 +432,7 @@ namespace MWWorld float speed = fTargetSpellMaxSpeed * magicBoltState.mSpeed; osg::Vec3f direction = orient * osg::Vec3f(0,1,0); direction.normalize(); - osg::Vec3f newPos = projectile->getPosition() + direction * duration * speed; + projectile->setVelocity(direction * speed); update(magicBoltState, duration); @@ -441,8 +441,6 @@ namespace MWWorld if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer()) caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors); projectile->setValidTargets(targetActors); - - mPhysics->updateProjectile(magicBoltState.mProjectileId, newPos); } } @@ -460,7 +458,7 @@ namespace MWWorld // simulating aerodynamics at all projectileState.mVelocity -= osg::Vec3f(0, 0, Constants::GravityConst * Constants::UnitsPerMeter * 0.1f) * duration; - osg::Vec3f newPos = projectile->getPosition() + projectileState.mVelocity * duration; + projectile->setVelocity(projectileState.mVelocity); // rotation does not work well for throwing projectiles - their roll angle will depend on shooting direction. if (!projectileState.mThrown) @@ -479,8 +477,6 @@ namespace MWWorld if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer()) caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors); projectile->setValidTargets(targetActors); - - mPhysics->updateProjectile(projectileState.mProjectileId, newPos); } } @@ -493,7 +489,7 @@ namespace MWWorld auto* projectile = mPhysics->getProjectile(projectileState.mProjectileId); - const auto pos = projectile->getPosition(); + const auto pos = projectile->getSimulationPosition(); projectileState.mNode->setPosition(pos); if (projectile->isActive()) @@ -529,7 +525,7 @@ namespace MWWorld auto* projectile = mPhysics->getProjectile(magicBoltState.mProjectileId); - const auto pos = projectile->getPosition(); + const auto pos = projectile->getSimulationPosition(); magicBoltState.mNode->setPosition(pos); for (const auto& sound : magicBoltState.mSounds) sound->setPosition(pos);