forked from mirror/openmw-tes3mp
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.
|
||||
static const int sMaxIterations = 8;
|
||||
|
||||
// FIXME: move to a separate file
|
||||
class MovementSolver
|
||||
static bool isActor(const btCollisionObject *obj)
|
||||
{
|
||||
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:
|
||||
static bool isActor(const btCollisionObject *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return obj->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor;
|
||||
}
|
||||
const btCollisionWorld *mColWorld;
|
||||
const btCollisionObject *mColObj;
|
||||
|
||||
template <class Vec3>
|
||||
static bool isWalkableSlope(const Vec3 &normal)
|
||||
{
|
||||
static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope));
|
||||
return (normal.z() > sMaxSlopeCos);
|
||||
}
|
||||
ActorTracer mTracer, mUpStepper, mDownStepper;
|
||||
bool mHaveMoved;
|
||||
|
||||
static bool canStepDown(const ActorTracer &stepper)
|
||||
{
|
||||
return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject);
|
||||
}
|
||||
public:
|
||||
Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj)
|
||||
: mColWorld(colWorld)
|
||||
, mColObj(colObj)
|
||||
, mHaveMoved(true)
|
||||
{}
|
||||
|
||||
static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
|
||||
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
|
||||
bool step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime)
|
||||
{
|
||||
/*
|
||||
* Slide up an incline or set of stairs. Should be called only after a
|
||||
|
@ -129,12 +140,14 @@ namespace MWPhysics
|
|||
* +--+ +--------
|
||||
* ==============================================
|
||||
*/
|
||||
ActorTracer tracer, stepper;
|
||||
|
||||
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
|
||||
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||
return false; // didn't even move the smallest representable amount
|
||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||
if (mHaveMoved)
|
||||
{
|
||||
mHaveMoved = false;
|
||||
mUpStepper.doTrace(mColObj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), mColWorld);
|
||||
if(mUpStepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||
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.
|
||||
|
@ -149,9 +162,9 @@ namespace MWPhysics
|
|||
* +--+
|
||||
* ==============================================
|
||||
*/
|
||||
osg::Vec3f tracerPos = stepper.mEndPos;
|
||||
tracer.doTrace(colobj, tracerPos, tracerPos + toMove, collisionWorld);
|
||||
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||
osg::Vec3f tracerPos = mUpStepper.mEndPos;
|
||||
mTracer.doTrace(mColObj, tracerPos, tracerPos + toMove, mColWorld);
|
||||
if(mTracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||
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);
|
||||
if (!canStepDown(stepper))
|
||||
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
||||
if (!canStepDown(mDownStepper))
|
||||
{
|
||||
// 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;
|
||||
|
||||
osg::Vec3f direction = toMove;
|
||||
direction.normalize();
|
||||
tracer.doTrace(colobj, tracerPos, tracerPos + direction*sMinStep, collisionWorld);
|
||||
if (tracer.mFraction < 0.001f)
|
||||
mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld);
|
||||
if (mTracer.mFraction < 0.001f)
|
||||
return false;
|
||||
|
||||
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
|
||||
if (!canStepDown(stepper))
|
||||
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
||||
if (!canStepDown(mDownStepper))
|
||||
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.
|
||||
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
||||
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
||||
position = stepper.mEndPos;
|
||||
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
|
||||
position = mDownStepper.mEndPos;
|
||||
remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance
|
||||
mHaveMoved = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MovementSolver
|
||||
{
|
||||
private:
|
||||
///Project a vector u on another vector 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));
|
||||
}
|
||||
|
||||
Stepper stepper(collisionWorld, colobj);
|
||||
osg::Vec3f origVelocity = velocity;
|
||||
|
||||
osg::Vec3f newPosition = 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;
|
||||
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
||||
// 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)
|
||||
{
|
||||
// don't let pure water creatures move out of water after stepMove
|
||||
|
|
Loading…
Reference in a new issue