mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-27 04:10:24 +00:00
Optimize short-trace test to only be done when particularly helpful
This commit is contained in:
parent
e23b0edda4
commit
8c0102e1ee
4 changed files with 36 additions and 24 deletions
|
@ -203,7 +203,7 @@ namespace MWPhysics
|
||||||
if((newPosition - nextpos).length2() > 0.0001)
|
if((newPosition - nextpos).length2() > 0.0001)
|
||||||
{
|
{
|
||||||
// trace to where character would go if there were no obstructions
|
// trace to where character would go if there were no obstructions
|
||||||
tracer.doTrace(actor.mCollisionObject, newPosition, nextpos, collisionWorld);
|
tracer.doTrace(actor.mCollisionObject, newPosition, nextpos, collisionWorld, actor.mIsOnGround);
|
||||||
|
|
||||||
// check for obstructions
|
// check for obstructions
|
||||||
if(tracer.mFraction >= 1.0f)
|
if(tracer.mFraction >= 1.0f)
|
||||||
|
@ -338,7 +338,7 @@ namespace MWPhysics
|
||||||
osg::Vec3f from = newPosition;
|
osg::Vec3f from = newPosition;
|
||||||
auto dropDistance = 2*sGroundOffset + (actor.mIsOnGround ? sStepSizeDown : 0);
|
auto dropDistance = 2*sGroundOffset + (actor.mIsOnGround ? sStepSizeDown : 0);
|
||||||
osg::Vec3f to = newPosition - osg::Vec3f(0,0,dropDistance);
|
osg::Vec3f to = newPosition - osg::Vec3f(0,0,dropDistance);
|
||||||
tracer.doTrace(actor.mCollisionObject, from, to, collisionWorld);
|
tracer.doTrace(actor.mCollisionObject, from, to, collisionWorld, actor.mIsOnGround);
|
||||||
if(tracer.mFraction < 1.0f)
|
if(tracer.mFraction < 1.0f)
|
||||||
{
|
{
|
||||||
if (!isActor(tracer.mHitObject))
|
if (!isActor(tracer.mHitObject))
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace MWPhysics
|
||||||
// Stairstepping algorithms work by moving up to avoid the step, moving forwards, then moving back down onto the ground.
|
// Stairstepping algorithms work by moving up to avoid the step, moving forwards, then moving back down onto the ground.
|
||||||
// This algorithm has a couple of minor problems, but they don't cause problems for sane geometry, and just prevent stepping on insane geometry.
|
// This algorithm has a couple of minor problems, but they don't cause problems for sane geometry, and just prevent stepping on insane geometry.
|
||||||
|
|
||||||
mUpStepper.doTrace(mColObj, position, position + osg::Vec3f(0.0f, 0.0f, Constants::sStepSizeUp), mColWorld);
|
mUpStepper.doTrace(mColObj, position, position + osg::Vec3f(0.0f, 0.0f, Constants::sStepSizeUp), mColWorld, onGround);
|
||||||
|
|
||||||
float upDistance = 0;
|
float upDistance = 0;
|
||||||
if(!mUpStepper.mHitObject)
|
if(!mUpStepper.mHitObject)
|
||||||
|
@ -117,7 +117,7 @@ namespace MWPhysics
|
||||||
downStepSize = upDistance;
|
downStepSize = upDistance;
|
||||||
else
|
else
|
||||||
downStepSize = moveDistance + upDistance + sStepSizeDown;
|
downStepSize = moveDistance + upDistance + sStepSizeDown;
|
||||||
mDownStepper.doTrace(mColObj, tracerDest, tracerDest + osg::Vec3f(0.0f, 0.0f, -downStepSize), mColWorld);
|
mDownStepper.doTrace(mColObj, tracerDest, tracerDest + osg::Vec3f(0.0f, 0.0f, -downStepSize), mColWorld, onGround);
|
||||||
|
|
||||||
// can't step down onto air, non-walkable-slopes, or actors
|
// can't step down onto air, non-walkable-slopes, or actors
|
||||||
// NOTE: using a capsule causes isWalkableSlope (used in canStepDown) to fail on certain geometry that were intended to be valid at the bottoms of stairs
|
// NOTE: using a capsule causes isWalkableSlope (used in canStepDown) to fail on certain geometry that were intended to be valid at the bottoms of stairs
|
||||||
|
|
|
@ -24,45 +24,57 @@ ActorConvexCallback sweepHelper(const btCollisionObject *actor, const btVector3&
|
||||||
assert(shape->isConvex());
|
assert(shape->isConvex());
|
||||||
|
|
||||||
const btVector3 motion = from - to; // FIXME: this is backwards; means ActorConvexCallback is doing dot product tests backwards too
|
const btVector3 motion = from - to; // FIXME: this is backwards; means ActorConvexCallback is doing dot product tests backwards too
|
||||||
ActorConvexCallback newTraceCallback(actor, motion, btScalar(0.0), world);
|
ActorConvexCallback traceCallback(actor, motion, btScalar(0.0), world);
|
||||||
// Inherit the actor's collision group and mask
|
// Inherit the actor's collision group and mask
|
||||||
newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup;
|
traceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask;
|
traceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
if(actorFilter)
|
if(actorFilter)
|
||||||
newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor;
|
traceCallback.m_collisionFilterMask &= ~CollisionType_Actor;
|
||||||
|
|
||||||
world->convexSweepTest(static_cast<const btConvexShape*>(shape), transFrom, transTo, newTraceCallback);
|
world->convexSweepTest(static_cast<const btConvexShape*>(shape), transFrom, transTo, traceCallback);
|
||||||
return newTraceCallback;
|
return traceCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world)
|
void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world, bool attempt_short_trace)
|
||||||
{
|
{
|
||||||
const btVector3 btstart = Misc::Convert::toBullet(start);
|
const btVector3 btstart = Misc::Convert::toBullet(start);
|
||||||
btVector3 btend = Misc::Convert::toBullet(end);
|
btVector3 btend = Misc::Convert::toBullet(end);
|
||||||
|
|
||||||
bool do_fallback = false;
|
// Because Bullet's collision trace tests touch *all* geometry in its path, a lot of long collision tests
|
||||||
if((btend-btstart).length2() > 5.0*5.0)
|
// will unnecessarily test against complex meshes that are dozens of units away. This wouldn't normally be
|
||||||
|
// a problem, but bullet isn't the fastest in the world when it comes to doing tests against triangle meshes.
|
||||||
|
// Therefore, we try out a short trace first, then only fall back to the full length trace if needed.
|
||||||
|
// This trace needs to be at least a couple units long, but there's no one particular ideal length.
|
||||||
|
// The length of 2.1 chosen here is a "works well in practice after testing a few random lengths" value.
|
||||||
|
// (Also, we only do this short test if the intended collision trace is long enough for it to make sense.)
|
||||||
|
const float fallback_length = 2.1f;
|
||||||
|
bool doing_short_trace = false;
|
||||||
|
// For some reason, typical scenes perform a little better if we increase the threshold length for the length test.
|
||||||
|
// (Multiplying by 2 in 'square distance' units gives us about 1.4x the threshold length. In benchmarks this was
|
||||||
|
// slightly better for the performance of normal scenes than 4.0, and just plain better than 1.0.)
|
||||||
|
if(attempt_short_trace && (btend-btstart).length2() > fallback_length*fallback_length*2.0)
|
||||||
{
|
{
|
||||||
btend = btstart + (btend-btstart).normalized()*5.0;
|
btend = btstart + (btend-btstart).normalized()*fallback_length;
|
||||||
do_fallback = true;
|
doing_short_trace = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newTraceCallback = sweepHelper(actor, btstart, btend, world, false);
|
auto traceCallback = sweepHelper(actor, btstart, btend, world, false);
|
||||||
|
|
||||||
// Copy the hit data over to our trace results struct:
|
// Copy the hit data over to our trace results struct:
|
||||||
if(newTraceCallback.hasHit())
|
if(traceCallback.hasHit())
|
||||||
{
|
{
|
||||||
mFraction = newTraceCallback.m_closestHitFraction;
|
mFraction = traceCallback.m_closestHitFraction;
|
||||||
if((end-start).length2() > 0.0)
|
// ensure fraction is correct (covers intended distance traveled instead of actual distance traveled)
|
||||||
|
if(doing_short_trace && (end-start).length2() > 0.0)
|
||||||
mFraction *= (btend-btstart).length() / (end-start).length();
|
mFraction *= (btend-btstart).length() / (end-start).length();
|
||||||
mPlaneNormal = Misc::Convert::toOsg(newTraceCallback.m_hitNormalWorld);
|
mPlaneNormal = Misc::Convert::toOsg(traceCallback.m_hitNormalWorld);
|
||||||
mEndPos = (end-start)*mFraction + start;
|
mEndPos = (end-start)*mFraction + start;
|
||||||
mHitPoint = Misc::Convert::toOsg(newTraceCallback.m_hitPointWorld);
|
mHitPoint = Misc::Convert::toOsg(traceCallback.m_hitPointWorld);
|
||||||
mHitObject = newTraceCallback.m_hitCollisionObject;
|
mHitObject = traceCallback.m_hitCollisionObject;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(do_fallback)
|
if(doing_short_trace)
|
||||||
{
|
{
|
||||||
btend = Misc::Convert::toBullet(end);
|
btend = Misc::Convert::toBullet(end);
|
||||||
auto newTraceCallback = sweepHelper(actor, btstart, btend, world, false);
|
auto newTraceCallback = sweepHelper(actor, btstart, btend, world, false);
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
float mFraction;
|
float mFraction;
|
||||||
|
|
||||||
void doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world);
|
void doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world, bool attempt_short_trace = false);
|
||||||
void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world);
|
void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue