From 561e0cbbf986f889829d9c4d40b30ad6c2d8aca6 Mon Sep 17 00:00:00 2001 From: logzero Date: Tue, 6 Dec 2016 22:20:31 +0100 Subject: [PATCH 01/10] Use squared length for distance checks in movement solver. --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 544fb0199..e6ef5328c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -229,7 +229,7 @@ namespace MWPhysics collisionWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && - ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 35 + ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35 || getSlope(tracer.mPlaneNormal) > sMaxSlope)) { actor->setOnGround(getSlope(toOsg(resultCallback1.m_hitNormalWorld)) <= sMaxSlope); @@ -370,7 +370,7 @@ namespace MWPhysics // NOTE: stepMove modifies newPosition if successful const float minStep = 10.f; StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); - if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent + if (result == Result_MaxSlope && (velocity*remainingTime).length2() < minStep*minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent { osg::Vec3f normalizedVelocity = velocity; normalizedVelocity.normalize(); From 25a0219e4d937a36172aba24c7440d7be8b567b8 Mon Sep 17 00:00:00 2001 From: logzero Date: Tue, 6 Dec 2016 22:46:09 +0100 Subject: [PATCH 02/10] Use cosine of max slope angle for walkable slope checks in movement solver. --- apps/openmw/mwphysics/physicssystem.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e6ef5328c..bf0589797 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -63,10 +63,11 @@ namespace MWPhysics class MovementSolver { private: - static float getSlope(osg::Vec3f normal) + template + static bool isWalkableSlope(const Vec3 &normal) { - normal.normalize(); - return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); + static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope)); + return (normal.z() > sMaxSlopeCos); } enum StepMoveResult @@ -163,7 +164,7 @@ namespace MWPhysics * ============================================== */ stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); - if (getSlope(stepper.mPlaneNormal) > sMaxSlope) + if (!isWalkableSlope(stepper.mPlaneNormal)) return Result_MaxSlope; if(stepper.mFraction < 1.0f) { @@ -230,13 +231,13 @@ namespace MWPhysics if (resultCallback1.hasHit() && ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35 - || getSlope(tracer.mPlaneNormal) > sMaxSlope)) + || !isWalkableSlope(tracer.mPlaneNormal))) { - actor->setOnGround(getSlope(toOsg(resultCallback1.m_hitNormalWorld)) <= sMaxSlope); + actor->setOnGround(isWalkableSlope(resultCallback1.m_hitNormalWorld)); return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f); } - actor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope); + actor->setOnGround(isWalkableSlope(tracer.mPlaneNormal)); return tracer.mEndPos; } @@ -413,7 +414,7 @@ namespace MWPhysics osg::Vec3f to = newPosition - (physicActor->getOnGround() ? osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f)); tracer.doTrace(colobj, from, to, collisionWorld); - if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope + if(tracer.mFraction < 1.0f && isWalkableSlope(tracer.mPlaneNormal) && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) { const btCollisionObject* standingOn = tracer.mHitObject; From 0b08802910fbcb2c54ee36dc53a77f4624fd51a7 Mon Sep 17 00:00:00 2001 From: logzero Date: Wed, 14 Dec 2016 16:30:31 +0100 Subject: [PATCH 03/10] Integrate MinStep move attempt into stepMove. This can save 1 to 3 convex casts per iteration. --- apps/openmw/mwphysics/physicssystem.cpp | 63 ++++++++++++++----------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index bf0589797..3699eeeba 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -55,6 +55,7 @@ namespace MWPhysics static const float sMaxSlope = 49.0f; static const float sStepSizeUp = 34.0f; static const float sStepSizeDown = 62.0f; + static const float sMinStep = 10.f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 8; @@ -63,6 +64,12 @@ namespace MWPhysics class MovementSolver { private: + static bool isActor(const btCollisionObject *obj) + { + assert(obj); + return obj->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor; + } + template static bool isWalkableSlope(const Vec3 &normal) { @@ -70,14 +77,12 @@ namespace MWPhysics return (normal.z() > sMaxSlopeCos); } - enum StepMoveResult + static bool canStepDown(const ActorTracer &stepper) { - Result_Blocked, // unable to move over obstacle - Result_MaxSlope, // unable to end movement on this slope - Result_Success - }; + return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject); + } - static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position, + static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld) { /* @@ -128,7 +133,7 @@ namespace MWPhysics stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) - return Result_Blocked; // didn't even move the smallest representable amount + return false; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) /* @@ -144,9 +149,10 @@ namespace MWPhysics * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld); + osg::Vec3f tracerPos = stepper.mEndPos; + tracer.doTrace(colobj, tracerPos, tracerPos + toMove, collisionWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) - return Result_Blocked; // didn't even move the smallest representable amount + return false; // didn't even move the smallest representable amount /* * Try moving back down sStepSizeDown using stepper. @@ -164,22 +170,32 @@ namespace MWPhysics * ============================================== */ stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); - if (!isWalkableSlope(stepper.mPlaneNormal)) - return Result_MaxSlope; - if(stepper.mFraction < 1.0f) + if (!canStepDown(stepper)) + { + // Try again with increased step length + if (tracer.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) + return false; + + stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); + if (!canStepDown(stepper)) + return false; + } + if (stepper.mFraction < 1.0f) { - // don't allow stepping up other actors - if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) - return Result_Blocked; // 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 - return Result_Success; + return true; } - - return Result_Blocked; + return false; } @@ -369,15 +385,8 @@ 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 - const float minStep = 10.f; - StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); - if (result == Result_MaxSlope && (velocity*remainingTime).length2() < minStep*minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent - { - osg::Vec3f normalizedVelocity = velocity; - normalizedVelocity.normalize(); - result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld); - } - if(result == Result_Success) + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); + if (result) { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) From 4f6e65e48105d97ce6886bdecdc29cd253b3f061 Mon Sep 17 00:00:00 2001 From: logzero Date: Thu, 15 Dec 2016 13:56:08 +0100 Subject: [PATCH 04/10] Apply sliding upward check to new velocity. This helps to capture the case where new velocity only differs in the z component (normal pointing up). TODO: Find a better way to handle the normal pointing up case. --- apps/openmw/mwphysics/physicssystem.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 3699eeeba..0d0a6e9f9 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -402,17 +402,18 @@ namespace MWPhysics reflectdir.normalize(); osg::Vec3f newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + + // Do not allow sliding upward if there is gravity. + // Stepping will have taken care of that. + if(!(newPosition.z() < swimlevel || isFlying)) + newVelocity.z() = std::min(newVelocity.z(), 0.0f); + if ((newVelocity-velocity).length2() < 0.01) break; if ((velocity * origVelocity) <= 0.f) break; // ^ dot product velocity = newVelocity; - - // Do not allow sliding upward if there is gravity. Stepping will have taken - // care of that. - if(!(newPosition.z() < swimlevel || isFlying)) - velocity.z() = std::min(velocity.z(), 0.0f); } } From 50fd9130587a9c6864a34db25c1369657c61b380 Mon Sep 17 00:00:00 2001 From: logzero Date: Wed, 21 Dec 2016 10:41:43 +0100 Subject: [PATCH 05/10] 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. --- apps/openmw/mwphysics/physicssystem.cpp | 99 +++++++++++++++---------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 0d0a6e9f9..494ff681c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -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 + 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 - 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::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::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::epsilon()) + osg::Vec3f tracerPos = mUpStepper.mEndPos; + mTracer.doTrace(mColObj, tracerPos, tracerPos + toMove, mColWorld); + if(mTracer.mFraction < std::numeric_limits::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 From e58de5e410549e9da9cd30989ba0d8f03a019224 Mon Sep 17 00:00:00 2001 From: logzero Date: Sat, 24 Dec 2016 12:29:09 +0100 Subject: [PATCH 06/10] Remove superfluous velocity reflection in movement solver. The slide projection negates the reflection effect. Just to be sure I've compared the resulting vectors with and without reflection at runtime. --- apps/openmw/mwphysics/physicssystem.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 494ff681c..ab7117a10 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -366,10 +366,7 @@ namespace MWPhysics newPosition.z() <= swimlevel) { const osg::Vec3f down(0,0,-1); - float movelen = velocity.normalize(); - osg::Vec3f reflectdir = reflect(velocity, down); - reflectdir.normalize(); - velocity = slide(reflectdir, down)*movelen; + velocity = slide(velocity, down); // NOTE: remainingTime is unchanged before the loop continues continue; // velocity updated, calculate nextpos again } @@ -413,12 +410,7 @@ namespace MWPhysics else { // Can't move this way, try to find another spot along the plane - osg::Vec3f direction = velocity; - float movelen = direction.normalize(); - osg::Vec3f reflectdir = reflect(velocity, tracer.mPlaneNormal); - reflectdir.normalize(); - - osg::Vec3f newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + osg::Vec3f newVelocity = slide(velocity, tracer.mPlaneNormal); // Do not allow sliding upward if there is gravity. // Stepping will have taken care of that. From ab1724d3db1db59b789171d6b013639fcc195c8b Mon Sep 17 00:00:00 2001 From: logzero Date: Sat, 24 Dec 2016 12:38:23 +0100 Subject: [PATCH 07/10] Compare new velocity to the original velocity. Using old velocity seems awkward, probably a copypaste/refactoring bug. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index ab7117a10..14e05f101 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -419,7 +419,7 @@ namespace MWPhysics if ((newVelocity-velocity).length2() < 0.01) break; - if ((velocity * origVelocity) <= 0.f) + if ((newVelocity * origVelocity) <= 0.f) break; // ^ dot product velocity = newVelocity; From 00f3bfba27d0d509c3991ec2450a80ca3c42ff35 Mon Sep 17 00:00:00 2001 From: logzero Date: Sat, 24 Dec 2016 23:07:44 +0100 Subject: [PATCH 08/10] Use tracer hit height to skip stepping up in movement solver. --- apps/openmw/mwphysics/physicssystem.cpp | 12 +++++++++--- apps/openmw/mwphysics/trace.cpp | 2 ++ apps/openmw/mwphysics/trace.h | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 14e05f101..2a3cb6137 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -396,10 +396,16 @@ namespace MWPhysics } + // We hit something. Check if we can step up. + float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z(); 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 = stepper.step(newPosition, velocity*remainingTime, remainingTime); + bool result = false; + if (hitHeight < sStepSizeUp) + { + // Try to step up onto it. + // NOTE: stepMove does not allow stepping over, modifies newPosition if successful + result = stepper.step(newPosition, velocity*remainingTime, remainingTime); + } if (result) { // don't let pure water creatures move out of water after stepMove diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 420ca1a9e..feda68ca5 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -78,6 +78,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star mFraction = newTraceCallback.m_closestHitFraction; mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); mEndPos = (end-start)*mFraction + start; + mHitPoint = toOsg(newTraceCallback.m_hitPointWorld); mHitObject = newTraceCallback.m_hitCollisionObject; } else @@ -85,6 +86,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star mEndPos = end; mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f); mFraction = 1.0f; + mHitPoint = end; mHitObject = NULL; } } diff --git a/apps/openmw/mwphysics/trace.h b/apps/openmw/mwphysics/trace.h index 7b7d0391e..0297c9e07 100644 --- a/apps/openmw/mwphysics/trace.h +++ b/apps/openmw/mwphysics/trace.h @@ -15,6 +15,7 @@ namespace MWPhysics { osg::Vec3f mEndPos; osg::Vec3f mPlaneNormal; + osg::Vec3f mHitPoint; const btCollisionObject* mHitObject; float mFraction; From a5360483bbbef3581383d60918f7b3eb754d3e04 Mon Sep 17 00:00:00 2001 From: logzero Date: Sun, 25 Dec 2016 15:34:43 +0100 Subject: [PATCH 09/10] Back off slightly when we are touching something. This can reduce the amount of movement solver failures significantly. I've observed a drop of 8 iteration cases by almost factor of ten. --- apps/openmw/mwphysics/physicssystem.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2a3cb6137..db72ac636 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -395,6 +395,13 @@ namespace MWPhysics break; } + // We are touching something. + if (tracer.mFraction < 1E-9f) + { + // Try to separate by backing off slighly to unstuck the solver + const osg::Vec3f backOff = (newPosition - tracer.mHitPoint) * 1E-3f; + newPosition += backOff; + } // We hit something. Check if we can step up. float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z(); From dbf0fa6766f580556cb69503f1ee6f60057790e7 Mon Sep 17 00:00:00 2001 From: logzero Date: Sat, 31 Dec 2016 10:57:06 +0100 Subject: [PATCH 10/10] Skip stepping if movement tracer hits actor. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index db72ac636..87a7ab3e5 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -407,7 +407,7 @@ namespace MWPhysics float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z(); osg::Vec3f oldPosition = newPosition; bool result = false; - if (hitHeight < sStepSizeUp) + if (hitHeight < sStepSizeUp && !isActor(tracer.mHitObject)) { // Try to step up onto it. // NOTE: stepMove does not allow stepping over, modifies newPosition if successful