Remove unused btKinematicCharacterController
parent
264736c139
commit
d4aeb177f9
@ -1,643 +0,0 @@
|
|||||||
/*
|
|
||||||
Bullet Continuous Collision Detection and Physics Library
|
|
||||||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "LinearMath/btIDebugDraw.h"
|
|
||||||
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
|
||||||
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
|
||||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
|
||||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
|
||||||
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
|
|
||||||
#include "LinearMath/btDefaultMotionState.h"
|
|
||||||
#include "btKinematicCharacterController.h"
|
|
||||||
|
|
||||||
///@todo Interact with dynamic objects,
|
|
||||||
///Ride kinematicly animated platforms properly
|
|
||||||
///Support ducking
|
|
||||||
class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
|
||||||
{
|
|
||||||
m_me[0] = me;
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me[], int count_) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
|
||||||
{
|
|
||||||
count = count_;
|
|
||||||
|
|
||||||
for(int i = 0; i < count; i++)
|
|
||||||
m_me[i] = me[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < count; i++)
|
|
||||||
if (rayResult.m_collisionObject == m_me[i])
|
|
||||||
return 1.0;
|
|
||||||
|
|
||||||
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
btCollisionObject* m_me[10];
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
btKinematicClosestNotMeConvexResultCallback( btCollisionObject* me, const btVector3& up, btScalar minSlopeDot )
|
|
||||||
: btCollisionWorld::ClosestConvexResultCallback( btVector3( 0.0, 0.0, 0.0 ), btVector3( 0.0, 0.0, 0.0 ) ),
|
|
||||||
m_me( me ), m_up( up ), m_minSlopeDot( minSlopeDot )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
|
||||||
{
|
|
||||||
if( convexResult.m_hitCollisionObject == m_me )
|
|
||||||
return btScalar( 1 );
|
|
||||||
|
|
||||||
btVector3 hitNormalWorld;
|
|
||||||
if( normalInWorldSpace )
|
|
||||||
{
|
|
||||||
hitNormalWorld = convexResult.m_hitNormalLocal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
///need to transform normal into worldspace
|
|
||||||
hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box...
|
|
||||||
|
|
||||||
btScalar dotUp = m_up.dot(hitNormalWorld);
|
|
||||||
if( dotUp < m_minSlopeDot )
|
|
||||||
return btScalar( 1 );
|
|
||||||
|
|
||||||
return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
btCollisionObject* m_me;
|
|
||||||
const btVector3 m_up;
|
|
||||||
btScalar m_minSlopeDot;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
btKinematicCharacterController::btKinematicCharacterController( btPairCachingGhostObject* externalGhostObject_,
|
|
||||||
btPairCachingGhostObject* internalGhostObject_,
|
|
||||||
btScalar stepHeight,
|
|
||||||
btScalar constantScale,
|
|
||||||
btScalar gravity,
|
|
||||||
btScalar fallVelocity,
|
|
||||||
btScalar jumpVelocity,
|
|
||||||
btScalar recoveringFactor )
|
|
||||||
{
|
|
||||||
m_upAxis = btKinematicCharacterController::Y_AXIS;
|
|
||||||
|
|
||||||
m_walkDirection.setValue( btScalar( 0 ), btScalar( 0 ), btScalar( 0 ) );
|
|
||||||
|
|
||||||
m_useGhostObjectSweepTest = true;
|
|
||||||
|
|
||||||
externalGhostObject = externalGhostObject_;
|
|
||||||
internalGhostObject = internalGhostObject_;
|
|
||||||
|
|
||||||
m_recoveringFactor = recoveringFactor;
|
|
||||||
|
|
||||||
m_stepHeight = stepHeight;
|
|
||||||
|
|
||||||
m_useWalkDirection = true; // use walk direction by default, legacy behavior
|
|
||||||
m_velocityTimeInterval = btScalar( 0 );
|
|
||||||
m_verticalVelocity = btScalar( 0 );
|
|
||||||
m_verticalOffset = btScalar( 0 );
|
|
||||||
|
|
||||||
m_gravity = constantScale * gravity;
|
|
||||||
m_fallSpeed = constantScale * fallVelocity; // Terminal velocity of a sky diver in m/s.
|
|
||||||
|
|
||||||
m_jumpSpeed = constantScale * jumpVelocity; // ?
|
|
||||||
m_wasJumping = false;
|
|
||||||
|
|
||||||
setMaxSlope( btRadians( 45.0 ) );
|
|
||||||
|
|
||||||
mCollision = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btKinematicCharacterController::~btKinematicCharacterController ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setVerticalVelocity(float z)
|
|
||||||
{
|
|
||||||
m_verticalVelocity = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool btKinematicCharacterController::recoverFromPenetration( btCollisionWorld* collisionWorld )
|
|
||||||
{
|
|
||||||
bool penetration = false;
|
|
||||||
|
|
||||||
if(!mCollision) return penetration;
|
|
||||||
|
|
||||||
collisionWorld->getDispatcher()->dispatchAllCollisionPairs( internalGhostObject->getOverlappingPairCache(),
|
|
||||||
collisionWorld->getDispatchInfo(),
|
|
||||||
collisionWorld->getDispatcher() );
|
|
||||||
|
|
||||||
btVector3 currentPosition = internalGhostObject->getWorldTransform().getOrigin();
|
|
||||||
|
|
||||||
btScalar maxPen = btScalar( 0 );
|
|
||||||
|
|
||||||
for( int i = 0; i < internalGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++ )
|
|
||||||
{
|
|
||||||
m_manifoldArray.resize(0);
|
|
||||||
|
|
||||||
btBroadphasePair* collisionPair = &internalGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
|
||||||
|
|
||||||
if( collisionPair->m_algorithm )
|
|
||||||
collisionPair->m_algorithm->getAllContactManifolds( m_manifoldArray );
|
|
||||||
|
|
||||||
|
|
||||||
for( int j = 0; j < m_manifoldArray.size(); j++ )
|
|
||||||
{
|
|
||||||
btPersistentManifold* manifold = m_manifoldArray[j];
|
|
||||||
|
|
||||||
btScalar directionSign = manifold->getBody0() == internalGhostObject ? btScalar( -1.0 ) : btScalar( 1.0 );
|
|
||||||
|
|
||||||
for( int p = 0; p < manifold->getNumContacts(); p++ )
|
|
||||||
{
|
|
||||||
const btManifoldPoint&pt = manifold->getContactPoint( p );
|
|
||||||
if( (manifold->getBody1() == externalGhostObject && manifold->getBody0() == internalGhostObject)
|
|
||||||
||(manifold->getBody0() == externalGhostObject && manifold->getBody1() == internalGhostObject) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
btScalar dist = pt.getDistance();
|
|
||||||
|
|
||||||
if( dist < 0.0 )
|
|
||||||
{
|
|
||||||
if( dist < maxPen )
|
|
||||||
maxPen = dist;
|
|
||||||
|
|
||||||
// NOTE : btScalar affects the stairs but the parkinson...
|
|
||||||
// 0.0 , the capsule can break the walls...
|
|
||||||
currentPosition += pt.m_normalWorldOnB * directionSign * dist * m_recoveringFactor;
|
|
||||||
|
|
||||||
penetration = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ???
|
|
||||||
//manifold->clearManifold();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
btTransform transform = internalGhostObject->getWorldTransform();
|
|
||||||
|
|
||||||
transform.setOrigin( currentPosition );
|
|
||||||
|
|
||||||
internalGhostObject->setWorldTransform( transform );
|
|
||||||
externalGhostObject->setWorldTransform( transform );
|
|
||||||
|
|
||||||
return penetration;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btVector3 btKinematicCharacterController::stepUp( btCollisionWorld* world, const btVector3& currentPosition, btScalar& currentStepOffset )
|
|
||||||
{
|
|
||||||
btVector3 targetPosition = currentPosition + getUpAxisDirections()[ m_upAxis ] * ( m_stepHeight + ( m_verticalOffset > btScalar( 0.0 ) ? m_verticalOffset : 0.0 ) );
|
|
||||||
|
|
||||||
//if the no collisions mode is on, no need to go any further
|
|
||||||
if(!mCollision)
|
|
||||||
{
|
|
||||||
currentStepOffset = m_stepHeight;
|
|
||||||
return targetPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the collision shape
|
|
||||||
//
|
|
||||||
btCollisionShape* collisionShape = externalGhostObject->getCollisionShape();
|
|
||||||
btAssert( collisionShape->isConvex() );
|
|
||||||
|
|
||||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
|
||||||
|
|
||||||
// FIXME: Handle penetration properly
|
|
||||||
//
|
|
||||||
btTransform start;
|
|
||||||
start.setIdentity();
|
|
||||||
start.setOrigin( currentPosition + getUpAxisDirections()[ m_upAxis ] * ( convexShape->getMargin() ) );
|
|
||||||
|
|
||||||
btTransform end;
|
|
||||||
end.setIdentity();
|
|
||||||
end.setOrigin( targetPosition );
|
|
||||||
|
|
||||||
btKinematicClosestNotMeConvexResultCallback callback( externalGhostObject, -getUpAxisDirections()[ m_upAxis ], m_maxSlopeCosine );
|
|
||||||
callback.m_collisionFilterGroup = externalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
|
||||||
callback.m_collisionFilterMask = externalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
|
||||||
|
|
||||||
// Sweep test
|
|
||||||
//
|
|
||||||
if( m_useGhostObjectSweepTest )
|
|
||||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration );
|
|
||||||
|
|
||||||
else
|
|
||||||
world->convexSweepTest( convexShape, start, end, callback );
|
|
||||||
|
|
||||||
if( callback.hasHit() )
|
|
||||||
{
|
|
||||||
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
|
||||||
//
|
|
||||||
if( callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > btScalar( 0.0 ) )
|
|
||||||
{
|
|
||||||
// We moved up only a fraction of the step height
|
|
||||||
//
|
|
||||||
currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
|
|
||||||
|
|
||||||
return currentPosition.lerp( targetPosition, callback.m_closestHitFraction );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_verticalVelocity = btScalar( 0.0 );
|
|
||||||
m_verticalOffset = btScalar( 0.0 );
|
|
||||||
|
|
||||||
return currentPosition;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentStepOffset = m_stepHeight;
|
|
||||||
return targetPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///Reflect the vector d around the vector r
|
|
||||||
inline btVector3 reflect( const btVector3& d, const btVector3& r )
|
|
||||||
{
|
|
||||||
return d - ( btScalar( 2.0 ) * d.dot( r ) ) * r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///Project a vector u on another vector v
|
|
||||||
inline btVector3 project( const btVector3& u, const btVector3& v )
|
|
||||||
{
|
|
||||||
return v * u.dot( v );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///Helper for computing the character sliding
|
|
||||||
inline btVector3 slide( const btVector3& direction, const btVector3& planeNormal )
|
|
||||||
{
|
|
||||||
return direction - project( direction, planeNormal );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
btVector3 slideOnCollision( const btVector3& fromPosition, const btVector3& toPosition, const btVector3& hitNormal )
|
|
||||||
{
|
|
||||||
btVector3 moveDirection = toPosition - fromPosition;
|
|
||||||
btScalar moveLength = moveDirection.length();
|
|
||||||
|
|
||||||
if( moveLength <= btScalar( SIMD_EPSILON ) )
|
|
||||||
return toPosition;
|
|
||||||
|
|
||||||
moveDirection.normalize();
|
|
||||||
|
|
||||||
btVector3 reflectDir = reflect( moveDirection, hitNormal );
|
|
||||||
reflectDir.normalize();
|
|
||||||
|
|
||||||
return fromPosition + slide( reflectDir, hitNormal ) * moveLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btVector3 btKinematicCharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& currentPosition, const btVector3& walkMove )
|
|
||||||
{
|
|
||||||
// We go to !
|
|
||||||
//
|
|
||||||
btVector3 targetPosition = currentPosition + walkMove;
|
|
||||||
|
|
||||||
//if the no collisions mode is on, no need to go any further
|
|
||||||
if(!mCollision) return targetPosition;
|
|
||||||
|
|
||||||
// Retrieve the collision shape
|
|
||||||
//
|
|
||||||
btCollisionShape* collisionShape = externalGhostObject->getCollisionShape();
|
|
||||||
btAssert( collisionShape->isConvex() );
|
|
||||||
|
|
||||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
|
||||||
|
|
||||||
btTransform start;
|
|
||||||
start.setIdentity();
|
|
||||||
|
|
||||||
btTransform end;
|
|
||||||
end.setIdentity();
|
|
||||||
|
|
||||||
btScalar fraction = btScalar( 1.0 );
|
|
||||||
|
|
||||||
// This optimization scheme suffers in the corners.
|
|
||||||
// It basically jumps from a wall to another, then fails to find a new
|
|
||||||
// position (after 4 iterations here) and finally don't move at all.
|
|
||||||
//
|
|
||||||
// The stepping algorithm adds some problems with stairs. It seems
|
|
||||||
// the treads create some fake corner using capsules for collisions.
|
|
||||||
//
|
|
||||||
for( int i = 0; i < 4 && fraction > btScalar( 0.01 ); i++ )
|
|
||||||
{
|
|
||||||
start.setOrigin( currentPosition );
|
|
||||||
end.setOrigin( targetPosition );
|
|
||||||
|
|
||||||
btVector3 sweepDirNegative = currentPosition - targetPosition;
|
|
||||||
|
|
||||||
btKinematicClosestNotMeConvexResultCallback callback( externalGhostObject, sweepDirNegative, btScalar( 0.0 ) );
|
|
||||||
callback.m_collisionFilterGroup = externalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
|
||||||
callback.m_collisionFilterMask = externalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
|
||||||
|
|
||||||
if( m_useGhostObjectSweepTest )
|
|
||||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
|
||||||
|
|
||||||
else
|
|
||||||
collisionWorld->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
|
||||||
|
|
||||||
if( callback.hasHit() )
|
|
||||||
{
|
|
||||||
// Try another target position
|
|
||||||
//
|
|
||||||
targetPosition = slideOnCollision( currentPosition, targetPosition, callback.m_hitNormalWorld );
|
|
||||||
fraction = callback.m_closestHitFraction;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
|
|
||||||
// Move to the valid target position
|
|
||||||
//
|
|
||||||
return targetPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't move if you can't find a valid target position...
|
|
||||||
// It prevents some flickering.
|
|
||||||
//
|
|
||||||
return currentPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///Handle the gravity
|
|
||||||
btScalar btKinematicCharacterController::addFallOffset( bool wasOnGround, btScalar currentStepOffset, btScalar dt )
|
|
||||||
{
|
|
||||||
btScalar downVelocity = ( m_verticalVelocity < 0.0 ? -m_verticalVelocity : btScalar( 0.0 ) ) * dt;
|
|
||||||
|
|
||||||
if( downVelocity > btScalar( 0.0 ) && downVelocity < m_stepHeight && ( wasOnGround || !m_wasJumping ) )
|
|
||||||
downVelocity = m_stepHeight;
|
|
||||||
|
|
||||||
return currentStepOffset + downVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btVector3 btKinematicCharacterController::stepDown( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar currentStepOffset )
|
|
||||||
{
|
|
||||||
btVector3 stepDrop = getUpAxisDirections()[ m_upAxis ] * currentStepOffset;
|
|
||||||
|
|
||||||
// Be sure we are falling from the last m_currentPosition
|
|
||||||
// It prevents some flickering
|
|
||||||
//
|
|
||||||
btVector3 targetPosition = currentPosition - stepDrop;
|
|
||||||
|
|
||||||
//if the no collisions mode is on, no need to go any further
|
|
||||||
if(!mCollision) return targetPosition;
|
|
||||||
|
|
||||||
btTransform start;
|
|
||||||
start.setIdentity();
|
|
||||||
start.setOrigin( currentPosition );
|
|
||||||
|
|
||||||
btTransform end;
|
|
||||||
end.setIdentity();
|
|
||||||
end.setOrigin( targetPosition );
|
|
||||||
|
|
||||||
btKinematicClosestNotMeConvexResultCallback callback( internalGhostObject, getUpAxisDirections()[ m_upAxis ], m_maxSlopeCosine );
|
|
||||||
callback.m_collisionFilterGroup = internalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
|
||||||
callback.m_collisionFilterMask = internalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
|
||||||
|
|
||||||
// Retrieve the collision shape
|
|
||||||
//
|
|
||||||
btCollisionShape* collisionShape = internalGhostObject->getCollisionShape();
|
|
||||||
btAssert( collisionShape->isConvex() );
|
|
||||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
|
||||||
|
|
||||||
if( m_useGhostObjectSweepTest )
|
|
||||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
|
||||||
|
|
||||||
else
|
|
||||||
collisionWorld->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
|
||||||
|
|
||||||
if( callback.hasHit() )
|
|
||||||
{
|
|
||||||
m_verticalVelocity = btScalar( 0.0 );
|
|
||||||
m_verticalOffset = btScalar( 0.0 );
|
|
||||||
m_wasJumping = false;
|
|
||||||
|
|
||||||
// We dropped a fraction of the height -> hit floor
|
|
||||||
//
|
|
||||||
return currentPosition.lerp( targetPosition, callback.m_closestHitFraction );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
|
|
||||||
// We dropped the full height
|
|
||||||
//
|
|
||||||
return targetPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setWalkDirection( const btVector3& walkDirection )
|
|
||||||
{
|
|
||||||
m_useWalkDirection = true;
|
|
||||||
m_walkDirection = walkDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setVelocityForTimeInterval( const btVector3& velocity, btScalar timeInterval )
|
|
||||||
{
|
|
||||||
m_useWalkDirection = false;
|
|
||||||
m_walkDirection = velocity;
|
|
||||||
m_velocityTimeInterval = timeInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::warp( const btVector3& origin )
|
|
||||||
{
|
|
||||||
btTransform transform;
|
|
||||||
transform.setIdentity();
|
|
||||||
transform.setOrigin( -origin );
|
|
||||||
|
|
||||||
externalGhostObject->setWorldTransform( transform );
|
|
||||||
internalGhostObject->setWorldTransform( transform );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::preStep( btCollisionWorld* collisionWorld )
|
|
||||||
{
|
|
||||||
BT_PROFILE( "preStep" );
|
|
||||||
|
|
||||||
for( int i = 0; i < 4 && recoverFromPenetration ( collisionWorld ); i++ );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt )
|
|
||||||
{
|
|
||||||
BT_PROFILE( "playerStep" );
|
|
||||||
|
|
||||||
if( !m_useWalkDirection && m_velocityTimeInterval <= btScalar( 0.0 ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool wasOnGround = onGround();
|
|
||||||
|
|
||||||
// Handle the gravity
|
|
||||||
//
|
|
||||||
m_verticalVelocity -= m_gravity * dt;
|
|
||||||
|
|
||||||
if( m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed )
|
|
||||||
m_verticalVelocity = m_jumpSpeed;
|
|
||||||
|
|
||||||
if( m_verticalVelocity < 0.0 && btFabs( m_verticalVelocity ) > btFabs( m_fallSpeed ) )
|
|
||||||
m_verticalVelocity = -btFabs( m_fallSpeed );
|
|
||||||
|
|
||||||
m_verticalOffset = m_verticalVelocity * dt;
|
|
||||||
|
|
||||||
// This forced stepping up can cause problems when the character
|
|
||||||
// walks (jump in fact...) under too low ceilings.
|
|
||||||
//
|
|
||||||
btVector3 currentPosition = externalGhostObject->getWorldTransform().getOrigin();
|
|
||||||
btScalar currentStepOffset;
|
|
||||||
|
|
||||||
currentPosition = stepUp( collisionWorld, currentPosition, currentStepOffset );
|
|
||||||
|
|
||||||
// Move in the air and slide against the walls ignoring the stair steps.
|
|
||||||
//
|
|
||||||
if( m_useWalkDirection )
|
|
||||||
currentPosition = stepForwardAndStrafe( collisionWorld, currentPosition, m_walkDirection );
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
btScalar dtMoving = ( dt < m_velocityTimeInterval ) ? dt : m_velocityTimeInterval;
|
|
||||||
m_velocityTimeInterval -= dt;
|
|
||||||
|
|
||||||
// How far will we move while we are moving ?
|
|
||||||
//
|
|
||||||
btVector3 moveDirection = m_walkDirection * dtMoving;
|
|
||||||
|
|
||||||
currentPosition = stepForwardAndStrafe( collisionWorld, currentPosition, moveDirection );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally find the ground.
|
|
||||||
//
|
|
||||||
currentStepOffset = addFallOffset( wasOnGround, currentStepOffset, dt );
|
|
||||||
|
|
||||||
currentPosition = stepDown( collisionWorld, currentPosition, currentStepOffset );
|
|
||||||
|
|
||||||
// Apply the new position to the collision objects.
|
|
||||||
//
|
|
||||||
btTransform tranform;
|
|
||||||
tranform = externalGhostObject->getWorldTransform();
|
|
||||||
tranform.setOrigin( currentPosition );
|
|
||||||
|
|
||||||
externalGhostObject->setWorldTransform( tranform );
|
|
||||||
internalGhostObject->setWorldTransform( tranform );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setFallSpeed( btScalar fallSpeed )
|
|
||||||
{
|
|
||||||
m_fallSpeed = fallSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setJumpSpeed( btScalar jumpSpeed )
|
|
||||||
{
|
|
||||||
m_jumpSpeed = jumpSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setMaxJumpHeight( btScalar maxJumpHeight )
|
|
||||||
{
|
|
||||||
m_maxJumpHeight = maxJumpHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool btKinematicCharacterController::canJump() const
|
|
||||||
{
|
|
||||||
return onGround();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::jump()
|
|
||||||
{
|
|
||||||
if( !canJump() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_verticalVelocity = m_jumpSpeed;
|
|
||||||
m_wasJumping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setGravity( btScalar gravity )
|
|
||||||
{
|
|
||||||
m_gravity = gravity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btScalar btKinematicCharacterController::getGravity() const
|
|
||||||
{
|
|
||||||
return m_gravity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::setMaxSlope( btScalar slopeRadians )
|
|
||||||
{
|
|
||||||
m_maxSlopeRadians = slopeRadians;
|
|
||||||
m_maxSlopeCosine = btCos( slopeRadians );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btScalar btKinematicCharacterController::getMaxSlope() const
|
|
||||||
{
|
|
||||||
return m_maxSlopeRadians;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool btKinematicCharacterController::onGround() const
|
|
||||||
{
|
|
||||||
return btFabs( m_verticalVelocity ) < btScalar( SIMD_EPSILON ) &&
|
|
||||||
btFabs( m_verticalOffset ) < btScalar( SIMD_EPSILON );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btVector3* btKinematicCharacterController::getUpAxisDirections()
|
|
||||||
{
|
|
||||||
static btVector3 sUpAxisDirection[] =
|
|
||||||
{
|
|
||||||
btVector3( btScalar( 0.0 ), btScalar( 0.0 ), btScalar( 0.0 ) ),
|
|
||||||
btVector3( btScalar( 0.0 ), btScalar( 1.0 ), btScalar( 0.0 ) ),
|
|
||||||
btVector3( btScalar( 0.0 ), btScalar( 0.0 ), btScalar( 1.0 ) )
|
|
||||||
};
|
|
||||||
|
|
||||||
return sUpAxisDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void btKinematicCharacterController::debugDraw( btIDebugDraw* debugDrawer )
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
Bullet Continuous Collision Detection and Physics Library
|
|
||||||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef KINEMATIC_CHARACTER_CONTROLLER_H
|
|
||||||
#define KINEMATIC_CHARACTER_CONTROLLER_H
|
|
||||||
|
|
||||||
#include "LinearMath/btVector3.h"
|
|
||||||
#include "LinearMath/btQuickprof.h"
|
|
||||||
|
|
||||||
#include "BulletDynamics/Character/btCharacterControllerInterface.h"
|
|
||||||
|
|
||||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
|
||||||
|
|
||||||
|
|
||||||
class btCollisionShape;
|
|
||||||
class btRigidBody;
|
|
||||||
class btCollisionWorld;
|
|
||||||
class btCollisionDispatcher;
|
|
||||||
class btPairCachingGhostObject;
|
|
||||||
|
|
||||||
///btKinematicCharacterController is an object that supports a sliding motion in a world.
|
|
||||||
///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.
|
|
||||||
///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user.
|
|
||||||
class btKinematicCharacterController : public btCharacterControllerInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum UpAxis
|
|
||||||
{
|
|
||||||
X_AXIS = 0,
|
|
||||||
Y_AXIS = 1,
|
|
||||||
Z_AXIS = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
btPairCachingGhostObject* externalGhostObject; // use this for querying collisions for sliding and move
|
|
||||||
btPairCachingGhostObject* internalGhostObject; // and this for recoreving from penetrations
|
|
||||||
|
|
||||||
btScalar m_verticalVelocity;
|
|
||||||
btScalar m_verticalOffset;
|
|
||||||
btScalar m_fallSpeed;
|
|
||||||
btScalar m_jumpSpeed;
|
|
||||||
btScalar m_maxJumpHeight;
|
|
||||||
btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value)
|
|
||||||
btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization)
|
|
||||||
btScalar m_gravity;
|
|
||||||
btScalar m_recoveringFactor;
|
|
||||||
|
|
||||||
btScalar m_stepHeight;
|
|
||||||
|
|
||||||
///this is the desired walk direction, set by the user
|
|
||||||
btVector3 m_walkDirection;
|
|
||||||
|
|
||||||
///keep track of the contact manifolds
|
|
||||||
btManifoldArray m_manifoldArray;
|
|
||||||
|
|
||||||
///Gravity attributes
|
|
||||||
bool m_wasJumping;
|
|
||||||
|
|
||||||
bool m_useGhostObjectSweepTest;
|
|
||||||
bool m_useWalkDirection;
|
|
||||||
btScalar m_velocityTimeInterval;
|
|
||||||
|
|
||||||
UpAxis m_upAxis;
|
|
||||||
|
|
||||||
static btVector3* getUpAxisDirections();
|
|
||||||
|
|
||||||
bool recoverFromPenetration ( btCollisionWorld* collisionWorld );
|
|
||||||
|
|
||||||
btVector3 stepUp( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar& currentStepOffset );
|
|
||||||
btVector3 stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& currentPosition, const btVector3& walkMove );
|
|
||||||
btScalar addFallOffset( bool wasJumping, btScalar currentStepOffset, btScalar dt );
|
|
||||||
btVector3 stepDown( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar currentStepOffset );
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// externalGhostObject is used for querying the collisions for sliding along the wall,
|
|
||||||
/// and internalGhostObject is used for querying the collisions for recovering from large penetrations.
|
|
||||||
/// These parameters can point on the same object.
|
|
||||||
/// Using a smaller internalGhostObject can help for removing some flickering but create some
|
|
||||||
/// stopping artefacts when sliding along stairs or small walls.
|
|
||||||
/// Don't forget to scale gravity and fallSpeed if you scale the world.
|
|
||||||
btKinematicCharacterController( btPairCachingGhostObject* externalGhostObject,
|
|
||||||
btPairCachingGhostObject* internalGhostObject,
|
|
||||||
btScalar stepHeight,
|
|
||||||
btScalar constantScale = btScalar( 1.0 ),
|
|
||||||
btScalar gravity = btScalar( 9.8 ),
|
|
||||||
btScalar fallVelocity = btScalar( 55.0 ),
|
|
||||||
btScalar jumpVelocity = btScalar( 9.8 ),
|
|
||||||
btScalar recoveringFactor = btScalar( 0.2 ) );
|
|
||||||
|
|
||||||
~btKinematicCharacterController ();
|
|
||||||
|
|
||||||
void setVerticalVelocity(float z);
|
|
||||||
|
|
||||||
///btActionInterface interface
|
|
||||||
virtual void updateAction( btCollisionWorld* collisionWorld, btScalar deltaTime )
|
|
||||||
{
|
|
||||||
preStep( collisionWorld );
|
|
||||||
playerStep( collisionWorld, deltaTime );
|
|
||||||
}
|
|
||||||
|
|
||||||
///btActionInterface interface
|
|
||||||
void debugDraw( btIDebugDraw* debugDrawer );
|
|
||||||
|
|
||||||
void setUpAxis( UpAxis axis )
|
|
||||||
{
|
|
||||||
m_upAxis = axis;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This should probably be called setPositionIncrementPerSimulatorStep.
|
|
||||||
/// This is neither a direction nor a velocity, but the amount to
|
|
||||||
/// increment the position each simulation iteration, regardless
|
|
||||||
/// of dt.
|
|
||||||
/// This call will reset any velocity set by setVelocityForTimeInterval().
|
|
||||||
virtual void setWalkDirection(const btVector3& walkDirection);
|
|
||||||
|
|
||||||
/// Caller provides a velocity with which the character should move for
|
|
||||||
/// the given time period. After the time period, velocity is reset
|
|
||||||
/// to zero.
|
|
||||||
/// This call will reset any walk direction set by setWalkDirection().
|
|
||||||
/// Negative time intervals will result in no motion.
|
|
||||||
virtual void setVelocityForTimeInterval(const btVector3& velocity,
|
|
||||||
btScalar timeInterval);
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
void warp( const btVector3& origin );
|
|
||||||
|
|
||||||
void preStep( btCollisionWorld* collisionWorld );
|
|
||||||
void playerStep( btCollisionWorld* collisionWorld, btScalar dt );
|
|
||||||
|
|
||||||
void setFallSpeed( btScalar fallSpeed );
|
|
||||||
void setJumpSpeed( btScalar jumpSpeed );
|
|
||||||
void setMaxJumpHeight( btScalar maxJumpHeight );
|
|
||||||
bool canJump() const;
|
|
||||||
|
|
||||||
void jump();
|
|
||||||
|
|
||||||
void setGravity( btScalar gravity );
|
|
||||||
btScalar getGravity() const;
|
|
||||||
|
|
||||||
/// The max slope determines the maximum angle that the controller can walk up.
|
|
||||||
/// The slope angle is measured in radians.
|
|
||||||
void setMaxSlope( btScalar slopeRadians );
|
|
||||||
btScalar getMaxSlope() const;
|
|
||||||
|
|
||||||
void setUseGhostSweepTest( bool useGhostObjectSweepTest )
|
|
||||||
{
|
|
||||||
m_useGhostObjectSweepTest = useGhostObjectSweepTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onGround() const;
|
|
||||||
|
|
||||||
//if set to false, there will be no collision.
|
|
||||||
bool mCollision;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // KINEMATIC_CHARACTER_CONTROLLER_H
|
|
Loading…
Reference in New Issue