From ca6cce0c7e98ab43ebc5550c28c43d4ab7136706 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 30 Mar 2020 23:07:12 +0300 Subject: [PATCH] Separate Stepper --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwphysics/constants.hpp | 16 +++ apps/openmw/mwphysics/physicssystem.cpp | 150 +----------------------- apps/openmw/mwphysics/physicssystem.hpp | 3 - apps/openmw/mwphysics/stepper.cpp | 148 +++++++++++++++++++++++ apps/openmw/mwphysics/stepper.hpp | 32 +++++ apps/openmw/mwworld/worldimp.cpp | 1 + 7 files changed, 200 insertions(+), 152 deletions(-) create mode 100644 apps/openmw/mwphysics/constants.hpp create mode 100644 apps/openmw/mwphysics/stepper.cpp create mode 100644 apps/openmw/mwphysics/stepper.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 67eb0cd27e..0472bd033c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -71,7 +71,7 @@ add_openmw_dir (mwworld add_openmw_dir (mwphysics physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback - contacttestresultcallback deepestnotmecontacttestresultcallback + contacttestresultcallback deepestnotmecontacttestresultcallback stepper ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwphysics/constants.hpp b/apps/openmw/mwphysics/constants.hpp new file mode 100644 index 0000000000..46367ab343 --- /dev/null +++ b/apps/openmw/mwphysics/constants.hpp @@ -0,0 +1,16 @@ +#ifndef OPENMW_MWPHYSICS_CONSTANTS_H +#define OPENMW_MWPHYSICS_CONSTANTS_H + +namespace MWPhysics +{ + static const float sStepSizeUp = 34.0f; + static const float sStepSizeDown = 62.0f; + static const float sMinStep = 10.f; + static const float sGroundOffset = 1.0f; + static const float sMaxSlope = 49.0f; + + // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + static const int sMaxIterations = 8; +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index bf4bd386e2..908ec90f3b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -49,17 +49,11 @@ #include "deepestnotmecontacttestresultcallback.hpp" #include "closestnotmerayresultcallback.hpp" #include "contacttestresultcallback.hpp" +#include "stepper.hpp" +#include "constants.hpp" namespace MWPhysics { - - static const float sStepSizeDown = 62.0f; - static const float sMinStep = 10.f; - static const float sGroundOffset = 1.0f; - - // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - static const int sMaxIterations = 8; - static bool isActor(const btCollisionObject *obj) { assert(obj); @@ -73,146 +67,6 @@ namespace MWPhysics return (normal.z() > sMaxSlopeCos); } - static bool canStepDown(const ActorTracer &stepper) - { - return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject); - } - - class Stepper - { - private: - const btCollisionWorld *mColWorld; - const btCollisionObject *mColObj; - - ActorTracer mTracer, mUpStepper, mDownStepper; - bool mHaveMoved; - - public: - Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj) - : mColWorld(colWorld) - , mColObj(colObj) - , mHaveMoved(true) - {} - - 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 - * collision detection otherwise unnecessary tracing will be performed. - * - * NOTE: with a small change this method can be used to step over an obstacle - * of height sStepSize. - * - * If successful return 'true' and update 'position' to the new possible - * location and adjust 'remainingTime'. - * - * If not successful return 'false'. May fail for these reasons: - * - can't move directly up from current position - * - having moved up by between epsilon() and sStepSize, can't move forward - * - having moved forward by between epsilon() and toMove, - * = moved down between 0 and just under sStepSize but slope was too steep, or - * = moved the full sStepSize down (FIXME: this could be a bug) - * - * - * - * Starting position. Obstacle or stairs with height upto sStepSize in front. - * - * +--+ +--+ |XX - * | | -------> toMove | | +--+XX - * | | | | |XXXXX - * | | +--+ | | +--+XXXXX - * | | |XX| | | |XXXXXXXX - * +--+ +--+ +--+ +-------- - * ============================================== - */ - - /* - * Try moving up sStepSize using stepper. - * FIXME: does not work in case there is no front obstacle but there is one above - * - * +--+ +--+ - * | | | | - * | | | | |XX - * | | | | +--+XX - * | | | | |XXXXX - * +--+ +--+ +--+ +--+XXXXX - * |XX| |XXXXXXXX - * +--+ +-------- - * ============================================== - */ - 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. - * - * +--+ +--+ - * | | |YY| FIXME: collision with object YY - * | | +--+ - * | | - * <------------------->| | - * +--+ +--+ - * |XX| the moved amount is toMove*tracer.mFraction - * +--+ - * ============================================== - */ - 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 - - /* - * Try moving back down sStepSizeDown using stepper. - * NOTE: if there is an obstacle below (e.g. stairs), we'll be "stepping up". - * Below diagram is the case where we "stepped over" an obstacle in front. - * - * +--+ - * |YY| - * +--+ +--+ - * | | - * | | - * +--+ | | - * |XX| | | - * +--+ +--+ - * ============================================== - */ - 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 (mTracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep) - return false; - - osg::Vec3f direction = toMove; - direction.normalize(); - mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld); - if (mTracer.mFraction < 0.001f) - return false; - - mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld); - if (!canStepDown(mDownStepper)) - return false; - } - 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 = mDownStepper.mEndPos; - remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance - mHaveMoved = true; - return true; - } - return false; - } - }; - class MovementSolver { private: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index d74e2de160..0f2ecc0927 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -50,9 +50,6 @@ namespace MWPhysics class Object; class Actor; - static const float sMaxSlope = 49.0f; - static const float sStepSizeUp = 34.0f; - class PhysicsSystem { public: diff --git a/apps/openmw/mwphysics/stepper.cpp b/apps/openmw/mwphysics/stepper.cpp new file mode 100644 index 0000000000..0ab383dd1e --- /dev/null +++ b/apps/openmw/mwphysics/stepper.cpp @@ -0,0 +1,148 @@ +#include "stepper.hpp" + +#include + +#include +#include + +#include "collisiontype.hpp" +#include "constants.hpp" + +namespace MWPhysics +{ + static bool canStepDown(const ActorTracer &stepper) + { + if (!stepper.mHitObject) + return false; + static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope)); + if (stepper.mPlaneNormal.z() <= sMaxSlopeCos) + return false; + + return stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor; + } + + Stepper::Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj) + : mColWorld(colWorld) + , mColObj(colObj) + , mHaveMoved(true) + { + } + + bool Stepper::step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime) + { + /* + * Slide up an incline or set of stairs. Should be called only after a + * collision detection otherwise unnecessary tracing will be performed. + * + * NOTE: with a small change this method can be used to step over an obstacle + * of height sStepSize. + * + * If successful return 'true' and update 'position' to the new possible + * location and adjust 'remainingTime'. + * + * If not successful return 'false'. May fail for these reasons: + * - can't move directly up from current position + * - having moved up by between epsilon() and sStepSize, can't move forward + * - having moved forward by between epsilon() and toMove, + * = moved down between 0 and just under sStepSize but slope was too steep, or + * = moved the full sStepSize down (FIXME: this could be a bug) + * + * Starting position. Obstacle or stairs with height upto sStepSize in front. + * + * +--+ +--+ |XX + * | | -------> toMove | | +--+XX + * | | | | |XXXXX + * | | +--+ | | +--+XXXXX + * | | |XX| | | |XXXXXXXX + * +--+ +--+ +--+ +-------- + * ============================================== + */ + + /* + * Try moving up sStepSize using stepper. + * FIXME: does not work in case there is no front obstacle but there is one above + * + * +--+ +--+ + * | | | | + * | | | | |XX + * | | | | +--+XX + * | | | | |XXXXX + * +--+ +--+ +--+ +--+XXXXX + * |XX| |XXXXXXXX + * +--+ +-------- + * ============================================== + */ + 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. + * + * +--+ +--+ + * | | |YY| FIXME: collision with object YY + * | | +--+ + * | | + * <------------------->| | + * +--+ +--+ + * |XX| the moved amount is toMove*tracer.mFraction + * +--+ + * ============================================== + */ + 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 + + /* + * Try moving back down sStepSizeDown using stepper. + * NOTE: if there is an obstacle below (e.g. stairs), we'll be "stepping up". + * Below diagram is the case where we "stepped over" an obstacle in front. + * + * +--+ + * |YY| + * +--+ +--+ + * | | + * | | + * +--+ | | + * |XX| | | + * +--+ +--+ + * ============================================== + */ + 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 (mTracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep) + return false; + + osg::Vec3f direction = toMove; + direction.normalize(); + mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld); + if (mTracer.mFraction < 0.001f) + return false; + + mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld); + if (!canStepDown(mDownStepper)) + return false; + } + + 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 = mDownStepper.mEndPos; + remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance + mHaveMoved = true; + return true; + } + return false; + } +} diff --git a/apps/openmw/mwphysics/stepper.hpp b/apps/openmw/mwphysics/stepper.hpp new file mode 100644 index 0000000000..27e6294b05 --- /dev/null +++ b/apps/openmw/mwphysics/stepper.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_MWPHYSICS_STEPPER_H +#define OPENMW_MWPHYSICS_STEPPER_H + +#include "trace.h" + +class btCollisionObject; +class btCollisionWorld; + +namespace osg +{ + class Vec3f; +} + +namespace MWPhysics +{ + class Stepper + { + private: + const btCollisionWorld *mColWorld; + const btCollisionObject *mColObj; + + ActorTracer mTracer, mUpStepper, mDownStepper; + bool mHaveMoved; + + public: + Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj); + + bool step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime); + }; +} + +#endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 26eac954b9..8598b9b046 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -56,6 +56,7 @@ #include "../mwphysics/actor.hpp" #include "../mwphysics/collisiontype.hpp" #include "../mwphysics/object.hpp" +#include "../mwphysics/constants.hpp" #include "player.hpp" #include "manualref.hpp"