diff --git a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp index 0baaa62417..7744af14b5 100644 --- a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp +++ b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.cpp @@ -39,6 +39,7 @@ namespace MWPhysics mObject = collisionObject; mLeastDistSqr = distsqr; mContactPoint = cp.getPositionWorldOnA(); + mContactNormal = cp.m_normalWorldOnB; } } diff --git a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp index 9b2e97e657..00cb5c01f7 100644 --- a/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp +++ b/apps/openmw/mwphysics/deepestnotmecontacttestresultcallback.hpp @@ -20,6 +20,7 @@ namespace MWPhysics public: const btCollisionObject *mObject{nullptr}; btVector3 mContactPoint{0,0,0}; + btVector3 mContactNormal{0,0,0}; btScalar mLeastDistSqr; DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3 &origin); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index a349ee2447..513e8d59b4 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,5 +1,8 @@ #include "physicssystem.hpp" +#include +#include +#include #include #include @@ -90,6 +93,7 @@ namespace MWPhysics } mTaskScheduler = std::make_unique(mPhysicsDt, mCollisionWorld); + mDebugDrawer = std::make_unique(mParentNode, mCollisionWorld.get()); } PhysicsSystem::~PhysicsSystem() @@ -124,14 +128,8 @@ namespace MWPhysics { mDebugDrawEnabled = !mDebugDrawEnabled; - if (mDebugDrawEnabled && !mDebugDrawer) - { - mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mCollisionWorld.get())); - mCollisionWorld->setDebugDrawer(mDebugDrawer.get()); - mDebugDrawer->setDebugMode(mDebugDrawEnabled); - } - else if (mDebugDrawer) - mDebugDrawer->setDebugMode(mDebugDrawEnabled); + mCollisionWorld->setDebugDrawer(mDebugDrawEnabled ? mDebugDrawer.get() : nullptr); + mDebugDrawer->setDebugMode(mDebugDrawEnabled); return mDebugDrawEnabled; } @@ -175,6 +173,7 @@ namespace MWPhysics if (result.mHit) { + reportCollision(Misc::Convert::toBullet(result.mHitPos), Misc::Convert::toBullet(result.mHitNormal)); return std::make_pair(result.mHitObject, result.mHitPos); } @@ -219,7 +218,10 @@ namespace MWPhysics { PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); if (holder) + { + reportCollision(resultCallback.mContactPoint, resultCallback.mContactNormal); return std::make_pair(holder->getPtr(), Misc::Convert::toOsg(resultCallback.mContactPoint)); + } } return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } @@ -758,7 +760,7 @@ namespace MWPhysics void PhysicsSystem::debugDraw() { - if (mDebugDrawer) + if (mDebugDrawEnabled) mDebugDrawer->step(); } @@ -864,6 +866,12 @@ namespace MWPhysics stats.setAttribute(frameNumber, "Physics HeightFields", mHeightFields.size()); } + void PhysicsSystem::reportCollision(const btVector3& position, const btVector3& normal) + { + if (mDebugDrawEnabled) + mDebugDrawer->addCollision(position, normal); + } + ActorFrameData::ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel) : mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn), diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 96aba99c45..31707465b9 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -45,6 +45,7 @@ class btDefaultCollisionConfiguration; class btCollisionDispatcher; class btCollisionObject; class btCollisionShape; +class btVector3; namespace MWPhysics { @@ -232,6 +233,7 @@ namespace MWPhysics bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + void reportCollision(const btVector3& position, const btVector3& normal); private: diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 4cf76e473a..61570be452 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -1,4 +1,4 @@ -#include "bulletdebugdraw.hpp" +#include #include @@ -6,17 +6,11 @@ #include #include +#include +#include "bulletdebugdraw.hpp" #include "vismask.hpp" -namespace -{ - osg::Vec3f toOsg(const btVector3& vec) - { - return osg::Vec3f(vec.x(), vec.y(), vec.z()); - } -} - namespace MWRender { @@ -37,11 +31,14 @@ void DebugDrawer::createGeometry() mGeometry->setNodeMask(Mask_Debug); mVertices = new osg::Vec3Array; + mColors = new osg::Vec4Array; mDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); mGeometry->setUseDisplayList(false); mGeometry->setVertexArray(mVertices); + mGeometry->setColorArray(mColors); + mGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); mGeometry->setDataVariance(osg::Object::DYNAMIC); mGeometry->addPrimitiveSet(mDrawArrays); @@ -70,23 +67,53 @@ void DebugDrawer::step() if (mDebugOn) { mVertices->clear(); + mColors->clear(); mWorld->debugDrawWorld(); + showCollisions(); mDrawArrays->setCount(mVertices->size()); mVertices->dirty(); + mColors->dirty(); mGeometry->dirtyBound(); } } void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) { - mVertices->push_back(toOsg(from)); - mVertices->push_back(toOsg(to)); + mVertices->push_back(Misc::Convert::toOsg(from)); + mVertices->push_back(Misc::Convert::toOsg(to)); + mColors->push_back({1,1,1,1}); + mColors->push_back({1,1,1,1}); +} + +void DebugDrawer::addCollision(const btVector3& orig, const btVector3& normal) +{ + mCollisionViews.emplace_back(orig, normal); +} + +void DebugDrawer::showCollisions() +{ + const auto now = std::chrono::steady_clock::now(); + for (auto& [from, to , created] : mCollisionViews) + { + if (now - created < std::chrono::seconds(2)) + { + mVertices->push_back(Misc::Convert::toOsg(from)); + mVertices->push_back(Misc::Convert::toOsg(to)); + mColors->push_back({1,0,0,1}); + mColors->push_back({1,0,0,1}); + } + } + mCollisionViews.erase(std::remove_if(mCollisionViews.begin(), mCollisionViews.end(), + [&now](const CollisionView& view) { return now - view.mCreated >= std::chrono::seconds(2); }), + mCollisionViews.end()); } void DebugDrawer::drawContactPoint(const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color) { - mVertices->push_back(toOsg(PointOnB)); - mVertices->push_back(toOsg(PointOnB) + (toOsg(normalOnB) * distance * 20)); + mVertices->push_back(Misc::Convert::toOsg(PointOnB)); + mVertices->push_back(Misc::Convert::toOsg(PointOnB) + (Misc::Convert::toOsg(normalOnB) * distance * 20)); + mColors->push_back({1,1,1,1}); + mColors->push_back({1,1,1,1}); } void DebugDrawer::reportErrorWarning(const char *warningString) @@ -96,7 +123,7 @@ void DebugDrawer::reportErrorWarning(const char *warningString) void DebugDrawer::setDebugMode(int isOn) { - mDebugOn = (isOn == 0) ? false : true; + mDebugOn = (isOn != 0); if (!mDebugOn) destroyGeometry(); @@ -109,6 +136,4 @@ int DebugDrawer::getDebugMode() const return mDebugOn; } - - } diff --git a/apps/openmw/mwrender/bulletdebugdraw.hpp b/apps/openmw/mwrender/bulletdebugdraw.hpp index 30cabc4f94..f07ce2e2ed 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.hpp +++ b/apps/openmw/mwrender/bulletdebugdraw.hpp @@ -1,6 +1,9 @@ #ifndef OPENMW_MWRENDER_BULLETDEBUGDRAW_H #define OPENMW_MWRENDER_BULLETDEBUGDRAW_H +#include +#include + #include #include #include @@ -20,11 +23,22 @@ namespace MWRender class DebugDrawer : public btIDebugDraw { +private: + struct CollisionView + { + btVector3 mOrig; + btVector3 mEnd; + std::chrono::time_point mCreated; + CollisionView(btVector3 orig, btVector3 normal) : mOrig(orig), mEnd(orig + normal * 20), mCreated(std::chrono::steady_clock::now()) {}; + }; + std::vector mCollisionViews; + protected: osg::ref_ptr mParentNode; btCollisionWorld *mWorld; osg::ref_ptr mGeometry; osg::ref_ptr mVertices; + osg::ref_ptr mColors; osg::ref_ptr mDrawArrays; bool mDebugOn; @@ -41,6 +55,10 @@ public: void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) override; + void addCollision(const btVector3& orig, const btVector3& normal); + + void showCollisions(); + void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) override; void reportErrorWarning(const char* warningString) override; diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1f04ff0e04..39cdc3e722 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -442,6 +443,7 @@ namespace MWWorld cast.mSourceName = it->mSourceName; cast.mStack = false; cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true); + mPhysics->reportCollision(Misc::Convert::toBullet(result.mHitPos), Misc::Convert::toBullet(result.mHitNormal)); } } @@ -522,6 +524,7 @@ namespace MWWorld caster = result.mHitObject; MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHit ? result.mHitPos : newPos, it->mAttackStrength); + mPhysics->reportCollision(Misc::Convert::toBullet(result.mHitPos), Misc::Convert::toBullet(result.mHitNormal)); if (underwater) mRendering->emitWaterRipple(newPos);