mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-01 09:36:40 +00:00
Move Projectile simulation to the background thread.
This commit is contained in:
parent
a245981e4e
commit
3750eb9cd8
6 changed files with 82 additions and 38 deletions
|
@ -3,6 +3,7 @@
|
|||
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btConvexShape.h>
|
||||
|
||||
#include <components/esm/loadgmst.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
|
@ -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<const btConvexShape*>(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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Simulation> PhysicsSystem::prepareSimulation(bool willSimulate)
|
||||
{
|
||||
std::vector<Simulation> 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())
|
||||
|
|
|
@ -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<std::shared_ptr<Actor>, ActorFrameData>;
|
||||
using Simulation = std::variant<ActorSimulation>;
|
||||
using ProjectileSimulation = std::pair<std::shared_ptr<Projectile>, ProjectileFrameData>;
|
||||
using Simulation = std::variant<ActorSimulation, ProjectileSimulation>;
|
||||
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue