From 16297918856fed409e17414a0891503733db782d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 30 Mar 2020 21:23:41 +0300 Subject: [PATCH 1/8] Port wareya's actor tracer consistency fixes --- apps/openmw/mwphysics/trace.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 57b0a83680..13bc7f7983 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -14,9 +14,9 @@ namespace MWPhysics class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: - ClosestNotMeConvexResultCallback(const btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot) + ClosestNotMeConvexResultCallback(const btCollisionObject *me, const btVector3 &motion, btScalar minCollisionDot) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), - mMe(me), mUp(up), mMinSlopeDot(minSlopeDot) + mMe(me), mMotion(motion), mMinCollisionDot(minCollisionDot) { } @@ -34,8 +34,9 @@ public: hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; } - btScalar dotUp = mUp.dot(hitNormalWorld); - if(dotUp < mMinSlopeDot) + // dot product of the motion vector against the collision contact normal + btScalar dotCollision = mMotion.dot(hitNormalWorld); + if(dotCollision <= mMinCollisionDot) return btScalar(1); return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); @@ -43,8 +44,8 @@ public: protected: const btCollisionObject *mMe; - const btVector3 mUp; - const btScalar mMinSlopeDot; + const btVector3 mMotion; + const btScalar mMinCollisionDot; }; @@ -59,22 +60,21 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star from.setOrigin(btstart); to.setOrigin(btend); - ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0)); + const btVector3 motion = btstart-btend; + ClosestNotMeConvexResultCallback newTraceCallback(actor, motion, btScalar(0.0)); // Inherit the actor's collision group and mask newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup; newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask; const btCollisionShape *shape = actor->getCollisionShape(); assert(shape->isConvex()); - world->convexSweepTest(static_cast(shape), - from, to, newTraceCallback); + world->convexSweepTest(static_cast(shape), from, to, newTraceCallback); // Copy the hit data over to our trace results struct: if(newTraceCallback.hasHit()) { - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; mFraction = newTraceCallback.m_closestHitFraction; - mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + mPlaneNormal = Misc::Convert::toOsg(newTraceCallback.m_hitNormalWorld); mEndPos = (end-start)*mFraction + start; mHitPoint = Misc::Convert::toOsg(newTraceCallback.m_hitPointWorld); mHitObject = newTraceCallback.m_hitCollisionObject; @@ -91,14 +91,15 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world) { - const btVector3 btstart(start.x(), start.y(), start.z()); - const btVector3 btend(end.x(), end.y(), end.z()); + const btVector3 btstart = Misc::Convert::toBullet(start); + const btVector3 btend = Misc::Convert::toBullet(end); const btTransform &trans = actor->getCollisionObject()->getWorldTransform(); btTransform from(trans.getBasis(), btstart); btTransform to(trans.getBasis(), btend); - ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionObject(), btstart-btend, btScalar(0.0)); + const btVector3 motion = btstart-btend; + ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionObject(), motion, btScalar(0.0)); // Inherit the actor's collision group and mask newTraceCallback.m_collisionFilterGroup = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup; newTraceCallback.m_collisionFilterMask = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -107,9 +108,8 @@ void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const world->convexSweepTest(actor->getConvexShape(), from, to, newTraceCallback); if(newTraceCallback.hasHit()) { - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; mFraction = newTraceCallback.m_closestHitFraction; - mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + mPlaneNormal = Misc::Convert::toOsg(newTraceCallback.m_hitNormalWorld); mEndPos = (end-start)*mFraction + start; } else From ce588fb39cb92ca6fab470b4eecaab55d30e341b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 30 Mar 2020 21:39:10 +0300 Subject: [PATCH 2/8] Separate DeepestNotMeContactTestResultCallback --- apps/openmw/CMakeLists.txt | 3 +- .../deepestnotmecontacttestresultcallback.cpp | 45 +++++++++++++++++ .../deepestnotmecontacttestresultcallback.hpp | 32 ++++++++++++ apps/openmw/mwphysics/physicssystem.cpp | 49 +------------------ 4 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp create mode 100644 apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2bc85e0625..67eb0cd27e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -70,7 +70,8 @@ add_openmw_dir (mwworld ) add_openmw_dir (mwphysics - physicssystem trace collisiontype actor convert object heightfield + physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback + contacttestresultcallback deepestnotmecontacttestresultcallback ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp new file mode 100644 index 0000000000..be94128c18 --- /dev/null +++ b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp @@ -0,0 +1,45 @@ +#include "deepestnotmecontacttestresultcallback.hpp" + +#include + +#include "../mwworld/class.hpp" + +#include "ptrholder.hpp" + +namespace MWPhysics +{ + + DeepestNotMeContactTestResultCallback::DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3 &origin) + : mMe(me), mTargets(targets), mOrigin(origin), mLeastDistSqr(std::numeric_limits::max()) + { + } + + btScalar DeepestNotMeContactTestResultCallback::addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) + { + const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; + if (collisionObject != mMe) + { + if (!mTargets.empty()) + { + if ((std::find(mTargets.begin(), mTargets.end(), collisionObject) == mTargets.end())) + { + PtrHolder* holder = static_cast(collisionObject->getUserPointer()); + if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor()) + return 0.f; + } + } + + btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); + if(!mObject || distsqr < mLeastDistSqr) + { + mObject = collisionObject; + mLeastDistSqr = distsqr; + mContactPoint = cp.getPositionWorldOnA(); + } + } + + return 0.f; + } +} diff --git a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp new file mode 100644 index 0000000000..2fcef66db3 --- /dev/null +++ b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_MWPHYSICS_DEEPESTNOTMECONTACTTESTRESULTCALLBACK_H +#define OPENMW_MWPHYSICS_DEEPESTNOTMECONTACTTESTRESULTCALLBACK_H + +#include + +#include +#include + +namespace MWPhysics +{ + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + const btCollisionObject* mMe; + const std::vector mTargets; + + // Store the real origin, since the shape's origin is its center + btVector3 mOrigin; + + public: + const btCollisionObject *mObject{nullptr}; + btVector3 mContactPoint{0,0,0}; + btScalar mLeastDistSqr; + + DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3 &origin); + + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1); + }; +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 69177d95d3..0ff433aa4a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -46,6 +46,7 @@ #include "object.hpp" #include "heightfield.hpp" #include "hasspherecollisioncallback.hpp" +#include "deepestnotmecontacttestresultcallback.hpp" namespace MWPhysics { @@ -646,54 +647,6 @@ namespace MWPhysics return true; } - class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback - { - const btCollisionObject* mMe; - const std::vector mTargets; - - // Store the real origin, since the shape's origin is its center - btVector3 mOrigin; - - public: - const btCollisionObject *mObject; - btVector3 mContactPoint; - btScalar mLeastDistSqr; - - DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3 &origin) - : mMe(me), mTargets(targets), mOrigin(origin), mObject(nullptr), mContactPoint(0,0,0), - mLeastDistSqr(std::numeric_limits::max()) - { } - - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) - { - const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; - if (collisionObject != mMe) - { - if (!mTargets.empty()) - { - if ((std::find(mTargets.begin(), mTargets.end(), collisionObject) == mTargets.end())) - { - PtrHolder* holder = static_cast(collisionObject->getUserPointer()); - if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor()) - return 0.f; - } - } - - btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); - if(!mObject || distsqr < mLeastDistSqr) - { - mObject = collisionObject; - mLeastDistSqr = distsqr; - mContactPoint = cp.getPositionWorldOnA(); - } - } - - return 0.f; - } - }; - std::pair PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor, const osg::Vec3f &origin, const osg::Quat &orient, From c94cd775bf9103c2f488216771131f3ae380804b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 30 Mar 2020 21:45:38 +0300 Subject: [PATCH 3/8] Separate ClosestNotMeRayResultCallback --- .../closestnotmerayresultcallback.cpp | 34 +++++++++++++++++++ .../closestnotmerayresultcallback.hpp | 24 +++++++++++++ apps/openmw/mwphysics/physicssystem.cpp | 30 +--------------- 3 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 apps/openmw/mwphysics/closestnotmerayresultcallback.cpp create mode 100644 apps/openmw/mwphysics/closestnotmerayresultcallback.hpp diff --git a/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp b/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp new file mode 100644 index 0000000000..86763a7933 --- /dev/null +++ b/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp @@ -0,0 +1,34 @@ +#include "closestnotmerayresultcallback.hpp" + +#include + +#include + +#include "../mwworld/class.hpp" + +#include "ptrholder.hpp" + +namespace MWPhysics +{ + ClosestNotMeRayResultCallback::ClosestNotMeRayResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3& from, const btVector3& to) + : btCollisionWorld::ClosestRayResultCallback(from, to) + , mMe(me), mTargets(targets) + { + } + + btScalar ClosestNotMeRayResultCallback::addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) + { + if (rayResult.m_collisionObject == mMe) + return 1.f; + if (!mTargets.empty()) + { + if ((std::find(mTargets.begin(), mTargets.end(), rayResult.m_collisionObject) == mTargets.end())) + { + PtrHolder* holder = static_cast(rayResult.m_collisionObject->getUserPointer()); + if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor()) + return 1.f; + } + } + return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); + } +} diff --git a/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp b/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp new file mode 100644 index 0000000000..3d2c5704b2 --- /dev/null +++ b/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_MWPHYSICS_CLOSESTNOTMERAYRESULTCALLBACK_H +#define OPENMW_MWPHYSICS_CLOSESTNOTMERAYRESULTCALLBACK_H + +#include + +#include + +class btCollisionObject; + +namespace MWPhysics +{ + class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback + { + public: + ClosestNotMeRayResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3& from, const btVector3& to); + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace); + private: + const btCollisionObject* mMe; + const std::vector mTargets; + }; +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 0ff433aa4a..73284cd7fa 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -47,6 +47,7 @@ #include "heightfield.hpp" #include "hasspherecollisioncallback.hpp" #include "deepestnotmecontacttestresultcallback.hpp" +#include "closestnotmerayresultcallback.hpp" namespace MWPhysics { @@ -737,35 +738,6 @@ namespace MWPhysics return (point - Misc::Convert::toOsg(cb.m_hitPointWorld)).length(); } - class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback - { - public: - ClosestNotMeRayResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3& from, const btVector3& to) - : btCollisionWorld::ClosestRayResultCallback(from, to) - , mMe(me), mTargets(targets) - { - } - - virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) - { - if (rayResult.m_collisionObject == mMe) - return 1.f; - if (!mTargets.empty()) - { - if ((std::find(mTargets.begin(), mTargets.end(), rayResult.m_collisionObject) == mTargets.end())) - { - PtrHolder* holder = static_cast(rayResult.m_collisionObject->getUserPointer()); - if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor()) - return 1.f; - } - } - return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); - } - private: - const btCollisionObject* mMe; - const std::vector mTargets; - }; - PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore, std::vector targets, int mask, int group) const { btVector3 btFrom = Misc::Convert::toBullet(from); From 5d625c12dc052c0db9aea2ed092aa3266d989733 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 30 Mar 2020 21:49:47 +0300 Subject: [PATCH 4/8] Separate ContactTestResultCallback --- .../mwphysics/contacttestresultcallback.cpp | 27 +++++++++++++++++ .../mwphysics/contacttestresultcallback.hpp | 30 +++++++++++++++++++ apps/openmw/mwphysics/physicssystem.cpp | 27 +---------------- 3 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 apps/openmw/mwphysics/contacttestresultcallback.cpp create mode 100644 apps/openmw/mwphysics/contacttestresultcallback.hpp diff --git a/apps/openmw/mwphysics/contacttestresultcallback.cpp b/apps/openmw/mwphysics/contacttestresultcallback.cpp new file mode 100644 index 0000000000..f8209e3636 --- /dev/null +++ b/apps/openmw/mwphysics/contacttestresultcallback.cpp @@ -0,0 +1,27 @@ +#include "contacttestresultcallback.hpp" + +#include + +#include "ptrholder.hpp" + +namespace MWPhysics +{ + ContactTestResultCallback::ContactTestResultCallback(const btCollisionObject* testedAgainst) + : mTestedAgainst(testedAgainst) + { + } + + btScalar ContactTestResultCallback::addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) + { + const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; + if (collisionObject == mTestedAgainst) + collisionObject = col1Wrap->m_collisionObject; + PtrHolder* holder = static_cast(collisionObject->getUserPointer()); + if (holder) + mResult.push_back(holder->getPtr()); + return 0.f; + } + +} diff --git a/apps/openmw/mwphysics/contacttestresultcallback.hpp b/apps/openmw/mwphysics/contacttestresultcallback.hpp new file mode 100644 index 0000000000..bb90eced0f --- /dev/null +++ b/apps/openmw/mwphysics/contacttestresultcallback.hpp @@ -0,0 +1,30 @@ +#ifndef OPENMW_MWPHYSICS_CONTACTTESTRESULTCALLBACK_H +#define OPENMW_MWPHYSICS_CONTACTTESTRESULTCALLBACK_H + +#include + +#include + +#include "../mwworld/ptr.hpp" + +class btCollisionObject; +class btCollisionObjectWrapper; + +namespace MWPhysics +{ + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + const btCollisionObject* mTestedAgainst; + + public: + ContactTestResultCallback(const btCollisionObject* testedAgainst); + + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1); + + std::vector mResult; + }; +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 73284cd7fa..bf4bd386e2 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -48,6 +48,7 @@ #include "hasspherecollisioncallback.hpp" #include "deepestnotmecontacttestresultcallback.hpp" #include "closestnotmerayresultcallback.hpp" +#include "contacttestresultcallback.hpp" namespace MWPhysics { @@ -882,32 +883,6 @@ namespace MWPhysics return osg::Vec3f(); } - class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback - { - public: - ContactTestResultCallback(const btCollisionObject* testedAgainst) - : mTestedAgainst(testedAgainst) - { - } - - const btCollisionObject* mTestedAgainst; - - std::vector mResult; - - virtual btScalar addSingleResult(btManifoldPoint& cp, - const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, - const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) - { - const btCollisionObject* collisionObject = col0Wrap->m_collisionObject; - if (collisionObject == mTestedAgainst) - collisionObject = col1Wrap->m_collisionObject; - PtrHolder* holder = static_cast(collisionObject->getUserPointer()); - if (holder) - mResult.push_back(holder->getPtr()); - return 0.f; - } - }; - std::vector PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const { btCollisionObject* me = nullptr; From ca6cce0c7e98ab43ebc5550c28c43d4ab7136706 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 30 Mar 2020 23:07:12 +0300 Subject: [PATCH 5/8] 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" From 19010ec045a5149021f1919f239f098db83af128 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 31 Mar 2020 00:05:54 +0300 Subject: [PATCH 6/8] Separate MovementSolver --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwphysics/movementsolver.cpp | 324 ++++++++++++++++++++++ apps/openmw/mwphysics/movementsolver.hpp | 40 +++ apps/openmw/mwphysics/physicssystem.cpp | 334 +---------------------- 4 files changed, 366 insertions(+), 334 deletions(-) create mode 100644 apps/openmw/mwphysics/movementsolver.cpp create mode 100644 apps/openmw/mwphysics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0472bd033c..4b74d308fb 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 stepper + contacttestresultcallback deepestnotmecontacttestresultcallback stepper movementsolver ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp new file mode 100644 index 0000000000..6345a76d97 --- /dev/null +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -0,0 +1,324 @@ +#include "movementsolver.hpp" + +#include +#include +#include + +#include +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/refdata.hpp" + +#include "actor.hpp" +#include "collisiontype.hpp" +#include "constants.hpp" +#include "stepper.hpp" +#include "trace.h" + +namespace MWPhysics +{ + 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); + } + + osg::Vec3f MovementSolver::traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight) + { + osg::Vec3f offset = actor->getCollisionObjectPosition() - ptr.getRefData().getPosition().asVec3(); + + ActorTracer tracer; + tracer.findGround(actor, position + offset, position + offset - osg::Vec3f(0,0,maxHeight), collisionWorld); + if (tracer.mFraction >= 1.0f) + { + actor->setOnGround(false); + return position; + } + + actor->setOnGround(true); + + // Check if we actually found a valid spawn point (use an infinitely thin ray this time). + // Required for some broken door destinations in Morrowind.esm, where the spawn point + // intersects with other geometry if the actor's base is taken into account + btVector3 from = Misc::Convert::toBullet(position); + btVector3 to = from - btVector3(0,0,maxHeight); + + btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); + resultCallback1.m_collisionFilterGroup = 0xff; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; + + collisionWorld->rayTest(from, to, resultCallback1); + + if (resultCallback1.hasHit() && ((Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos + offset).length2() > 35*35 + || !isWalkableSlope(tracer.mPlaneNormal))) + { + actor->setOnSlope(!isWalkableSlope(resultCallback1.m_hitNormalWorld)); + return Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); + } + + actor->setOnSlope(!isWalkableSlope(tracer.mPlaneNormal)); + + return tracer.mEndPos-offset + osg::Vec3f(0.f, 0.f, sGroundOffset); + } + + osg::Vec3f MovementSolver::move(osg::Vec3f position, const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, + bool isFlying, float waterlevel, float slowFall, const btCollisionWorld* collisionWorld, + std::map& standingCollisionTracker) + { + const ESM::Position& refpos = ptr.getRefData().getPosition(); + // Early-out for totally static creatures + // (Not sure if gravity should still apply?) + if (!ptr.getClass().isMobile(ptr)) + return position; + + // Reset per-frame data + physicActor->setWalkingOnWater(false); + // Anything to collide with? + if(!physicActor->getCollisionMode()) + { + return position + (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * + osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1)) + ) * movement * time; + } + + const btCollisionObject *colobj = physicActor->getCollisionObject(); + osg::Vec3f halfExtents = physicActor->getHalfExtents(); + + // NOTE: here we don't account for the collision box translation (i.e. physicActor->getPosition() - refpos.pos). + // That means the collision shape used for moving this actor is in a different spot than the collision shape + // other actors are using to collide against this actor. + // While this is strictly speaking wrong, it's needed for MW compatibility. + position.z() += halfExtents.z(); + + static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get().find("fSwimHeightScale")->mValue.getFloat(); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + + ActorTracer tracer; + + osg::Vec3f inertia = physicActor->getInertialForce(); + osg::Vec3f velocity; + + if (position.z() < swimlevel || isFlying) + { + velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; + } + else + { + velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; + + if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope()) + || (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope())) + inertia = velocity; + else if (!physicActor->getOnGround() || physicActor->getOnSlope()) + velocity = velocity + inertia; + } + + // dead actors underwater will float to the surface, if the CharacterController tells us to do so + if (movement.z() > 0 && ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) + velocity = osg::Vec3f(0,0,1) * 25; + + if (ptr.getClass().getMovementSettings(ptr).mPosition[2]) + { + const bool isPlayer = (ptr == MWMechanics::getPlayer()); + // Advance acrobatics and set flag for GetPCJumping + if (isPlayer) + { + ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0); + MWBase::Environment::get().getWorld()->getPlayer().setJumping(true); + } + + // Decrease fatigue + if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState()) + { + const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); + const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat(); + const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr)); + const float fatigueDecrease = fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult; + MWMechanics::DynamicStat fatigue = ptr.getClass().getCreatureStats(ptr).getFatigue(); + fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); + ptr.getClass().getCreatureStats(ptr).setFatigue(fatigue); + } + ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; + } + + // Now that we have the effective movement vector, apply wind forces to it + if (MWBase::Environment::get().getWorld()->isInStorm()) + { + osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); + static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get().find("fStromWalkMult")->mValue.getFloat(); + 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. + * nextpos is the local variable used to find potential newPosition, using velocity and remainingTime + * The initial velocity was set earlier (see above). + */ + float remainingTime = time; + for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations) + { + osg::Vec3f nextpos = newPosition + velocity * remainingTime; + + // If not able to fly, don't allow to swim up into the air + if(!isFlying && nextpos.z() > swimlevel && newPosition.z() < swimlevel) + { + const osg::Vec3f down(0,0,-1); + velocity = slide(velocity, down); + // NOTE: remainingTime is unchanged before the loop continues + continue; // velocity updated, calculate nextpos again + } + + if((newPosition - nextpos).length2() > 0.0001) + { + // trace to where character would go if there were no obstructions + tracer.doTrace(colobj, newPosition, nextpos, collisionWorld); + + // check for obstructions + if(tracer.mFraction >= 1.0f) + { + newPosition = tracer.mEndPos; // ok to move, so set newPosition + break; + } + } + else + { + // The current position and next position are nearly the same, so just exit. + // Note: Bullet can trigger an assert in debug modes if the positions + // are the same, since that causes it to attempt to normalize a zero + // length vector (which can also happen with nearly identical vectors, since + // precision can be lost due to any math Bullet does internally). Since we + // aren't performing any collision detection, we want to reject the next + // position, so that we don't slowly move inside another object. + break; + } + + // We are touching something. + if (tracer.mFraction < 1E-9f) + { + // Try to separate by backing off slighly to unstuck the solver + osg::Vec3f backOff = (newPosition - tracer.mHitPoint) * 1E-2f; + newPosition += backOff; + } + + // We hit something. Check if we can step up. + float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z(); + osg::Vec3f oldPosition = newPosition; + bool result = false; + if (hitHeight < sStepSizeUp && !isActor(tracer.mHitObject)) + { + // 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 + if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z() + halfExtents.z() > waterlevel) + newPosition = oldPosition; + } + else + { + // Can't move this way, try to find another spot along the plane + osg::Vec3f newVelocity = slide(velocity, tracer.mPlaneNormal); + + // 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 ((newVelocity * origVelocity) <= 0.f) + break; // ^ dot product + + velocity = newVelocity; + } + } + + bool isOnGround = false; + bool isOnSlope = false; + if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel)) + { + osg::Vec3f from = newPosition; + osg::Vec3f to = newPosition - (physicActor->getOnGround() ? osg::Vec3f(0,0,sStepSizeDown + 2*sGroundOffset) : osg::Vec3f(0,0,2*sGroundOffset)); + tracer.doTrace(colobj, from, to, collisionWorld); + if(tracer.mFraction < 1.0f && !isActor(tracer.mHitObject)) + { + const btCollisionObject* standingOn = tracer.mHitObject; + PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); + if (ptrHolder) + standingCollisionTracker[ptr] = ptrHolder->getPtr(); + + if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) + physicActor->setWalkingOnWater(true); + if (!isFlying) + newPosition.z() = tracer.mEndPos.z() + sGroundOffset; + + isOnGround = true; + + isOnSlope = !isWalkableSlope(tracer.mPlaneNormal); + } + else + { + // standing on actors is not allowed (see above). + // in addition to that, apply a sliding effect away from the center of the actor, + // so that we do not stay suspended in air indefinitely. + if (tracer.mFraction < 1.0f && isActor(tracer.mHitObject)) + { + if (osg::Vec3f(velocity.x(), velocity.y(), 0).length2() < 100.f*100.f) + { + btVector3 aabbMin, aabbMax; + tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); + btVector3 center = (aabbMin + aabbMax) / 2.f; + inertia = osg::Vec3f(position.x() - center.x(), position.y() - center.y(), 0); + inertia.normalize(); + inertia *= 100; + } + } + + isOnGround = false; + } + } + + if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || isFlying) + physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f)); + else + { + inertia.z() -= time * Constants::GravityConst * Constants::UnitsPerMeter; + if (inertia.z() < 0) + inertia.z() *= slowFall; + if (slowFall < 1.f) { + inertia.x() *= slowFall; + inertia.y() *= slowFall; + } + physicActor->setInertialForce(inertia); + } + physicActor->setOnGround(isOnGround); + physicActor->setOnSlope(isOnSlope); + + newPosition.z() -= halfExtents.z(); // remove what was added at the beginning + return newPosition; + } +} diff --git a/apps/openmw/mwphysics/movementsolver.hpp b/apps/openmw/mwphysics/movementsolver.hpp new file mode 100644 index 0000000000..54a417fa75 --- /dev/null +++ b/apps/openmw/mwphysics/movementsolver.hpp @@ -0,0 +1,40 @@ +#ifndef OPENMW_MWPHYSICS_MOVEMENTSOLVER_H +#define OPENMW_MWPHYSICS_MOVEMENTSOLVER_H + +#include + +#include + +#include "../mwworld/ptr.hpp" + +class btCollisionWorld; + +namespace MWPhysics +{ + class Actor; + + class MovementSolver + { + private: + ///Project a vector u on another vector v + static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v) + { + return v * (u * v); + // ^ dot product + } + + ///Helper for computing the character sliding + static inline osg::Vec3f slide(const osg::Vec3f& direction, const osg::Vec3f &planeNormal) + { + return direction - project(direction, planeNormal); + } + + public: + static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight); + static osg::Vec3f move(osg::Vec3f position, const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, + bool isFlying, float waterlevel, float slowFall, const btCollisionWorld* collisionWorld, + std::map& standingCollisionTracker); + }; +} + +#endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 908ec90f3b..a205abeb46 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -29,12 +29,10 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/movement.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/player.hpp" #include "../mwrender/bulletdebugdraw.hpp" @@ -49,341 +47,11 @@ #include "deepestnotmecontacttestresultcallback.hpp" #include "closestnotmerayresultcallback.hpp" #include "contacttestresultcallback.hpp" -#include "stepper.hpp" #include "constants.hpp" +#include "movementsolver.hpp" namespace MWPhysics { - 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); - } - - class MovementSolver - { - private: - ///Project a vector u on another vector v - static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v) - { - return v * (u * v); - // ^ dot product - } - - ///Helper for computing the character sliding - static inline osg::Vec3f slide(const osg::Vec3f& direction, const osg::Vec3f &planeNormal) - { - return direction - project(direction, planeNormal); - } - - public: - static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight) - { - osg::Vec3f offset = actor->getCollisionObjectPosition() - ptr.getRefData().getPosition().asVec3(); - - ActorTracer tracer; - tracer.findGround(actor, position + offset, position + offset - osg::Vec3f(0,0,maxHeight), collisionWorld); - if(tracer.mFraction >= 1.0f) - { - actor->setOnGround(false); - return position; - } - else - { - actor->setOnGround(true); - - // Check if we actually found a valid spawn point (use an infinitely thin ray this time). - // Required for some broken door destinations in Morrowind.esm, where the spawn point - // intersects with other geometry if the actor's base is taken into account - btVector3 from = Misc::Convert::toBullet(position); - btVector3 to = from - btVector3(0,0,maxHeight); - - btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterGroup = 0xff; - resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; - - collisionWorld->rayTest(from, to, resultCallback1); - - if (resultCallback1.hasHit() && - ( (Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) - (tracer.mEndPos-offset)).length2() > 35*35 - || !isWalkableSlope(tracer.mPlaneNormal))) - { - actor->setOnSlope(!isWalkableSlope(resultCallback1.m_hitNormalWorld)); - return Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); - } - else - { - actor->setOnSlope(!isWalkableSlope(tracer.mPlaneNormal)); - } - - return tracer.mEndPos-offset + osg::Vec3f(0.f, 0.f, sGroundOffset); - } - } - - static osg::Vec3f move(osg::Vec3f position, const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, const btCollisionWorld* collisionWorld, - std::map& standingCollisionTracker) - { - const ESM::Position& refpos = ptr.getRefData().getPosition(); - // Early-out for totally static creatures - // (Not sure if gravity should still apply?) - if (!ptr.getClass().isMobile(ptr)) - return position; - - // Reset per-frame data - physicActor->setWalkingOnWater(false); - // Anything to collide with? - if(!physicActor->getCollisionMode()) - { - return position + (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * - osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1)) - ) * movement * time; - } - - const btCollisionObject *colobj = physicActor->getCollisionObject(); - osg::Vec3f halfExtents = physicActor->getHalfExtents(); - - // NOTE: here we don't account for the collision box translation (i.e. physicActor->getPosition() - refpos.pos). - // That means the collision shape used for moving this actor is in a different spot than the collision shape - // other actors are using to collide against this actor. - // While this is strictly speaking wrong, it's needed for MW compatibility. - position.z() += halfExtents.z(); - - static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() - .find("fSwimHeightScale")->mValue.getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); - - ActorTracer tracer; - - osg::Vec3f inertia = physicActor->getInertialForce(); - osg::Vec3f velocity; - - if(position.z() < swimlevel || isFlying) - { - velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * - osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; - } - else - { - velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; - - if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope()) - || (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope())) - inertia = velocity; - else if (!physicActor->getOnGround() || physicActor->getOnSlope()) - velocity = velocity + inertia; - } - - // dead actors underwater will float to the surface, if the CharacterController tells us to do so - if (movement.z() > 0 && ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) - velocity = osg::Vec3f(0,0,1) * 25; - - if (ptr.getClass().getMovementSettings(ptr).mPosition[2]) - { - const bool isPlayer = (ptr == MWMechanics::getPlayer()); - // Advance acrobatics and set flag for GetPCJumping - if (isPlayer) - { - ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0); - MWBase::Environment::get().getWorld()->getPlayer().setJumping(true); - } - - // Decrease fatigue - if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState()) - { - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); - const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat(); - const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr)); - const float fatigueDecrease = fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult; - MWMechanics::DynamicStat fatigue = ptr.getClass().getCreatureStats(ptr).getFatigue(); - fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); - ptr.getClass().getCreatureStats(ptr).setFatigue(fatigue); - } - ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; - } - - // Now that we have the effective movement vector, apply wind forces to it - if (MWBase::Environment::get().getWorld()->isInStorm()) - { - osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); - float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); - static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get() - .find("fStromWalkMult")->mValue.getFloat(); - 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. - * nextpos is the local variable used to find potential newPosition, using velocity and remainingTime - * The initial velocity was set earlier (see above). - */ - float remainingTime = time; - for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations) - { - osg::Vec3f nextpos = newPosition + velocity * remainingTime; - - // If not able to fly, don't allow to swim up into the air - if(!isFlying && // can't fly - nextpos.z() > swimlevel && // but about to go above water - newPosition.z() < swimlevel) - { - const osg::Vec3f down(0,0,-1); - velocity = slide(velocity, down); - // NOTE: remainingTime is unchanged before the loop continues - continue; // velocity updated, calculate nextpos again - } - - if((newPosition - nextpos).length2() > 0.0001) - { - // trace to where character would go if there were no obstructions - tracer.doTrace(colobj, newPosition, nextpos, collisionWorld); - - // check for obstructions - if(tracer.mFraction >= 1.0f) - { - newPosition = tracer.mEndPos; // ok to move, so set newPosition - break; - } - } - else - { - // The current position and next position are nearly the same, so just exit. - // Note: Bullet can trigger an assert in debug modes if the positions - // are the same, since that causes it to attempt to normalize a zero - // length vector (which can also happen with nearly identical vectors, since - // precision can be lost due to any math Bullet does internally). Since we - // aren't performing any collision detection, we want to reject the next - // position, so that we don't slowly move inside another object. - break; - } - - // We are touching something. - if (tracer.mFraction < 1E-9f) - { - // Try to separate by backing off slighly to unstuck the solver - osg::Vec3f backOff = (newPosition - tracer.mHitPoint) * 1E-2f; - newPosition += backOff; - } - - // We hit something. Check if we can step up. - float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z(); - osg::Vec3f oldPosition = newPosition; - bool result = false; - if (hitHeight < sStepSizeUp && !isActor(tracer.mHitObject)) - { - // 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 - if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + halfExtents.z() > waterlevel) - newPosition = oldPosition; - } - else - { - // Can't move this way, try to find another spot along the plane - osg::Vec3f newVelocity = slide(velocity, tracer.mPlaneNormal); - - // 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 ((newVelocity * origVelocity) <= 0.f) - break; // ^ dot product - - velocity = newVelocity; - } - } - - bool isOnGround = false; - bool isOnSlope = false; - if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel)) - { - osg::Vec3f from = newPosition; - osg::Vec3f to = newPosition - (physicActor->getOnGround() ? - osg::Vec3f(0,0,sStepSizeDown + 2*sGroundOffset) : osg::Vec3f(0,0,2*sGroundOffset)); - tracer.doTrace(colobj, from, to, collisionWorld); - if(tracer.mFraction < 1.0f - && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) - { - const btCollisionObject* standingOn = tracer.mHitObject; - PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); - if (ptrHolder) - standingCollisionTracker[ptr] = ptrHolder->getPtr(); - - if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) - physicActor->setWalkingOnWater(true); - if (!isFlying) - newPosition.z() = tracer.mEndPos.z() + sGroundOffset; - - isOnGround = true; - - isOnSlope = !isWalkableSlope(tracer.mPlaneNormal); - } - else - { - // standing on actors is not allowed (see above). - // in addition to that, apply a sliding effect away from the center of the actor, - // so that we do not stay suspended in air indefinitely. - if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) - { - if (osg::Vec3f(velocity.x(), velocity.y(), 0).length2() < 100.f*100.f) - { - btVector3 aabbMin, aabbMax; - tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); - btVector3 center = (aabbMin + aabbMax) / 2.f; - inertia = osg::Vec3f(position.x() - center.x(), position.y() - center.y(), 0); - inertia.normalize(); - inertia *= 100; - } - } - - isOnGround = false; - } - } - - if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || isFlying) - physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f)); - else - { - inertia.z() -= time * Constants::GravityConst * Constants::UnitsPerMeter; - if (inertia.z() < 0) - inertia.z() *= slowFall; - if (slowFall < 1.f) { - inertia.x() *= slowFall; - inertia.y() *= slowFall; - } - physicActor->setInertialForce(inertia); - } - physicActor->setOnGround(isOnGround); - physicActor->setOnSlope(isOnSlope); - - newPosition.z() -= halfExtents.z(); // remove what was added at the beginning - return newPosition; - } - }; - - - // --------------------------------------------------------------- - - PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) : mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager(), resourceSystem->getNifFileManager())) , mResourceSystem(resourceSystem) From 4f08f6e09bb51d0a5cd0513a4421e1ab50209e92 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 31 Mar 2020 00:25:33 +0300 Subject: [PATCH 7/8] Separate ClosestNotMeConvexResultCallback --- apps/openmw/CMakeLists.txt | 1 + .../closestnotmeconvexresultcallback.cpp | 34 ++++++++++++++++ .../closestnotmeconvexresultcallback.hpp | 24 ++++++++++++ .../deepestnotmecontacttestresultcallback.cpp | 2 + .../deepestnotmecontacttestresultcallback.hpp | 3 +- apps/openmw/mwphysics/trace.cpp | 39 +------------------ 6 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 apps/openmw/mwphysics/closestnotmeconvexresultcallback.cpp create mode 100644 apps/openmw/mwphysics/closestnotmeconvexresultcallback.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4b74d308fb..44f37dac0c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -72,6 +72,7 @@ add_openmw_dir (mwworld add_openmw_dir (mwphysics physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback contacttestresultcallback deepestnotmecontacttestresultcallback stepper movementsolver + closestnotmeconvexresultcallback ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwphysics/closestnotmeconvexresultcallback.cpp b/apps/openmw/mwphysics/closestnotmeconvexresultcallback.cpp new file mode 100644 index 0000000000..ddfdb8a42f --- /dev/null +++ b/apps/openmw/mwphysics/closestnotmeconvexresultcallback.cpp @@ -0,0 +1,34 @@ +#include "closestnotmeconvexresultcallback.hpp" + +#include + +namespace MWPhysics +{ + ClosestNotMeConvexResultCallback::ClosestNotMeConvexResultCallback(const btCollisionObject *me, const btVector3 &motion, btScalar minCollisionDot) + : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), + mMe(me), mMotion(motion), mMinCollisionDot(minCollisionDot) + { + } + + btScalar ClosestNotMeConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) + { + if (convexResult.m_hitCollisionObject == mMe) + return btScalar(1); + + btVector3 hitNormalWorld; + if (normalInWorldSpace) + hitNormalWorld = convexResult.m_hitNormalLocal; + else + { + ///need to transform normal into worldspace + hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; + } + + // dot product of the motion vector against the collision contact normal + btScalar dotCollision = mMotion.dot(hitNormalWorld); + if (dotCollision <= mMinCollisionDot) + return btScalar(1); + + return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); + } +} diff --git a/apps/openmw/mwphysics/closestnotmeconvexresultcallback.hpp b/apps/openmw/mwphysics/closestnotmeconvexresultcallback.hpp new file mode 100644 index 0000000000..e4e960ab81 --- /dev/null +++ b/apps/openmw/mwphysics/closestnotmeconvexresultcallback.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_MWPHYSICS_CLOSESTNOTMECONVEXRESULTCALLBACK_H +#define OPENMW_MWPHYSICS_CLOSESTNOTMECONVEXRESULTCALLBACK_H + +#include + +class btCollisionObject; + +namespace MWPhysics +{ + class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback + { + public: + ClosestNotMeConvexResultCallback(const btCollisionObject *me, const btVector3 &motion, btScalar minCollisionDot); + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace); + + protected: + const btCollisionObject *mMe; + const btVector3 mMotion; + const btScalar mMinCollisionDot; + }; +} + +#endif diff --git a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp index be94128c18..0baaa62417 100644 --- a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp +++ b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwworld/class.hpp" #include "ptrholder.hpp" diff --git a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp index 2fcef66db3..f1107046b1 100644 --- a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp +++ b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp @@ -3,9 +3,10 @@ #include -#include #include +class btCollisionObject; + namespace MWPhysics { class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 13bc7f7983..58082f4db2 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -7,48 +7,11 @@ #include "collisiontype.hpp" #include "actor.hpp" +#include "closestnotmeconvexresultcallback.hpp" namespace MWPhysics { -class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback -{ -public: - ClosestNotMeConvexResultCallback(const btCollisionObject *me, const btVector3 &motion, btScalar minCollisionDot) - : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), - mMe(me), mMotion(motion), mMinCollisionDot(minCollisionDot) - { - } - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) - { - if(convexResult.m_hitCollisionObject == mMe) - return btScalar( 1 ); - - btVector3 hitNormalWorld; - if(normalInWorldSpace) - hitNormalWorld = convexResult.m_hitNormalLocal; - else - { - ///need to transform normal into worldspace - hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; - } - - // dot product of the motion vector against the collision contact normal - btScalar dotCollision = mMotion.dot(hitNormalWorld); - if(dotCollision <= mMinCollisionDot) - return btScalar(1); - - return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - } - -protected: - const btCollisionObject *mMe; - const btVector3 mMotion; - const btScalar mMinCollisionDot; -}; - - void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world) { const btVector3 btstart = Misc::Convert::toBullet(start); From 5e2e5b7aa9e2f8c5da97c9c0815f2d84fccd8593 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 31 Mar 2020 18:31:46 +0300 Subject: [PATCH 8/8] Fix btCollisionObjectWrapper forward declaration --- apps/openmw/mwphysics/contacttestresultcallback.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/contacttestresultcallback.hpp b/apps/openmw/mwphysics/contacttestresultcallback.hpp index bb90eced0f..0f469127db 100644 --- a/apps/openmw/mwphysics/contacttestresultcallback.hpp +++ b/apps/openmw/mwphysics/contacttestresultcallback.hpp @@ -8,7 +8,7 @@ #include "../mwworld/ptr.hpp" class btCollisionObject; -class btCollisionObjectWrapper; +struct btCollisionObjectWrapper; namespace MWPhysics {