+ improved KinematicCharacterController
+ improved btSubsimplexConvexCast, btContinuousConvexCollision and btGjkConvexCast to support configuration that start in touching/penetration, required for 'sliding'. + added files to CMakeLists.txt for CharacterController + bump up version to 2.70 (preparation for beta)
This commit is contained in:
@@ -87,7 +87,7 @@ btVector3 perpindicularComponent (const btVector3& direction, const btVector3& n
|
||||
KinematicCharacterController::KinematicCharacterController ()
|
||||
{
|
||||
m_turnAngle = btScalar(0.0);
|
||||
m_walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
|
||||
m_walkVelocity = btScalar(1.1) * 14.0; // 4 km/h -> 1.1 m/s
|
||||
m_shape = NULL;
|
||||
m_pairCache = NULL;
|
||||
m_collisionObject = NULL;
|
||||
@@ -97,15 +97,15 @@ KinematicCharacterController::~KinematicCharacterController ()
|
||||
{
|
||||
}
|
||||
|
||||
void KinematicCharacterController::setup (btDynamicsWorld* dynamicsWorld, btScalar height, btScalar width, btScalar stepHeight)
|
||||
void KinematicCharacterController::setup (btScalar height, btScalar width, btScalar stepHeight)
|
||||
{
|
||||
btVector3 spherePositions[2];
|
||||
btScalar sphereRadii[2];
|
||||
|
||||
sphereRadii[0] = width;
|
||||
sphereRadii[1] = width;
|
||||
spherePositions[0] = btVector3 (0.0, (height/btScalar(2.0) - width), 0.0);
|
||||
spherePositions[1] = btVector3 (0.0, (-height/btScalar(2.0) + width), 0.0);
|
||||
spherePositions[0] = btVector3 (0.0, (height/btScalar(2.0) ), 0.0);
|
||||
spherePositions[1] = btVector3 (0.0, (-height/btScalar(2.0)), 0.0);
|
||||
|
||||
m_halfHeight = height/btScalar(2.0);
|
||||
|
||||
@@ -116,19 +116,20 @@ void KinematicCharacterController::setup (btDynamicsWorld* dynamicsWorld, btScal
|
||||
btTransform startTransform;
|
||||
startTransform.setIdentity ();
|
||||
startTransform.setOrigin (btVector3(0.0, 4.0, 0.0));
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
|
||||
//btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||
//btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
|
||||
m_collisionObject = new btCollisionObject ();
|
||||
|
||||
m_collisionObject->setWorldTransform(startTransform);
|
||||
m_collisionObject->setCollisionShape (m_shape);
|
||||
m_collisionObject->setCollisionFlags (btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
dynamicsWorld->addCollisionObject (m_collisionObject);
|
||||
m_collisionObject->setCollisionFlags (btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
|
||||
}
|
||||
|
||||
void KinematicCharacterController::destroy (btDynamicsWorld* dynamicsWorld)
|
||||
void KinematicCharacterController::destroy ()
|
||||
{
|
||||
if (m_collisionObject)
|
||||
{
|
||||
dynamicsWorld->removeCollisionObject (m_collisionObject);
|
||||
delete m_collisionObject;
|
||||
}
|
||||
|
||||
@@ -143,29 +144,33 @@ btCollisionObject* KinematicCharacterController::getCollisionObject ()
|
||||
return m_collisionObject;
|
||||
}
|
||||
|
||||
bool KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dynamicsWorld)
|
||||
bool KinematicCharacterController::recoverFromPenetration (const btDynamicsWorld* dynamicsWorld)
|
||||
{
|
||||
|
||||
if (m_pairCache == NULL)
|
||||
return false;
|
||||
|
||||
bool penetration = false;
|
||||
|
||||
dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs (m_pairCache, dynamicsWorld->getDispatchInfo(), dynamicsWorld->getDispatcher());
|
||||
|
||||
m_dispatcher->dispatchAllCollisionPairs (m_pairCache, dynamicsWorld->getDispatchInfo(), m_dispatcher);
|
||||
|
||||
btManifoldArray manifoldArray;
|
||||
m_currentPosition = m_collisionObject->getWorldTransform().getOrigin();
|
||||
|
||||
btScalar maxPen = btScalar(0.0);
|
||||
for (int i = 0; i < m_pairCache->getNumOverlappingPairs(); i++)
|
||||
{
|
||||
manifoldArray.clear();
|
||||
m_manifoldArray.resize(0);
|
||||
|
||||
btBroadphasePair* collisionPair = &m_pairCache->getOverlappingPairArray()[i];
|
||||
|
||||
if (collisionPair->m_algorithm)
|
||||
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
|
||||
collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
|
||||
|
||||
for (int j=0;j<manifoldArray.size();j++)
|
||||
|
||||
for (int j=0;j<m_manifoldArray.size();j++)
|
||||
{
|
||||
btPersistentManifold* manifold = manifoldArray[j];
|
||||
btPersistentManifold* manifold = m_manifoldArray[j];
|
||||
btScalar directionSign = manifold->getBody0() == m_collisionObject ? btScalar(-1.0) : btScalar(1.0);
|
||||
for (int p=0;p<manifold->getNumContacts();p++)
|
||||
{
|
||||
@@ -176,7 +181,8 @@ bool KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dyna
|
||||
if (pt.getDistance() < maxPen)
|
||||
{
|
||||
maxPen = pt.getDistance();
|
||||
m_touchingNormal = pt.m_normalWorldOnB * directionSign;
|
||||
m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
|
||||
|
||||
}
|
||||
m_currentPosition += pt.m_normalWorldOnB * directionSign * pt.getDistance() * btScalar(0.2);
|
||||
penetration = true;
|
||||
@@ -184,13 +190,18 @@ bool KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dyna
|
||||
//printf("touching %f\n", pt.getDistance());
|
||||
}
|
||||
}
|
||||
manifold->clearManifold();
|
||||
|
||||
//manifold->clearManifold();
|
||||
}
|
||||
}
|
||||
btTransform newTrans = m_collisionObject->getWorldTransform();
|
||||
newTrans.setOrigin(m_currentPosition);
|
||||
m_collisionObject->setWorldTransform(newTrans);
|
||||
// printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
|
||||
return penetration;
|
||||
}
|
||||
|
||||
void KinematicCharacterController::stepUp (btDynamicsWorld* dynamicsWorld)
|
||||
void KinematicCharacterController::stepUp (const btDynamicsWorld* dynamicsWorld)
|
||||
{
|
||||
// phase 1: up
|
||||
btTransform start, end;
|
||||
@@ -222,31 +233,47 @@ void KinematicCharacterController::updateTargetPositionBasedOnCollision (const b
|
||||
{
|
||||
btVector3 movementDirection = m_targetPosition - m_currentPosition;
|
||||
btScalar movementLength = movementDirection.length();
|
||||
movementDirection.normalize();
|
||||
|
||||
btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
|
||||
reflectDir.normalize();
|
||||
|
||||
btVector3 parallelDir, perpindicularDir;
|
||||
|
||||
parallelDir = parallelComponent (reflectDir, hitNormal);
|
||||
perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
|
||||
|
||||
m_targetPosition = m_currentPosition;
|
||||
if (tangentMag != 0.0)
|
||||
if (movementLength>SIMD_EPSILON)
|
||||
{
|
||||
m_targetPosition += parallelDir * btScalar (tangentMag*movementLength);
|
||||
}
|
||||
movementDirection.normalize();
|
||||
|
||||
if (normalMag != 0.0)
|
||||
btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
|
||||
reflectDir.normalize();
|
||||
|
||||
btVector3 parallelDir, perpindicularDir;
|
||||
|
||||
parallelDir = parallelComponent (reflectDir, hitNormal);
|
||||
perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
|
||||
|
||||
m_targetPosition = m_currentPosition;
|
||||
if (0)//tangentMag != 0.0)
|
||||
{
|
||||
btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
|
||||
// printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
|
||||
m_targetPosition += parComponent;
|
||||
}
|
||||
|
||||
if (normalMag != 0.0)
|
||||
{
|
||||
btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
|
||||
// printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
|
||||
m_targetPosition += perpComponent;
|
||||
}
|
||||
} else
|
||||
{
|
||||
m_targetPosition += perpindicularDir * btScalar (normalMag*movementLength);
|
||||
// printf("movementLength don't normalize a zero vector\n");
|
||||
}
|
||||
}
|
||||
|
||||
void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove)
|
||||
void KinematicCharacterController::stepForwardAndStrafe (const btDynamicsWorld* dynamicsWorld, const btVector3& walkMove)
|
||||
{
|
||||
|
||||
btVector3 originalDir = walkMove.normalized();
|
||||
if (walkMove.length() < SIMD_EPSILON)
|
||||
{
|
||||
originalDir.setValue(0.f,0.f,0.f);
|
||||
}
|
||||
// printf("originalDir=%f,%f,%f\n",originalDir[0],originalDir[1],originalDir[2]);
|
||||
// phase 2: forward and strafe
|
||||
btTransform start, end;
|
||||
m_targetPosition = m_currentPosition + walkMove;
|
||||
@@ -255,6 +282,7 @@ void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynami
|
||||
|
||||
btScalar fraction = 1.0;
|
||||
btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
|
||||
// printf("distance2=%f\n",distance2);
|
||||
|
||||
if (m_touchingContact)
|
||||
{
|
||||
@@ -262,44 +290,67 @@ void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynami
|
||||
updateTargetPositionBasedOnCollision (m_touchingNormal);
|
||||
}
|
||||
|
||||
while (fraction > btScalar(0.01))
|
||||
int maxIter = 10;
|
||||
|
||||
while (fraction > btScalar(0.01) && maxIter-- > 0)
|
||||
{
|
||||
start.setOrigin (m_currentPosition);
|
||||
end.setOrigin (m_targetPosition);
|
||||
|
||||
ClosestNotMeConvexResultCallback callback (m_collisionObject);
|
||||
dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
|
||||
|
||||
//btScalar margin = m_shape->getMargin();
|
||||
//m_shape->setMargin(margin - 0.06f);
|
||||
dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
|
||||
//m_shape->setMargin(margin);
|
||||
|
||||
|
||||
fraction -= callback.m_closestHitFraction;
|
||||
|
||||
if (callback.HasHit())
|
||||
{
|
||||
// we moved only a fraction
|
||||
btScalar hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
|
||||
if (hitDistance<0.f)
|
||||
{
|
||||
// printf("neg dist?\n");
|
||||
}
|
||||
|
||||
/* If the distance is farther than the collision margin, move */
|
||||
if (hitDistance > 0.05)
|
||||
{
|
||||
// printf("callback.m_closestHitFraction=%f\n",callback.m_closestHitFraction);
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
|
||||
}
|
||||
|
||||
updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
|
||||
btVector3 currentDir = m_targetPosition - m_currentPosition;
|
||||
distance2 = currentDir.length2();
|
||||
currentDir.normalize();
|
||||
/* Ageia's C.C. took this test from Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
|
||||
if (currentDir.dot(originalDir) <= btScalar(0.0))
|
||||
if (distance2 > SIMD_EPSILON)
|
||||
{
|
||||
currentDir.normalize();
|
||||
/* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
|
||||
if (currentDir.dot(originalDir) <= btScalar(0.0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// printf("currentDir: don't normalize a zero vector\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// we moved whole way
|
||||
m_currentPosition = m_targetPosition;
|
||||
}
|
||||
|
||||
// if (callback.m_closestHitFraction == 0.f)
|
||||
// break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void KinematicCharacterController::stepDown (btDynamicsWorld* dynamicsWorld, btScalar dt)
|
||||
void KinematicCharacterController::stepDown (const btDynamicsWorld* dynamicsWorld, btScalar dt)
|
||||
{
|
||||
btTransform start, end;
|
||||
|
||||
@@ -341,13 +392,15 @@ void KinematicCharacterController::warp (const btVector3& origin)
|
||||
m_collisionObject->setWorldTransform (xform);
|
||||
}
|
||||
|
||||
void KinematicCharacterController::registerPairCache (btOverlappingPairCache* pairCache)
|
||||
void KinematicCharacterController::registerPairCacheAndDispatcher (btOverlappingPairCache* pairCache, btCollisionDispatcher* dispatcher)
|
||||
{
|
||||
m_pairCache = pairCache;
|
||||
m_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
|
||||
void KinematicCharacterController::preStep (const btDynamicsWorld* dynamicsWorld)
|
||||
{
|
||||
|
||||
int numPenetrationLoops = 0;
|
||||
m_touchingContact = false;
|
||||
while (recoverFromPenetration (dynamicsWorld))
|
||||
@@ -356,7 +409,7 @@ void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
|
||||
m_touchingContact = true;
|
||||
if (numPenetrationLoops > 4)
|
||||
{
|
||||
printf("character could not recover from penetration = %d\n", numPenetrationLoops);
|
||||
// printf("character could not recover from penetration = %d\n", numPenetrationLoops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -364,6 +417,7 @@ void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
|
||||
xform = m_collisionObject->getWorldTransform ();
|
||||
|
||||
btVector3 forwardDir = xform.getBasis()[2];
|
||||
// printf("forwardDir=%f,%f,%f\n",forwardDir[0],forwardDir[1],forwardDir[2]);
|
||||
btVector3 upDir = xform.getBasis()[1];
|
||||
btVector3 strafeDir = xform.getBasis()[0];
|
||||
forwardDir.normalize ();
|
||||
@@ -376,11 +430,12 @@ void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
|
||||
|
||||
m_currentPosition = xform.getOrigin();
|
||||
m_targetPosition = m_currentPosition;
|
||||
// printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld,
|
||||
void KinematicCharacterController::playerStep (const btDynamicsWorld* dynamicsWorld,
|
||||
btScalar dt,
|
||||
int forward,
|
||||
int backward,
|
||||
@@ -406,6 +461,9 @@ void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld,
|
||||
btTransform xform;
|
||||
xform = m_collisionObject->getWorldTransform ();
|
||||
|
||||
// printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
|
||||
// printf("walkSpeed=%f\n",walkSpeed);
|
||||
|
||||
stepUp (dynamicsWorld);
|
||||
stepForwardAndStrafe (dynamicsWorld, walkDirection * walkSpeed);
|
||||
stepDown (dynamicsWorld, dt);
|
||||
|
||||
Reference in New Issue
Block a user