1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 21:53:51 +00:00

Refactor stepMove function into a Stepper object

to be able to reuse up stepper results
for successive movement solver iterations.
This can reduce the number of convex casts
almost by half in some cases.
This commit is contained in:
logzero 2016-12-21 10:41:43 +01:00
parent 4f6e65e481
commit 50fd913058

View file

@ -60,30 +60,41 @@ namespace MWPhysics
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
static const int sMaxIterations = 8; static const int sMaxIterations = 8;
// FIXME: move to a separate file static bool isActor(const btCollisionObject *obj)
class MovementSolver {
assert(obj);
return obj->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor;
}
template <class Vec3>
static bool isWalkableSlope(const Vec3 &normal)
{
static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope));
return (normal.z() > sMaxSlopeCos);
}
static bool canStepDown(const ActorTracer &stepper)
{
return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject);
}
class Stepper
{ {
private: private:
static bool isActor(const btCollisionObject *obj) const btCollisionWorld *mColWorld;
{ const btCollisionObject *mColObj;
assert(obj);
return obj->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor;
}
template <class Vec3> ActorTracer mTracer, mUpStepper, mDownStepper;
static bool isWalkableSlope(const Vec3 &normal) bool mHaveMoved;
{
static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope));
return (normal.z() > sMaxSlopeCos);
}
static bool canStepDown(const ActorTracer &stepper) public:
{ Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj)
return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject); : mColWorld(colWorld)
} , mColObj(colObj)
, mHaveMoved(true)
{}
static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position, bool step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime)
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
{ {
/* /*
* Slide up an incline or set of stairs. Should be called only after a * Slide up an incline or set of stairs. Should be called only after a
@ -129,12 +140,14 @@ namespace MWPhysics
* +--+ +-------- * +--+ +--------
* ============================================== * ==============================================
*/ */
ActorTracer tracer, stepper; if (mHaveMoved)
{
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); mHaveMoved = false;
if(stepper.mFraction < std::numeric_limits<float>::epsilon()) mUpStepper.doTrace(mColObj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), mColWorld);
return false; // didn't even move the smallest representable amount if(mUpStepper.mFraction < std::numeric_limits<float>::epsilon())
// (TODO: shouldn't this be larger? Why bother with such a small amount?) return false; // didn't even move the smallest representable amount
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
}
/* /*
* Try moving from the elevated position using tracer. * Try moving from the elevated position using tracer.
@ -149,9 +162,9 @@ namespace MWPhysics
* +--+ * +--+
* ============================================== * ==============================================
*/ */
osg::Vec3f tracerPos = stepper.mEndPos; osg::Vec3f tracerPos = mUpStepper.mEndPos;
tracer.doTrace(colobj, tracerPos, tracerPos + toMove, collisionWorld); mTracer.doTrace(mColObj, tracerPos, tracerPos + toMove, mColWorld);
if(tracer.mFraction < std::numeric_limits<float>::epsilon()) if(mTracer.mFraction < std::numeric_limits<float>::epsilon())
return false; // didn't even move the smallest representable amount return false; // didn't even move the smallest representable amount
/* /*
@ -169,36 +182,40 @@ namespace MWPhysics
* +--+ +--+ * +--+ +--+
* ============================================== * ==============================================
*/ */
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
if (!canStepDown(stepper)) if (!canStepDown(mDownStepper))
{ {
// Try again with increased step length // Try again with increased step length
if (tracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep) if (mTracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep)
return false; return false;
osg::Vec3f direction = toMove; osg::Vec3f direction = toMove;
direction.normalize(); direction.normalize();
tracer.doTrace(colobj, tracerPos, tracerPos + direction*sMinStep, collisionWorld); mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld);
if (tracer.mFraction < 0.001f) if (mTracer.mFraction < 0.001f)
return false; return false;
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
if (!canStepDown(stepper)) if (!canStepDown(mDownStepper))
return false; return false;
} }
if (stepper.mFraction < 1.0f) if (mDownStepper.mFraction < 1.0f)
{ {
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing // TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
// NOTE: caller's variables 'position' & 'remainingTime' are modified here // NOTE: caller's variables 'position' & 'remainingTime' are modified here
position = stepper.mEndPos; position = mDownStepper.mEndPos;
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance
mHaveMoved = true;
return true; return true;
} }
return false; return false;
} }
};
class MovementSolver
{
private:
///Project a vector u on another vector v ///Project a vector u on another vector v
static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v) static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v)
{ {
@ -329,8 +346,8 @@ namespace MWPhysics
velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f));
} }
Stepper stepper(collisionWorld, colobj);
osg::Vec3f origVelocity = velocity; osg::Vec3f origVelocity = velocity;
osg::Vec3f newPosition = position; osg::Vec3f newPosition = position;
/* /*
* A loop to find newPosition using tracer, if successful different from the starting position. * A loop to find newPosition using tracer, if successful different from the starting position.
@ -385,7 +402,7 @@ namespace MWPhysics
osg::Vec3f oldPosition = newPosition; osg::Vec3f oldPosition = newPosition;
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
// NOTE: stepMove modifies newPosition if successful // NOTE: stepMove modifies newPosition if successful
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); bool result = stepper.step(newPosition, velocity*remainingTime, remainingTime);
if (result) if (result)
{ {
// don't let pure water creatures move out of water after stepMove // don't let pure water creatures move out of water after stepMove