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:
parent
4f6e65e481
commit
50fd913058
1 changed files with 58 additions and 41 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue