Use sphere cast instead of ray for camera distance adjustment; use the box orientation value in newtrace

This commit is contained in:
scrawl 2013-04-30 20:26:59 +02:00
parent 61e476118d
commit 91c89e5db4
7 changed files with 60 additions and 28 deletions

View file

@ -322,10 +322,9 @@ void RenderingManager::update (float duration, bool paused)
btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btOrig(orig.x, orig.y, orig.z);
btVector3 btDest(dest.x, dest.y, dest.z); btVector3 btDest(dest.x, dest.y, dest.z);
std::pair<std::string,float> test = mPhysicsEngine->rayTest(btOrig, btDest); std::pair<bool, float> test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest);
if (!test.first.empty()) { if (test.first)
mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); mCamera->setCameraDistance(test.second * orig.distance(dest), false, false);
}
} }
mOcclusionQuery->update(duration); mOcclusionQuery->update(duration);

View file

@ -33,23 +33,23 @@ namespace MWWorld
class MovementSolver class MovementSolver
{ {
private: 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, const Ogre::Vector3 &halfExtents, bool isInterior,
OEngine::Physic::PhysicEngine *engine) OEngine::Physic::PhysicEngine *engine)
{ {
traceResults trace; // no initialization needed 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); halfExtents, isInterior, engine);
if(trace.fraction == 0.0f) if(trace.fraction == 0.0f)
return false; return false;
newtrace(&trace, trace.endpos, trace.endpos + velocity*remainingTime, newtrace(&trace, orient, trace.endpos, trace.endpos + velocity*remainingTime,
halfExtents, isInterior, engine); halfExtents, isInterior, engine);
if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope))
return false; 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) 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. // 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 traceResults trace; //no initialization needed
int maxHeight = 400.f; int maxHeight = 400.f;
int steps = 100; newtrace(&trace, Ogre::Quaternion::IDENTITY, newPosition, newPosition-Ogre::Vector3(0,0,maxHeight), halfExtents, isInterior, engine);
for (int i=0; i<steps; ++i) if(trace.fraction < 1.0f)
{ hit = true;
newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,maxHeight / steps), halfExtents, isInterior, engine);
if(trace.fraction < 1.0f)
hit = true;
newPosition = trace.endpos;
}
newPosition = trace.endpos; newPosition = trace.endpos;
physicActor->setOnGround(hit); physicActor->setOnGround(hit);
@ -154,7 +148,7 @@ namespace MWWorld
bool isInterior = !ptr.getCell()->isExterior(); bool isInterior = !ptr.getCell()->isExterior();
Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1);
physicActor->enableCollisions(false); physicActor->enableCollisions(false);
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z);
Ogre::Vector3 velocity; Ogre::Vector3 velocity;
if(!gravity) if(!gravity)
{ {
@ -167,7 +161,7 @@ namespace MWWorld
{ {
if(!(movement.z > 0.0f)) 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) if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope)
onground = true; onground = true;
} }
@ -188,7 +182,7 @@ namespace MWWorld
int iterations = 0; int iterations = 0;
do { do {
// trace to where character would go if there were no obstructions // 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; newPosition = trace.endpos;
remainingTime = remainingTime * (1.0f-trace.fraction); remainingTime = remainingTime * (1.0f-trace.fraction);
@ -207,7 +201,7 @@ namespace MWWorld
{ {
// Can't walk on this. Try to step up onto it. // Can't walk on this. Try to step up onto it.
if((gravity && !onground) || 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); Ogre::Vector3 resultantDirection = trace.planenormal.crossProduct(up);
resultantDirection.normalise(); resultantDirection.normalise();
@ -225,7 +219,7 @@ namespace MWWorld
if(onground) 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) if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope)
newPosition.z = trace.endpos.z + 2.0f; newPosition.z = trace.endpos.z + 2.0f;
else else

View file

@ -973,6 +973,8 @@ namespace MWWorld
if(duration <= 0.0f) if(duration <= 0.0f)
return; return;
processDoors(duration);
PtrMovementList::const_iterator player(actors.end()); PtrMovementList::const_iterator player(actors.end());
for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++) 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); moveObjectImp(player->first, vec.x, vec.y, vec.z);
} }
processDoors(duration);
mPhysEngine->stepSimulation (duration); mPhysEngine->stepSimulation (duration);
} }
@ -1022,6 +1022,7 @@ namespace MWWorld
mPhysics->getObjectAABB(it->first, min, max); mPhysics->getObjectAABB(it->first, min, max);
Ogre::Vector3 dimensions = max-min; Ogre::Vector3 dimensions = max-min;
/// \todo should use convexSweepTest here
std::vector<std::string> collisions = mPhysics->getCollisions(it->first); std::vector<std::string> collisions = mPhysics->getCollisions(it->first);
for (std::vector<std::string>::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) for (std::vector<std::string>::iterator cit = collisions.begin(); cit != collisions.end(); ++cit)
{ {

View file

@ -622,6 +622,41 @@ namespace Physic
return std::pair<std::string,float>(name,d); return std::pair<std::string,float>(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<const RigidBody*>(convexResult.m_hitCollisionObject))
if (body->mName == "player")
return 0;
return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
}
};
std::pair<bool, float> 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<float, std::string> > PhysicEngine::rayTest2(btVector3& from, btVector3& to) std::vector< std::pair<float, std::string> > PhysicEngine::rayTest2(btVector3& from, btVector3& to)
{ {
MyRayResultCallback resultCallback1; MyRayResultCallback resultCallback1;

View file

@ -298,6 +298,9 @@ namespace Physic
*/ */
std::vector< std::pair<float, std::string> > rayTest2(btVector3& from, btVector3& to); std::vector< std::pair<float, std::string> > rayTest2(btVector3& from, btVector3& to);
std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to);
///< @return (hit, relative distance)
std::vector<std::string> getCollisions(const std::string& name); std::vector<std::string> getCollisions(const std::string& name);
//event list of non player object //event list of non player object

View file

@ -15,16 +15,16 @@ enum traceWorldType
bothWorldTrace = collisionWorldTrace | pickWorldTrace 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 btstart(start.x, start.y, start.z + BBHalfExtents.z);
const btVector3 btend(end.x, end.y, end.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 btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z));
//const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2);
const btTransform from(btrot, btstart); const btTransform from(btorient, btstart);
const btTransform to(btrot, btend); const btTransform to(btorient, btend);
btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend);
newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World; newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World;

View file

@ -21,6 +21,6 @@ struct traceResults
float fraction; 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 #endif