diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 60a9b22a3f..236e9c5df5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -322,10 +322,9 @@ void RenderingManager::update (float duration, bool paused) btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = mPhysicsEngine->rayTest(btOrig, btDest); - if (!test.first.empty()) { + std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest); + if (test.first) mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); - } } mOcclusionQuery->update(duration); diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index ce32b79e53..dac8f97dbd 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -33,23 +33,23 @@ namespace MWWorld class MovementSolver { private: - static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, + static bool stepMove(Ogre::Vector3& position, const Ogre::Quaternion& orient, const Ogre::Vector3 &velocity, float remainingTime, const Ogre::Vector3 &halfExtents, bool isInterior, OEngine::Physic::PhysicEngine *engine) { traceResults trace; // no initialization needed - newtrace(&trace, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + newtrace(&trace, orient, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); if(trace.fraction == 0.0f) return false; - newtrace(&trace, trace.endpos, trace.endpos + velocity*remainingTime, + newtrace(&trace, orient, trace.endpos, trace.endpos + velocity*remainingTime, halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); + newtrace(&trace, orient, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); if(getSlope(trace.planenormal) <= sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -111,15 +111,9 @@ namespace MWWorld traceResults trace; //no initialization needed int maxHeight = 400.f; - int steps = 100; - for (int i=0; isetOnGround(hit); @@ -154,7 +148,7 @@ namespace MWWorld bool isInterior = !ptr.getCell()->isExterior(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); physicActor->enableCollisions(false); - + Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); Ogre::Vector3 velocity; if(!gravity) { @@ -167,7 +161,7 @@ namespace MWWorld { if(!(movement.z > 0.0f)) { - newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, isInterior, engine); + newtrace(&trace, orient, position, position-Ogre::Vector3(0,0,4), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } @@ -188,7 +182,7 @@ namespace MWWorld int iterations = 0; do { // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); + newtrace(&trace, orient, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; remainingTime = remainingTime * (1.0f-trace.fraction); @@ -207,7 +201,7 @@ namespace MWWorld { // Can't walk on this. Try to step up onto it. if((gravity && !onground) || - !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) + !stepMove(newPosition, orient, velocity, remainingTime, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = trace.planenormal.crossProduct(up); resultantDirection.normalise(); @@ -225,7 +219,7 @@ namespace MWWorld if(onground) { - newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, isInterior, engine); + newtrace(&trace, orient, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) newPosition.z = trace.endpos.z + 2.0f; else diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a903369eec..4d71f62b09 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -973,6 +973,8 @@ namespace MWWorld if(duration <= 0.0f) return; + processDoors(duration); + PtrMovementList::const_iterator player(actors.end()); for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++) { @@ -998,8 +1000,6 @@ namespace MWWorld moveObjectImp(player->first, vec.x, vec.y, vec.z); } - processDoors(duration); - mPhysEngine->stepSimulation (duration); } @@ -1022,6 +1022,7 @@ namespace MWWorld mPhysics->getObjectAABB(it->first, min, max); Ogre::Vector3 dimensions = max-min; + /// \todo should use convexSweepTest here std::vector collisions = mPhysics->getCollisions(it->first); for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index dbb42a6456..def69a2e8a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -622,6 +622,41 @@ namespace Physic return std::pair(name,d); } + // callback that ignores player in results + struct OurClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback + { + public: + OurClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld) + : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld) {} + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) + { + if (const RigidBody* body = dynamic_cast(convexResult.m_hitCollisionObject)) + if (body->mName == "player") + return 0; + return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); + } + }; + + std::pair PhysicEngine::sphereCast (float radius, btVector3& from, btVector3& to) + { + OurClosestConvexResultCallback callback(from, to); + callback.m_collisionFilterMask = OEngine::Physic::CollisionType_World; + + btSphereShape shape(radius); + const btQuaternion btrot(0.0f, 0.0f, 0.0f); + + btTransform from_ (btrot, from); + btTransform to_ (btrot, to); + + dynamicsWorld->convexSweepTest(&shape, from_, to_, callback); + + if (callback.hasHit()) + return std::make_pair(true, callback.m_closestHitFraction); + else + return std::make_pair(false, 1); + } + std::vector< std::pair > PhysicEngine::rayTest2(btVector3& from, btVector3& to) { MyRayResultCallback resultCallback1; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6d88fcb559..8b246408a6 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -298,6 +298,9 @@ namespace Physic */ std::vector< std::pair > rayTest2(btVector3& from, btVector3& to); + std::pair sphereCast (float radius, btVector3& from, btVector3& to); + ///< @return (hit, relative distance) + std::vector getCollisions(const std::string& name); //event list of non player object diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index cc443f2679..6ed2a92917 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -15,16 +15,16 @@ enum traceWorldType bothWorldTrace = collisionWorldTrace | pickWorldTrace }; -void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine *enginePass) //Traceobj was a Aedra Object +void newtrace(traceResults *results, const Ogre::Quaternion& orient, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine *enginePass) //Traceobj was a Aedra Object { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(0.0f, 0.0f, 0.0f); //y, x, z + const btQuaternion btorient (orient.x, orient.y, orient.z, orient.w); const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); - const btTransform from(btrot, btstart); - const btTransform to(btrot, btend); + const btTransform from(btorient, btstart); + const btTransform to(btorient, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World; diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index f484497d97..cd2547f8c0 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -21,6 +21,6 @@ struct traceResults float fraction; }; -void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); +void newtrace(traceResults *results, const Ogre::Quaternion& orient, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); #endif