mirror of
https://github.com/OpenMW/openmw.git
synced 2025-12-13 22:13:06 +00:00
Use std::variant in the physics simulation for the different types of objects. For now only support only for actors.
This commit is contained in:
parent
e9f065222c
commit
5009b66ef5
8 changed files with 155 additions and 87 deletions
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "collisiontype.hpp"
|
#include "collisiontype.hpp"
|
||||||
#include "mtphysics.hpp"
|
#include "mtphysics.hpp"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
@ -303,4 +304,15 @@ osg::Vec3f Actor::velocity()
|
||||||
return std::exchange(mVelocity, osg::Vec3f());
|
return std::exchange(mVelocity, osg::Vec3f());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Actor::canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const
|
||||||
|
{
|
||||||
|
const float halfZ = getHalfExtents().z();
|
||||||
|
const osg::Vec3f actorPosition = getPosition();
|
||||||
|
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
||||||
|
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
||||||
|
MWPhysics::ActorTracer tracer;
|
||||||
|
tracer.doTrace(getCollisionObject(), startingPosition, destinationPosition, world);
|
||||||
|
return (tracer.mFraction >= 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
class btCollisionShape;
|
class btCollisionShape;
|
||||||
class btCollisionObject;
|
class btCollisionObject;
|
||||||
|
class btCollisionWorld;
|
||||||
class btConvexShape;
|
class btConvexShape;
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
|
|
@ -165,6 +166,8 @@ namespace MWPhysics
|
||||||
void setVelocity(osg::Vec3f velocity);
|
void setVelocity(osg::Vec3f velocity);
|
||||||
osg::Vec3f velocity();
|
osg::Vec3f velocity();
|
||||||
|
|
||||||
|
bool canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MWWorld::Ptr mStandingOnPtr;
|
MWWorld::Ptr mStandingOnPtr;
|
||||||
/// Removes then re-adds the collision object to the dynamics world
|
/// Removes then re-adds the collision object to the dynamics world
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovementSolver::move(ActorFrameData& actor, float time, const btCollisionWorld* collisionWorld,
|
void MovementSolver::move(ActorFrameData& actor, float time, const btCollisionWorld* collisionWorld,
|
||||||
WorldFrameData& worldData)
|
const WorldFrameData& worldData)
|
||||||
{
|
{
|
||||||
// Reset per-frame data
|
// Reset per-frame data
|
||||||
actor.mWalkingOnWater = false;
|
actor.mWalkingOnWater = false;
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight);
|
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, WorldFrameData& worldData);
|
static void move(ActorFrameData& actor, float time, const btCollisionWorld* collisionWorld, const WorldFrameData& worldData);
|
||||||
static void unstuck(ActorFrameData& actor, const btCollisionWorld* collisionWorld);
|
static void unstuck(ActorFrameData& actor, const btCollisionWorld* collisionWorld);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,106 @@ namespace
|
||||||
return actorData.mPosition * interpolationFactor + actor.getPreviousPosition() * (1.f - interpolationFactor);
|
return actorData.mPosition * interpolationFactor + actor.getPreviousPosition() * (1.f - interpolationFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Visitors
|
||||||
|
{
|
||||||
|
struct InitPosition
|
||||||
|
{
|
||||||
|
const btCollisionWorld* mCollisionWorld;
|
||||||
|
void operator()(MWPhysics::ActorSimulation& sim) const
|
||||||
|
{
|
||||||
|
auto& [actor, frameData] = sim;
|
||||||
|
actor->applyOffsetChange();
|
||||||
|
frameData.mPosition = actor->getPosition();
|
||||||
|
if (frameData.mWaterCollision && frameData.mPosition.z() < frameData.mWaterlevel && actor->canMoveToWaterSurface(frameData.mWaterlevel, mCollisionWorld))
|
||||||
|
{
|
||||||
|
frameData.mPosition.z() = frameData.mWaterlevel;
|
||||||
|
MWBase::Environment::get().getWorld()->moveObject(actor->getPtr(), frameData.mPosition, false);
|
||||||
|
}
|
||||||
|
frameData.mOldHeight = frameData.mPosition.z();
|
||||||
|
const auto rotation = actor->getPtr().getRefData().getPosition().asRotationVec3();
|
||||||
|
frameData.mRotation = osg::Vec2f(rotation.x(), rotation.z());
|
||||||
|
frameData.mInertia = actor->getInertialForce();
|
||||||
|
frameData.mStuckFrames = actor->getStuckFrames();
|
||||||
|
frameData.mLastStuckPosition = actor->getLastStuckPosition();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PreStep
|
||||||
|
{
|
||||||
|
btCollisionWorld* mCollisionWorld;
|
||||||
|
void operator()(MWPhysics::ActorSimulation& sim) const
|
||||||
|
{
|
||||||
|
MWPhysics::MovementSolver::unstuck(sim.second, mCollisionWorld);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpdatePosition
|
||||||
|
{
|
||||||
|
btCollisionWorld* mCollisionWorld;
|
||||||
|
void operator()(MWPhysics::ActorSimulation& sim) const
|
||||||
|
{
|
||||||
|
auto& [actor, frameData] = sim;
|
||||||
|
if (actor->setPosition(frameData.mPosition))
|
||||||
|
{
|
||||||
|
frameData.mPosition = actor->getPosition(); // account for potential position change made by script
|
||||||
|
actor->updateCollisionObjectPosition();
|
||||||
|
mCollisionWorld->updateSingleAabb(actor->getCollisionObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Move
|
||||||
|
{
|
||||||
|
const float mPhysicsDt;
|
||||||
|
const btCollisionWorld* mCollisionWorld;
|
||||||
|
const MWPhysics::WorldFrameData& mWorldFrameData;
|
||||||
|
void operator()(MWPhysics::ActorSimulation& sim) const
|
||||||
|
{
|
||||||
|
MWPhysics::MovementSolver::move(sim.second, mPhysicsDt, mCollisionWorld, mWorldFrameData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sync
|
||||||
|
{
|
||||||
|
const bool mAdvanceSimulation;
|
||||||
|
const float mTimeAccum;
|
||||||
|
const float mPhysicsDt;
|
||||||
|
const MWPhysics::PhysicsTaskScheduler* scheduler;
|
||||||
|
void operator()(MWPhysics::ActorSimulation& sim) const
|
||||||
|
{
|
||||||
|
auto& [actor, frameData] = sim;
|
||||||
|
auto ptr = actor->getPtr();
|
||||||
|
|
||||||
|
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
const float heightDiff = frameData.mPosition.z() - frameData.mOldHeight;
|
||||||
|
const bool isStillOnGround = (mAdvanceSimulation && frameData.mWasOnGround && frameData.mIsOnGround);
|
||||||
|
|
||||||
|
if (isStillOnGround || frameData.mFlying || isUnderWater(frameData) || frameData.mSlowFall < 1)
|
||||||
|
stats.land(ptr == MWMechanics::getPlayer() && (frameData.mFlying || isUnderWater(frameData)));
|
||||||
|
else if (heightDiff < 0)
|
||||||
|
stats.addToFallHeight(-heightDiff);
|
||||||
|
|
||||||
|
actor->setSimulationPosition(::interpolateMovements(*actor, frameData, mTimeAccum, mPhysicsDt));
|
||||||
|
actor->setLastStuckPosition(frameData.mLastStuckPosition);
|
||||||
|
actor->setStuckFrames(frameData.mStuckFrames);
|
||||||
|
if (mAdvanceSimulation)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr standingOn;
|
||||||
|
auto* ptrHolder = static_cast<MWPhysics::PtrHolder*>(scheduler->getUserPointer(frameData.mStandingOn));
|
||||||
|
if (ptrHolder)
|
||||||
|
standingOn = ptrHolder->getPtr();
|
||||||
|
actor->setStandingOnPtr(standingOn);
|
||||||
|
// the "on ground" state of an actor might have been updated by a traceDown, don't overwrite the change
|
||||||
|
if (actor->getOnGround() == frameData.mWasOnGround)
|
||||||
|
actor->setOnGround(frameData.mIsOnGround);
|
||||||
|
actor->setOnSlope(frameData.mIsOnSlope);
|
||||||
|
actor->setWalkingOnWater(frameData.mWalkingOnWater);
|
||||||
|
actor->setInertialForce(frameData.mInertia);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
/// @return either the number of thread as configured by the user, or 1 if Bullet doesn't support multithreading and user requested more than 1 background threads
|
/// @return either the number of thread as configured by the user, or 1 if Bullet doesn't support multithreading and user requested more than 1 background threads
|
||||||
|
|
@ -235,13 +335,12 @@ namespace MWPhysics
|
||||||
return std::make_tuple(numSteps, actualDelta);
|
return std::make_tuple(numSteps, actualDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::applyQueuedMovements(float & timeAccum, std::vector<std::shared_ptr<Actor>>&& actors, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
void PhysicsTaskScheduler::applyQueuedMovements(float & timeAccum, std::vector<Simulation>&& simulations, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||||
{
|
{
|
||||||
// This function run in the main thread.
|
// This function run in the main thread.
|
||||||
// While the mSimulationMutex is held, background physics threads can't run.
|
// While the mSimulationMutex is held, background physics threads can't run.
|
||||||
|
|
||||||
MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
|
MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
|
||||||
assert(actors.size() == actorsData.size());
|
|
||||||
|
|
||||||
double timeStart = mTimer->tick();
|
double timeStart = mTimer->tick();
|
||||||
|
|
||||||
|
|
@ -259,19 +358,19 @@ namespace MWPhysics
|
||||||
timeAccum -= numSteps*newDelta;
|
timeAccum -= numSteps*newDelta;
|
||||||
|
|
||||||
// init
|
// init
|
||||||
for (size_t i = 0; i < actors.size(); ++i)
|
const Visitors::InitPosition vis{mCollisionWorld};
|
||||||
|
for (auto& sim : simulations)
|
||||||
{
|
{
|
||||||
actorsData[i].updatePosition(*actors[i], mCollisionWorld);
|
std::visit(vis, sim);
|
||||||
}
|
}
|
||||||
mPrevStepCount = numSteps;
|
mPrevStepCount = numSteps;
|
||||||
mRemainingSteps = numSteps;
|
mRemainingSteps = numSteps;
|
||||||
mTimeAccum = timeAccum;
|
mTimeAccum = timeAccum;
|
||||||
mPhysicsDt = newDelta;
|
mPhysicsDt = newDelta;
|
||||||
mActors = std::move(actors);
|
mSimulations = std::move(simulations);
|
||||||
mActorsFrameData = std::move(actorsData);
|
|
||||||
mAdvanceSimulation = (mRemainingSteps != 0);
|
mAdvanceSimulation = (mRemainingSteps != 0);
|
||||||
mNewFrame = true;
|
mNewFrame = true;
|
||||||
mNumJobs = mActorsFrameData.size();
|
mNumJobs = mSimulations.size();
|
||||||
mNextLOS.store(0, std::memory_order_relaxed);
|
mNextLOS.store(0, std::memory_order_relaxed);
|
||||||
mNextJob.store(0, std::memory_order_release);
|
mNextJob.store(0, std::memory_order_release);
|
||||||
|
|
||||||
|
|
@ -301,8 +400,7 @@ namespace MWPhysics
|
||||||
MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
|
MaybeExclusiveLock lock(mSimulationMutex, mNumThreads);
|
||||||
mBudget.reset(mDefaultPhysicsDt);
|
mBudget.reset(mDefaultPhysicsDt);
|
||||||
mAsyncBudget.reset(0.0f);
|
mAsyncBudget.reset(0.0f);
|
||||||
mActors.clear();
|
mSimulations.clear();
|
||||||
mActorsFrameData.clear();
|
|
||||||
for (const auto& [_, actor] : actors)
|
for (const auto& [_, actor] : actors)
|
||||||
{
|
{
|
||||||
actor->updatePosition();
|
actor->updatePosition();
|
||||||
|
|
@ -467,47 +565,11 @@ namespace MWPhysics
|
||||||
|
|
||||||
void PhysicsTaskScheduler::updateActorsPositions()
|
void PhysicsTaskScheduler::updateActorsPositions()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
const Visitors::UpdatePosition vis{mCollisionWorld};
|
||||||
|
for (auto& sim : mSimulations)
|
||||||
{
|
{
|
||||||
if (mActors[i]->setPosition(mActorsFrameData[i].mPosition))
|
MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
|
||||||
{
|
std::visit(vis, sim);
|
||||||
MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
|
|
||||||
mActorsFrameData[i].mPosition = mActors[i]->getPosition(); // account for potential position change made by script
|
|
||||||
mActors[i]->updateCollisionObjectPosition();
|
|
||||||
mCollisionWorld->updateSingleAabb(mActors[i]->getCollisionObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicsTaskScheduler::updateActor(Actor& actor, ActorFrameData& actorData, bool simulationPerformed, float timeAccum, float dt) const
|
|
||||||
{
|
|
||||||
auto ptr = actor.getPtr();
|
|
||||||
|
|
||||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
|
||||||
const float heightDiff = actorData.mPosition.z() - actorData.mOldHeight;
|
|
||||||
const bool isStillOnGround = (simulationPerformed && actorData.mWasOnGround && actorData.mIsOnGround);
|
|
||||||
|
|
||||||
if (isStillOnGround || actorData.mFlying || isUnderWater(actorData) || actorData.mSlowFall < 1)
|
|
||||||
stats.land(ptr == MWMechanics::getPlayer() && (actorData.mFlying || isUnderWater(actorData)));
|
|
||||||
else if (heightDiff < 0)
|
|
||||||
stats.addToFallHeight(-heightDiff);
|
|
||||||
|
|
||||||
actor.setSimulationPosition(interpolateMovements(actor, actorData, timeAccum, dt));
|
|
||||||
actor.setLastStuckPosition(actorData.mLastStuckPosition);
|
|
||||||
actor.setStuckFrames(actorData.mStuckFrames);
|
|
||||||
if (simulationPerformed)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr standingOn;
|
|
||||||
auto* ptrHolder = static_cast<MWPhysics::PtrHolder*>(getUserPointer(actorData.mStandingOn));
|
|
||||||
if (ptrHolder)
|
|
||||||
standingOn = ptrHolder->getPtr();
|
|
||||||
actor.setStandingOnPtr(standingOn);
|
|
||||||
// the "on ground" state of an actor might have been updated by a traceDown, don't overwrite the change
|
|
||||||
if (actor.getOnGround() == actorData.mWasOnGround)
|
|
||||||
actor.setOnGround(actorData.mIsOnGround);
|
|
||||||
actor.setOnSlope(actorData.mIsOnSlope);
|
|
||||||
actor.setWalkingOnWater(actorData.mWalkingOnWater);
|
|
||||||
actor.setInertialForce(actorData.mInertia);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,10 +594,11 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
mPreStepBarrier->wait([this] { afterPreStep(); });
|
mPreStepBarrier->wait([this] { afterPreStep(); });
|
||||||
int job = 0;
|
int job = 0;
|
||||||
|
const Visitors::Move vis{mPhysicsDt, mCollisionWorld, *mWorldFrameData};
|
||||||
while ((job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
|
while ((job = mNextJob.fetch_add(1, std::memory_order_relaxed)) < mNumJobs)
|
||||||
{
|
{
|
||||||
MaybeLock lockColWorld(mCollisionWorldMutex, mNumThreads);
|
MaybeLock lockColWorld(mCollisionWorldMutex, mNumThreads);
|
||||||
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
|
std::visit(vis, mSimulations[job]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mPostStepBarrier->wait([this] { afterPostStep(); });
|
mPostStepBarrier->wait([this] { afterPostStep(); });
|
||||||
|
|
@ -577,7 +640,7 @@ namespace MWPhysics
|
||||||
void PhysicsTaskScheduler::releaseSharedStates()
|
void PhysicsTaskScheduler::releaseSharedStates()
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mSimulationMutex, mUpdateAabbMutex);
|
std::scoped_lock lock(mSimulationMutex, mUpdateAabbMutex);
|
||||||
mActors.clear();
|
mSimulations.clear();
|
||||||
mUpdateAabb.clear();
|
mUpdateAabb.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -586,10 +649,11 @@ namespace MWPhysics
|
||||||
updateAabbs();
|
updateAabbs();
|
||||||
if (!mRemainingSteps)
|
if (!mRemainingSteps)
|
||||||
return;
|
return;
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
const Visitors::PreStep vis{mCollisionWorld};
|
||||||
|
for (auto& sim : mSimulations)
|
||||||
{
|
{
|
||||||
MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
|
MaybeExclusiveLock lock(mCollisionWorldMutex, mNumThreads);
|
||||||
MovementSolver::unstuck(mActorsFrameData[i], mCollisionWorld);
|
std::visit(vis, sim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -618,7 +682,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
void PhysicsTaskScheduler::syncWithMainThread()
|
void PhysicsTaskScheduler::syncWithMainThread()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mActors.size(); ++i)
|
const Visitors::Sync vis{mAdvanceSimulation, mTimeAccum, mPhysicsDt, this};
|
||||||
updateActor(*mActors[i], mActorsFrameData[i], mAdvanceSimulation, mTimeAccum, mPhysicsDt);
|
for (auto& sim : mSimulations)
|
||||||
|
std::visit(vis, sim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ namespace MWPhysics
|
||||||
/// @param timeAccum accumulated time from previous run to interpolate movements
|
/// @param timeAccum accumulated time from previous run to interpolate movements
|
||||||
/// @param actorsData per actor data needed to compute new positions
|
/// @param actorsData per actor data needed to compute new positions
|
||||||
/// @return new position of each actor
|
/// @return new position of each actor
|
||||||
void applyQueuedMovements(float & timeAccum, std::vector<std::shared_ptr<Actor>>&& actors, std::vector<ActorFrameData>&& actorsData, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
void applyQueuedMovements(float & timeAccum, std::vector<Simulation>&& simulations, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
||||||
|
|
||||||
void resetSimulation(const ActorMap& actors);
|
void resetSimulation(const ActorMap& actors);
|
||||||
|
|
||||||
|
|
@ -57,14 +58,12 @@ namespace MWPhysics
|
||||||
bool getLineOfSight(const std::shared_ptr<Actor>& actor1, const std::shared_ptr<Actor>& actor2);
|
bool getLineOfSight(const std::shared_ptr<Actor>& actor1, const std::shared_ptr<Actor>& actor2);
|
||||||
void debugDraw();
|
void debugDraw();
|
||||||
void* getUserPointer(const btCollisionObject* object) const;
|
void* getUserPointer(const btCollisionObject* object) const;
|
||||||
|
|
||||||
void releaseSharedStates(); // destroy all objects whose destructor can't be safely called from ~PhysicsTaskScheduler()
|
void releaseSharedStates(); // destroy all objects whose destructor can't be safely called from ~PhysicsTaskScheduler()
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void doSimulation();
|
void doSimulation();
|
||||||
void worker();
|
void worker();
|
||||||
void updateActorsPositions();
|
void updateActorsPositions();
|
||||||
void updateActor(Actor& actor, ActorFrameData& actorData, bool simulationPerformed, float timeAccum, float dt) const;
|
|
||||||
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
|
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
|
||||||
void refreshLOSCache();
|
void refreshLOSCache();
|
||||||
void updateAabbs();
|
void updateAabbs();
|
||||||
|
|
@ -77,8 +76,7 @@ namespace MWPhysics
|
||||||
void syncWithMainThread();
|
void syncWithMainThread();
|
||||||
|
|
||||||
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
||||||
std::vector<std::shared_ptr<Actor>> mActors;
|
std::vector<Simulation> mSimulations;
|
||||||
std::vector<ActorFrameData> mActorsFrameData;
|
|
||||||
std::unordered_set<const btCollisionObject*> mCollisionObjects;
|
std::unordered_set<const btCollisionObject*> mCollisionObjects;
|
||||||
float mDefaultPhysicsDt;
|
float mDefaultPhysicsDt;
|
||||||
float mPhysicsDt;
|
float mPhysicsDt;
|
||||||
|
|
|
||||||
|
|
@ -60,19 +60,6 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool canMoveToWaterSurface(const MWPhysics::Actor* physicActor, const float waterlevel, btCollisionWorld* world)
|
|
||||||
{
|
|
||||||
if (!physicActor)
|
|
||||||
return false;
|
|
||||||
const float halfZ = physicActor->getHalfExtents().z();
|
|
||||||
const osg::Vec3f actorPosition = physicActor->getPosition();
|
|
||||||
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
|
||||||
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
|
||||||
MWPhysics::ActorTracer tracer;
|
|
||||||
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, world);
|
|
||||||
return (tracer.mFraction >= 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleJump(const MWWorld::Ptr &ptr)
|
void handleJump(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
if (!ptr.getClass().isActor())
|
if (!ptr.getClass().isActor())
|
||||||
|
|
@ -386,7 +373,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||||
{
|
{
|
||||||
return ::canMoveToWaterSurface(getActor(actor), waterlevel, mCollisionWorld.get());
|
const auto* physactor = getActor(actor);
|
||||||
|
return physactor && physactor->canMoveToWaterSurface(waterlevel, mCollisionWorld.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
||||||
|
|
@ -727,11 +715,10 @@ namespace MWPhysics
|
||||||
actor->setVelocity(osg::Vec3f());
|
actor->setVelocity(osg::Vec3f());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::vector<std::shared_ptr<Actor>>, std::vector<ActorFrameData>> PhysicsSystem::prepareFrameData(bool willSimulate)
|
std::vector<Simulation> PhysicsSystem::prepareSimulation(bool willSimulate)
|
||||||
{
|
{
|
||||||
std::pair<std::vector<std::shared_ptr<Actor>>, std::vector<ActorFrameData>> framedata;
|
std::vector<Simulation> simulations;
|
||||||
framedata.first.reserve(mActors.size());
|
simulations.reserve(mActors.size());
|
||||||
framedata.second.reserve(mActors.size());
|
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
for (const auto& [ref, physicActor] : mActors)
|
for (const auto& [ref, physicActor] : mActors)
|
||||||
{
|
{
|
||||||
|
|
@ -760,14 +747,13 @@ namespace MWPhysics
|
||||||
const bool godmode = ptr == world->getPlayerConstPtr() && world->getGodModeState();
|
const bool godmode = ptr == world->getPlayerConstPtr() && world->getGodModeState();
|
||||||
const bool inert = stats.isDead() || (!godmode && stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0);
|
const bool inert = stats.isDead() || (!godmode && stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0);
|
||||||
|
|
||||||
framedata.first.emplace_back(physicActor);
|
simulations.emplace_back(ActorSimulation{physicActor, ActorFrameData{*physicActor, inert, waterCollision, slowFall, waterlevel}});
|
||||||
framedata.second.emplace_back(*physicActor, inert, waterCollision, slowFall, waterlevel);
|
|
||||||
|
|
||||||
// if the simulation will run, a jump request will be fulfilled. Update mechanics accordingly.
|
// if the simulation will run, a jump request will be fulfilled. Update mechanics accordingly.
|
||||||
if (willSimulate)
|
if (willSimulate)
|
||||||
handleJump(ptr);
|
handleJump(ptr);
|
||||||
}
|
}
|
||||||
return framedata;
|
return simulations;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::stepSimulation(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
void PhysicsSystem::stepSimulation(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||||
|
|
@ -793,9 +779,9 @@ namespace MWPhysics
|
||||||
mTaskScheduler->resetSimulation(mActors);
|
mTaskScheduler->resetSimulation(mActors);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto [actors, framedata] = prepareFrameData(mTimeAccum >= mPhysicsDt);
|
auto simulations = prepareSimulation(mTimeAccum >= mPhysicsDt);
|
||||||
// modifies mTimeAccum
|
// modifies mTimeAccum
|
||||||
mTaskScheduler->applyQueuedMovements(mTimeAccum, std::move(actors), std::move(framedata), frameStart, frameNumber, stats);
|
mTaskScheduler->applyQueuedMovements(mTimeAccum, std::move(simulations), frameStart, frameNumber, stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,7 +968,7 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
actor.applyOffsetChange();
|
actor.applyOffsetChange();
|
||||||
mPosition = actor.getPosition();
|
mPosition = actor.getPosition();
|
||||||
if (mWaterCollision && mPosition.z() < mWaterlevel && canMoveToWaterSurface(&actor, mWaterlevel, world))
|
if (mWaterCollision && mPosition.z() < mWaterlevel && actor.canMoveToWaterSurface(mWaterlevel, world))
|
||||||
{
|
{
|
||||||
mPosition.z() = mWaterlevel;
|
mPosition.z() = mWaterlevel;
|
||||||
MWBase::Environment::get().getWorld()->moveObject(actor.getPtr(), mPosition, false);
|
MWBase::Environment::get().getWorld()->moveObject(actor.getPtr(), mPosition, false);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include <osg/Quat>
|
#include <osg/Quat>
|
||||||
#include <osg/BoundingBox>
|
#include <osg/BoundingBox>
|
||||||
|
|
@ -107,6 +108,9 @@ namespace MWPhysics
|
||||||
osg::Vec3f mStormDirection;
|
osg::Vec3f mStormDirection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ActorSimulation = std::pair<std::shared_ptr<Actor>, ActorFrameData>;
|
||||||
|
using Simulation = std::variant<ActorSimulation>;
|
||||||
|
|
||||||
class PhysicsSystem : public RayCastingInterface
|
class PhysicsSystem : public RayCastingInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -253,7 +257,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
void updateWater();
|
void updateWater();
|
||||||
|
|
||||||
std::pair<std::vector<std::shared_ptr<Actor>>, std::vector<ActorFrameData>> prepareFrameData(bool willSimulate);
|
std::vector<Simulation> prepareSimulation(bool willSimulate);
|
||||||
|
|
||||||
std::unique_ptr<btBroadphaseInterface> mBroadphase;
|
std::unique_ptr<btBroadphaseInterface> mBroadphase;
|
||||||
std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration;
|
std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue