00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "LinearMath/btIDebugDraw.h"
00018 #include "BulletCollision/CollisionDispatch/btGhostObject.h"
00019 #include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
00020 #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
00021 #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
00022 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
00023 #include "LinearMath/btDefaultMotionState.h"
00024 #include "btKinematicCharacterController.h"
00025
00026
00027
00028 static btVector3
00029 getNormalizedVector(const btVector3& v)
00030 {
00031 btVector3 n = v.normalized();
00032 if (n.length() < SIMD_EPSILON) {
00033 n.setValue(0, 0, 0);
00034 }
00035 return n;
00036 }
00037
00038
00045 class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
00046 {
00047 public:
00048 btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
00049 {
00050 m_me = me;
00051 }
00052
00053 virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
00054 {
00055 if (rayResult.m_collisionObject == m_me)
00056 return 1.0;
00057
00058 return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
00059 }
00060 protected:
00061 btCollisionObject* m_me;
00062 };
00063
00064 class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
00065 {
00066 public:
00067 btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
00068 {
00069 m_me = me;
00070 }
00071
00072 virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
00073 {
00074 if (convexResult.m_hitCollisionObject == m_me)
00075 return 1.0;
00076
00077 return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
00078 }
00079 protected:
00080 btCollisionObject* m_me;
00081 };
00082
00083
00084
00085
00086
00087
00088 btVector3 btKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal)
00089 {
00090 return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
00091 }
00092
00093
00094
00095
00096 btVector3 btKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal)
00097 {
00098 btScalar magnitude = direction.dot(normal);
00099 return normal * magnitude;
00100 }
00101
00102
00103
00104
00105 btVector3 btKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal)
00106 {
00107 return direction - parallelComponent(direction, normal);
00108 }
00109
00110 btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis)
00111 {
00112 m_upAxis = upAxis;
00113 m_addedMargin = 0.02f;
00114 m_walkDirection.setValue(0,0,0);
00115 m_useGhostObjectSweepTest = true;
00116 m_ghostObject = ghostObject;
00117 m_stepHeight = stepHeight;
00118 m_turnAngle = btScalar(0.0);
00119 m_convexShape=convexShape;
00120 m_useWalkDirection = true;
00121 m_velocityTimeInterval = 0.0;
00122 }
00123
00124 btKinematicCharacterController::~btKinematicCharacterController ()
00125 {
00126 }
00127
00128 btPairCachingGhostObject* btKinematicCharacterController::getGhostObject()
00129 {
00130 return m_ghostObject;
00131 }
00132
00133 bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld)
00134 {
00135
00136 bool penetration = false;
00137
00138 collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
00139
00140 m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
00141
00142 btScalar maxPen = btScalar(0.0);
00143 for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
00144 {
00145 m_manifoldArray.resize(0);
00146
00147 btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
00148
00149 if (collisionPair->m_algorithm)
00150 collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
00151
00152
00153 for (int j=0;j<m_manifoldArray.size();j++)
00154 {
00155 btPersistentManifold* manifold = m_manifoldArray[j];
00156 btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
00157 for (int p=0;p<manifold->getNumContacts();p++)
00158 {
00159 const btManifoldPoint&pt = manifold->getContactPoint(p);
00160
00161 if (pt.getDistance() < 0.0)
00162 {
00163 if (pt.getDistance() < maxPen)
00164 {
00165 maxPen = pt.getDistance();
00166 m_touchingNormal = pt.m_normalWorldOnB * directionSign;
00167
00168 }
00169 m_currentPosition += pt.m_normalWorldOnB * directionSign * pt.getDistance() * btScalar(0.2);
00170 penetration = true;
00171 } else {
00172
00173 }
00174 }
00175
00176
00177 }
00178 }
00179 btTransform newTrans = m_ghostObject->getWorldTransform();
00180 newTrans.setOrigin(m_currentPosition);
00181 m_ghostObject->setWorldTransform(newTrans);
00182
00183 return penetration;
00184 }
00185
00186 void btKinematicCharacterController::stepUp ( btCollisionWorld* world)
00187 {
00188
00189 btTransform start, end;
00190 m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * m_stepHeight;
00191
00192 start.setIdentity ();
00193 end.setIdentity ();
00194
00195
00196 start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * btScalar(0.1f));
00197 end.setOrigin (m_targetPosition);
00198
00199 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject);
00200 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
00201 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
00202
00203 if (m_useGhostObjectSweepTest)
00204 {
00205 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
00206 }
00207 else
00208 {
00209 world->convexSweepTest (m_convexShape, start, end, callback);
00210 }
00211
00212 if (callback.hasHit())
00213 {
00214
00215 m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
00216 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
00217 } else {
00218 m_currentStepOffset = m_stepHeight;
00219 m_currentPosition = m_targetPosition;
00220 }
00221 }
00222
00223 void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
00224 {
00225 btVector3 movementDirection = m_targetPosition - m_currentPosition;
00226 btScalar movementLength = movementDirection.length();
00227 if (movementLength>SIMD_EPSILON)
00228 {
00229 movementDirection.normalize();
00230
00231 btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
00232 reflectDir.normalize();
00233
00234 btVector3 parallelDir, perpindicularDir;
00235
00236 parallelDir = parallelComponent (reflectDir, hitNormal);
00237 perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
00238
00239 m_targetPosition = m_currentPosition;
00240 if (0)
00241 {
00242 btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
00243
00244 m_targetPosition += parComponent;
00245 }
00246
00247 if (normalMag != 0.0)
00248 {
00249 btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
00250
00251 m_targetPosition += perpComponent;
00252 }
00253 } else
00254 {
00255
00256 }
00257 }
00258
00259 void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove)
00260 {
00261
00262
00263
00264 btTransform start, end;
00265 m_targetPosition = m_currentPosition + walkMove;
00266 start.setIdentity ();
00267 end.setIdentity ();
00268
00269 btScalar fraction = 1.0;
00270 btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
00271
00272
00273 if (m_touchingContact)
00274 {
00275 if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0))
00276 updateTargetPositionBasedOnCollision (m_touchingNormal);
00277 }
00278
00279 int maxIter = 10;
00280
00281 while (fraction > btScalar(0.01) && maxIter-- > 0)
00282 {
00283 start.setOrigin (m_currentPosition);
00284 end.setOrigin (m_targetPosition);
00285
00286 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject);
00287 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
00288 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
00289
00290
00291 btScalar margin = m_convexShape->getMargin();
00292 m_convexShape->setMargin(margin + m_addedMargin);
00293
00294
00295 if (m_useGhostObjectSweepTest)
00296 {
00297 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00298 } else
00299 {
00300 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00301 }
00302
00303 m_convexShape->setMargin(margin);
00304
00305
00306 fraction -= callback.m_closestHitFraction;
00307
00308 if (callback.hasHit())
00309 {
00310
00311 btScalar hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
00312 if (hitDistance<0.f)
00313 {
00314
00315 }
00316
00317
00318 if (hitDistance > m_addedMargin)
00319 {
00320
00321 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
00322 }
00323
00324 updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
00325 btVector3 currentDir = m_targetPosition - m_currentPosition;
00326 distance2 = currentDir.length2();
00327 if (distance2 > SIMD_EPSILON)
00328 {
00329 currentDir.normalize();
00330
00331 if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
00332 {
00333 break;
00334 }
00335 } else
00336 {
00337
00338 break;
00339 }
00340 } else {
00341
00342 m_currentPosition = m_targetPosition;
00343 }
00344
00345
00346
00347
00348 }
00349 }
00350
00351 void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt)
00352 {
00353 btTransform start, end;
00354
00355
00356 btVector3 step_drop = getUpAxisDirections()[m_upAxis] * m_currentStepOffset;
00357 btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * m_stepHeight;
00358 m_targetPosition -= (step_drop + gravity_drop);
00359
00360 start.setIdentity ();
00361 end.setIdentity ();
00362
00363 start.setOrigin (m_currentPosition);
00364 end.setOrigin (m_targetPosition);
00365
00366 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject);
00367 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
00368 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
00369
00370 if (m_useGhostObjectSweepTest)
00371 {
00372 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00373 } else
00374 {
00375 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00376 }
00377
00378 if (callback.hasHit())
00379 {
00380
00381 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
00382 } else {
00383
00384
00385 m_currentPosition = m_targetPosition;
00386 }
00387 }
00388
00389
00390
00391 void btKinematicCharacterController::setWalkDirection
00392 (
00393 const btVector3& walkDirection
00394 )
00395 {
00396 m_useWalkDirection = true;
00397 m_walkDirection = walkDirection;
00398 m_normalizedDirection = getNormalizedVector(m_walkDirection);
00399 }
00400
00401
00402
00403 void btKinematicCharacterController::setVelocityForTimeInterval
00404 (
00405 const btVector3& velocity,
00406 btScalar timeInterval
00407 )
00408 {
00409
00410
00411
00412
00413
00414 m_useWalkDirection = false;
00415 m_walkDirection = velocity;
00416 m_normalizedDirection = getNormalizedVector(m_walkDirection);
00417 m_velocityTimeInterval = timeInterval;
00418 }
00419
00420
00421
00422 void btKinematicCharacterController::reset ()
00423 {
00424 }
00425
00426 void btKinematicCharacterController::warp (const btVector3& origin)
00427 {
00428 btTransform xform;
00429 xform.setIdentity();
00430 xform.setOrigin (origin);
00431 m_ghostObject->setWorldTransform (xform);
00432 }
00433
00434
00435 void btKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld)
00436 {
00437
00438 int numPenetrationLoops = 0;
00439 m_touchingContact = false;
00440 while (recoverFromPenetration (collisionWorld))
00441 {
00442 numPenetrationLoops++;
00443 m_touchingContact = true;
00444 if (numPenetrationLoops > 4)
00445 {
00446
00447 break;
00448 }
00449 }
00450
00451 m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
00452 m_targetPosition = m_currentPosition;
00453
00454
00455
00456 }
00457
00458 void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt)
00459 {
00460
00461
00462
00463
00464 if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) {
00465
00466 return;
00467 }
00468
00469 btTransform xform;
00470 xform = m_ghostObject->getWorldTransform ();
00471
00472
00473
00474
00475 stepUp (collisionWorld);
00476 if (m_useWalkDirection) {
00477 stepForwardAndStrafe (collisionWorld, m_walkDirection);
00478 } else {
00479
00480
00481 btScalar dtMoving =
00482 (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval;
00483 m_velocityTimeInterval -= dt;
00484
00485
00486 btVector3 move = m_walkDirection * dtMoving;
00487
00488
00489
00490
00491 stepForwardAndStrafe(collisionWorld, move);
00492 }
00493 stepDown (collisionWorld, dt);
00494
00495
00496
00497 xform.setOrigin (m_currentPosition);
00498 m_ghostObject->setWorldTransform (xform);
00499 }
00500
00501 void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
00502 {
00503 m_fallSpeed = fallSpeed;
00504 }
00505
00506 void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
00507 {
00508 m_jumpSpeed = jumpSpeed;
00509 }
00510
00511 void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
00512 {
00513 m_maxJumpHeight = maxJumpHeight;
00514 }
00515
00516 bool btKinematicCharacterController::canJump () const
00517 {
00518 return onGround();
00519 }
00520
00521 void btKinematicCharacterController::jump ()
00522 {
00523 if (!canJump())
00524 return;
00525
00526 #if 0
00527 currently no jumping.
00528 btTransform xform;
00529 m_rigidBody->getMotionState()->getWorldTransform (xform);
00530 btVector3 up = xform.getBasis()[1];
00531 up.normalize ();
00532 btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
00533 m_rigidBody->applyCentralImpulse (up * magnitude);
00534 #endif
00535 }
00536
00537 bool btKinematicCharacterController::onGround () const
00538 {
00539 return true;
00540 }
00541
00542
00543 void btKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer)
00544 {
00545 }
00546
00547
00548 btVector3* btKinematicCharacterController::getUpAxisDirections()
00549 {
00550 static btVector3 sUpAxisDirection[3] = { btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f) };
00551
00552 return sUpAxisDirection;
00553 }