Move Projectile simulation to the background thread.

pull/3207/head
fredzio 3 years ago
parent a245981e4e
commit 3750eb9cd8

@ -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…
Cancel
Save