PhysicsCharacter.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /**
  2. * PhysicsCharacter.cpp
  3. *
  4. * Much of the collision detection code for this implementation is based off the
  5. * btbtKinematicCharacterController class from Bullet Physics 2.7.6.
  6. */
  7. #include "Base.h"
  8. #include "PhysicsCharacter.h"
  9. #include "Scene.h"
  10. #include "Game.h"
  11. #include "PhysicsController.h"
  12. namespace gameplay
  13. {
  14. class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
  15. {
  16. public:
  17. /**
  18. * @see btCollisionWorld::ClosestConvexResultCallback::ClosestConvexResultCallback
  19. */
  20. ClosestNotMeConvexResultCallback(PhysicsCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
  21. : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), _me(me), _up(up), _minSlopeDot(minSlopeDot)
  22. {
  23. }
  24. /**
  25. * @see btCollisionWorld::ClosestConvexResultCallback::addSingleResult
  26. */
  27. btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
  28. {
  29. PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(convexResult.m_hitCollisionObject->getUserPointer());
  30. GP_ASSERT(object);
  31. if (object == _me || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
  32. return 1.0f;
  33. /*
  34. btVector3 hitNormalWorld;
  35. if (normalInWorldSpace)
  36. {
  37. hitNormalWorld = convexResult.m_hitNormalLocal;
  38. } else
  39. {
  40. // transform normal into worldspace
  41. hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
  42. }
  43. btScalar dotUp = _up.dot(hitNormalWorld);
  44. if (dotUp < _minSlopeDot)
  45. {
  46. return btScalar(1.0);
  47. }
  48. */
  49. return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
  50. }
  51. protected:
  52. PhysicsCollisionObject* _me;
  53. const btVector3 _up;
  54. btScalar _minSlopeDot;
  55. };
  56. PhysicsCharacter::PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape, float mass)
  57. : PhysicsGhostObject(node, shape), _moveVelocity(0,0,0), _forwardVelocity(0.0f), _rightVelocity(0.0f),
  58. _verticalVelocity(0, 0, 0), _currentVelocity(0,0,0), _normalizedVelocity(0,0,0),
  59. _colliding(false), _collisionNormal(0,0,0), _currentPosition(0,0,0), _stepHeight(0.1f),
  60. _slopeAngle(0.0f), _cosSlopeAngle(0.0f), _physicsEnabled(true), _mass(mass)
  61. {
  62. setMaxSlopeAngle(45.0f);
  63. // Set the collision flags on the ghost object to indicate it's a character.
  64. GP_ASSERT(_ghostObject);
  65. _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
  66. // Register ourselves as an action on the physics world so we are called back during physics ticks.
  67. GP_ASSERT(Game::getInstance()->getPhysicsController() && Game::getInstance()->getPhysicsController()->_world);
  68. Game::getInstance()->getPhysicsController()->_world->addAction(this);
  69. }
  70. PhysicsCharacter::~PhysicsCharacter()
  71. {
  72. // Unregister ourselves as action from world.
  73. GP_ASSERT(Game::getInstance()->getPhysicsController() && Game::getInstance()->getPhysicsController()->_world);
  74. Game::getInstance()->getPhysicsController()->_world->removeAction(this);
  75. }
  76. PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
  77. {
  78. // Check if the properties is valid and has a valid namespace.
  79. if (!properties || !(strcmp(properties->getNamespace(), "collisionObject") == 0))
  80. {
  81. GP_ERROR("Failed to load physics character from properties object: must be non-null object and have namespace equal to 'collisionObject'.");
  82. return NULL;
  83. }
  84. // Check that the type is specified and correct.
  85. const char* type = properties->getString("type");
  86. if (!type)
  87. {
  88. GP_ERROR("Failed to load physics character from properties object; required attribute 'type' is missing.");
  89. return NULL;
  90. }
  91. if (strcmp(type, "CHARACTER") != 0)
  92. {
  93. GP_ERROR("Failed to load physics character from properties object; attribute 'type' must be equal to 'CHARACTER'.");
  94. return NULL;
  95. }
  96. // Load the physics collision shape definition.
  97. PhysicsCollisionShape::Definition* shape = PhysicsCollisionShape::Definition::create(node, properties);
  98. if (shape == NULL)
  99. {
  100. GP_ERROR("Failed to create collision shape during physics character creation.");
  101. return NULL;
  102. }
  103. // Load the character's parameters.
  104. properties->rewind();
  105. float mass = 1.0f;
  106. float maxStepHeight = 0.1f;
  107. float maxSlopeAngle = 0.0f;
  108. const char* name = NULL;
  109. while ((name = properties->getNextProperty()) != NULL)
  110. {
  111. if (strcmp(name, "mass") == 0)
  112. {
  113. mass = properties->getFloat();
  114. }
  115. else if (strcmp(name, "maxStepHeight") == 0)
  116. {
  117. maxStepHeight = properties->getFloat();
  118. }
  119. else if (strcmp(name, "maxSlopeAngle") == 0)
  120. {
  121. maxSlopeAngle = properties->getFloat();
  122. }
  123. else
  124. {
  125. // Ignore this case (the attributes for the character's collision shape would end up here).
  126. }
  127. }
  128. // Create the physics character.
  129. PhysicsCharacter* character = new PhysicsCharacter(node, *shape, mass);
  130. character->setMaxStepHeight(maxStepHeight);
  131. character->setMaxSlopeAngle(maxSlopeAngle);
  132. SAFE_DELETE(shape);
  133. return character;
  134. }
  135. PhysicsCollisionObject::Type PhysicsCharacter::getType() const
  136. {
  137. return PhysicsCollisionObject::CHARACTER;
  138. }
  139. btCollisionObject* PhysicsCharacter::getCollisionObject() const
  140. {
  141. return _ghostObject;
  142. }
  143. bool PhysicsCharacter::isPhysicsEnabled() const
  144. {
  145. return _physicsEnabled;
  146. }
  147. void PhysicsCharacter::setPhysicsEnabled(bool enabled)
  148. {
  149. _physicsEnabled = enabled;
  150. }
  151. float PhysicsCharacter::getMaxStepHeight() const
  152. {
  153. return _stepHeight;
  154. }
  155. void PhysicsCharacter::setMaxStepHeight(float height)
  156. {
  157. _stepHeight = height;
  158. }
  159. float PhysicsCharacter::getMaxSlopeAngle() const
  160. {
  161. return _slopeAngle;
  162. }
  163. void PhysicsCharacter::setMaxSlopeAngle(float angle)
  164. {
  165. _slopeAngle = angle;
  166. _cosSlopeAngle = std::cos(MATH_DEG_TO_RAD(angle));
  167. }
  168. void PhysicsCharacter::setVelocity(const Vector3& velocity)
  169. {
  170. _moveVelocity.setValue(velocity.x, velocity.y, velocity.z);
  171. }
  172. void PhysicsCharacter::rotate(const Vector3& axis, float angle)
  173. {
  174. GP_ASSERT(_node);
  175. _node->rotate(axis, angle);
  176. }
  177. void PhysicsCharacter::rotate(const Quaternion& rotation)
  178. {
  179. GP_ASSERT(_node);
  180. _node->rotate(rotation);
  181. }
  182. void PhysicsCharacter::setRotation(const Vector3& axis, float angle)
  183. {
  184. GP_ASSERT(_node);
  185. _node->setRotation(axis, angle);
  186. }
  187. void PhysicsCharacter::setRotation(const Quaternion& rotation)
  188. {
  189. GP_ASSERT(_node);
  190. _node->setRotation(rotation);
  191. }
  192. void PhysicsCharacter::setForwardVelocity(float velocity)
  193. {
  194. _forwardVelocity = velocity;
  195. }
  196. void PhysicsCharacter::setRightVelocity(float velocity)
  197. {
  198. _rightVelocity = velocity;
  199. }
  200. Vector3 PhysicsCharacter::getCurrentVelocity() const
  201. {
  202. Vector3 v(_currentVelocity.x(), _currentVelocity.y(), _currentVelocity.z());
  203. v.x += _verticalVelocity.x();
  204. v.y += _verticalVelocity.y();
  205. v.z += _verticalVelocity.z();
  206. return v;
  207. }
  208. void PhysicsCharacter::jump(float height)
  209. {
  210. // TODO: Add support for different jump modes (i.e. double jump, changing direction in air, holding down jump button for extra height, etc)
  211. if (!_verticalVelocity.isZero())
  212. return;
  213. // v = sqrt(v0^2 + 2 a s)
  214. // v0 == initial velocity (zero for jumping)
  215. // a == acceleration (inverse gravity)
  216. // s == linear displacement (height)
  217. GP_ASSERT(Game::getInstance()->getPhysicsController());
  218. Vector3 jumpVelocity = -Game::getInstance()->getPhysicsController()->getGravity() * height * 2.0f;
  219. jumpVelocity.set(
  220. jumpVelocity.x == 0 ? 0 : std::sqrt(jumpVelocity.x),
  221. jumpVelocity.y == 0 ? 0 : std::sqrt(jumpVelocity.y),
  222. jumpVelocity.z == 0 ? 0 : std::sqrt(jumpVelocity.z));
  223. _verticalVelocity += BV(jumpVelocity);
  224. }
  225. void PhysicsCharacter::updateCurrentVelocity()
  226. {
  227. GP_ASSERT(_node);
  228. Vector3 temp;
  229. btScalar velocity2 = 0;
  230. // Reset velocity vector.
  231. _normalizedVelocity.setValue(0, 0, 0);
  232. // Add movement velocity contribution.
  233. if (!_moveVelocity.isZero())
  234. {
  235. _normalizedVelocity = _moveVelocity;
  236. velocity2 = _moveVelocity.length2();
  237. }
  238. // Add forward velocity contribution.
  239. if (_forwardVelocity != 0)
  240. {
  241. _node->getWorldMatrix().getForwardVector(&temp);
  242. temp.normalize();
  243. temp *= -_forwardVelocity;
  244. _normalizedVelocity += btVector3(temp.x, temp.y, temp.z);
  245. velocity2 = std::max(std::abs(velocity2), std::abs(_forwardVelocity*_forwardVelocity));
  246. }
  247. // Add right velocity contribution.
  248. if (_rightVelocity != 0)
  249. {
  250. _node->getWorldMatrix().getRightVector(&temp);
  251. temp.normalize();
  252. temp *= _rightVelocity;
  253. _normalizedVelocity += btVector3(temp.x, temp.y, temp.z);
  254. velocity2 = std::max(std::abs(velocity2), std::abs(_rightVelocity*_rightVelocity));
  255. }
  256. // Compute final combined movement vectors
  257. if (_normalizedVelocity.isZero())
  258. {
  259. _currentVelocity.setZero();
  260. }
  261. else
  262. {
  263. _normalizedVelocity.normalize();
  264. _currentVelocity = _normalizedVelocity * std::sqrt(velocity2);
  265. }
  266. }
  267. void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep)
  268. {
  269. GP_ASSERT(_ghostObject);
  270. GP_ASSERT(_node);
  271. // First check for existing collisions and attempt to respond/fix them.
  272. // Basically we are trying to move the character so that it does not penetrate
  273. // any other collision objects in the scene. We need to do this to ensure that
  274. // the following steps (movement) start from a clean slate, where the character
  275. // is not colliding with anything. Also, this step handles collision between
  276. // dynamic objects (i.e. objects that moved and now intersect the character).
  277. if (_physicsEnabled)
  278. {
  279. _colliding = false;
  280. int stepCount = 0;
  281. while (fixCollision(collisionWorld))
  282. {
  283. _colliding = true;
  284. if (++stepCount > 4)
  285. {
  286. // Most likely we are wedged between a number of different collision objects.
  287. break;
  288. }
  289. }
  290. }
  291. // Update current and target world positions.
  292. btVector3 startPosition = _ghostObject->getWorldTransform().getOrigin();
  293. _currentPosition = startPosition;
  294. // Process movement in the up direction.
  295. if (_physicsEnabled)
  296. stepUp(collisionWorld, deltaTimeStep);
  297. // Process horizontal movement.
  298. stepForwardAndStrafe(collisionWorld, deltaTimeStep);
  299. // Process movement in the down direction.
  300. if (_physicsEnabled)
  301. stepDown(collisionWorld, deltaTimeStep);
  302. // Set new position.
  303. btVector3 translation = _currentPosition - startPosition;
  304. _node->translate(translation.x(), translation.y(), translation.z());
  305. }
  306. void PhysicsCharacter::stepUp(btCollisionWorld* collisionWorld, btScalar time)
  307. {
  308. btVector3 targetPosition(_currentPosition);
  309. if (_verticalVelocity.isZero())
  310. {
  311. // Simply increase our poisiton by step height to enable us
  312. // to smoothly move over steps.
  313. targetPosition += btVector3(0, _stepHeight, 0);
  314. }
  315. // TODO: Convex sweep test to ensure we didn't hit anything during the step up.
  316. _currentPosition = targetPosition;
  317. }
  318. void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, float time)
  319. {
  320. updateCurrentVelocity();
  321. // Calculate final velocity
  322. btVector3 velocity(_currentVelocity);
  323. velocity *= time; // since velocity is in meters per second
  324. if (velocity.isZero())
  325. {
  326. // No velocity, so we aren't moving
  327. return;
  328. }
  329. // Translate the target position by the velocity vector (already scaled by t)
  330. btVector3 targetPosition = _currentPosition + velocity;
  331. // If physics is disabled, simply update current position without checking collisions
  332. if (!_physicsEnabled)
  333. {
  334. _currentPosition = targetPosition;
  335. return;
  336. }
  337. // Check for collisions by performing a bullet convex sweep test
  338. btTransform start;
  339. btTransform end;
  340. start.setIdentity();
  341. end.setIdentity();
  342. btScalar fraction = 1.0;
  343. btScalar distance2;
  344. if (_colliding && (_normalizedVelocity.dot(_collisionNormal) > btScalar(0.0)))
  345. {
  346. updateTargetPositionFromCollision(targetPosition, _collisionNormal);
  347. }
  348. int maxIter = 10;
  349. GP_ASSERT(_ghostObject && _ghostObject->getBroadphaseHandle());
  350. GP_ASSERT(_collisionShape);
  351. GP_ASSERT(collisionWorld);
  352. GP_ASSERT(Game::getInstance()->getPhysicsController());
  353. while (fraction > btScalar(0.01) && maxIter-- > 0)
  354. {
  355. start.setOrigin(_currentPosition);
  356. end.setOrigin(targetPosition);
  357. btVector3 sweepDirNegative(_currentPosition - targetPosition);
  358. ClosestNotMeConvexResultCallback callback(this, sweepDirNegative, btScalar(0.0));
  359. callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
  360. callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
  361. _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  362. fraction -= callback.m_closestHitFraction;
  363. if (callback.hasHit())
  364. {
  365. Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
  366. PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
  367. GP_ASSERT(o);
  368. if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
  369. {
  370. PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
  371. GP_ASSERT(rb);
  372. normal.normalize();
  373. rb->applyImpulse(_mass * -normal * velocity.length());
  374. }
  375. updateTargetPositionFromCollision(targetPosition, callback.m_hitNormalWorld);
  376. btVector3 currentDir = targetPosition - _currentPosition;
  377. distance2 = currentDir.length2();
  378. if (distance2 > FLT_EPSILON)
  379. {
  380. currentDir.normalize();
  381. // If velocity is against original velocity, stop to avoid tiny oscilations in sloping corners.
  382. if (currentDir.dot(_normalizedVelocity) <= btScalar(0.0))
  383. {
  384. break;
  385. }
  386. }
  387. }
  388. else
  389. {
  390. // Nothing in our way
  391. break;
  392. }
  393. }
  394. _currentPosition = targetPosition;
  395. }
  396. void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
  397. {
  398. GP_ASSERT(Game::getInstance()->getPhysicsController() && Game::getInstance()->getPhysicsController()->_world);
  399. GP_ASSERT(_ghostObject && _ghostObject->getBroadphaseHandle());
  400. GP_ASSERT(_collisionShape);
  401. GP_ASSERT(collisionWorld);
  402. // Contribute gravity to vertical velocity.
  403. btVector3 gravity = Game::getInstance()->getPhysicsController()->_world->getGravity();
  404. _verticalVelocity += (gravity * time);
  405. // Compute new position from vertical velocity.
  406. btVector3 targetPosition = _currentPosition + (_verticalVelocity * time);
  407. targetPosition -= btVector3(0, _stepHeight, 0);
  408. // Perform a convex sweep test between current and target position.
  409. btTransform start;
  410. btTransform end;
  411. start.setIdentity();
  412. end.setIdentity();
  413. btScalar fraction = 1.0;
  414. int maxIter = 10;
  415. while (fraction > btScalar(0.01) && maxIter-- > 0)
  416. {
  417. start.setOrigin(_currentPosition);
  418. end.setOrigin(targetPosition);
  419. btVector3 sweepDirNegative(_currentPosition - targetPosition);
  420. ClosestNotMeConvexResultCallback callback(this, sweepDirNegative, 0.0);
  421. callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
  422. callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
  423. _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  424. fraction -= callback.m_closestHitFraction;
  425. if (callback.hasHit())
  426. {
  427. // Collision detected, fix it.
  428. Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
  429. normal.normalize();
  430. float dot = normal.dot(Vector3::unitY());
  431. if (dot > 1.0f - MATH_EPSILON)
  432. {
  433. targetPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
  434. // Zero out fall velocity when we hit an object going straight down.
  435. _verticalVelocity.setZero();
  436. break;
  437. }
  438. else
  439. {
  440. PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
  441. GP_ASSERT(o);
  442. if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
  443. {
  444. PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
  445. GP_ASSERT(rb);
  446. normal.normalize();
  447. rb->applyImpulse(_mass * -normal * sqrt(BV(normal).dot(_verticalVelocity)));
  448. }
  449. updateTargetPositionFromCollision(targetPosition, BV(normal));
  450. }
  451. }
  452. else
  453. {
  454. // Nothing is in the way.
  455. break;
  456. }
  457. }
  458. // Calculate what the vertical velocity actually is.
  459. // In cases where the character might not actually be able to move down,
  460. // but isn't intersecting with an object straight down either, we don't
  461. // want to keep increasing the vertical velocity until the character
  462. // randomly drops through the floor when it can finally move due to its
  463. // vertical velocity having such a great magnitude.
  464. if (!_verticalVelocity.isZero() && time > 0.0f)
  465. _verticalVelocity = ((targetPosition + btVector3(0.0, _stepHeight, 0.0)) - _currentPosition) / time;
  466. _currentPosition = targetPosition;
  467. }
  468. /*
  469. * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'.
  470. */
  471. btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal)
  472. {
  473. return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
  474. }
  475. /*
  476. * Returns the portion of 'direction' that is parallel to 'normal'.
  477. */
  478. btVector3 parallelComponent(const btVector3& direction, const btVector3& normal)
  479. {
  480. btScalar magnitude = direction.dot(normal);
  481. return normal * magnitude;
  482. }
  483. /*
  484. * Returns the portion of 'direction' that is perpindicular to 'normal'.
  485. */
  486. btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal)
  487. {
  488. return direction - parallelComponent(direction, normal);
  489. }
  490. void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPosition, const btVector3& collisionNormal)
  491. {
  492. btVector3 movementDirection = targetPosition - _currentPosition;
  493. btScalar movementLength = movementDirection.length();
  494. if (movementLength > FLT_EPSILON)
  495. {
  496. movementDirection.normalize();
  497. btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
  498. reflectDir.normalize();
  499. btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
  500. targetPosition = _currentPosition;
  501. // Disallow the character from moving up during collision recovery (using an arbitrary reasonable epsilon).
  502. // Note that this will need to be generalized to allow for an arbitrary up axis.
  503. if (perpindicularDir.y() < _stepHeight + 0.001)
  504. {
  505. btVector3 perpComponent = perpindicularDir * movementLength;
  506. targetPosition += perpComponent;
  507. }
  508. }
  509. }
  510. bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
  511. {
  512. GP_ASSERT(_node);
  513. GP_ASSERT(_ghostObject);
  514. GP_ASSERT(world && world->getDispatcher());
  515. GP_ASSERT(Game::getInstance()->getPhysicsController());
  516. bool collision = false;
  517. btOverlappingPairCache* pairCache = _ghostObject->getOverlappingPairCache();
  518. GP_ASSERT(pairCache);
  519. // Tell the world to dispatch collision events for our ghost object.
  520. world->getDispatcher()->dispatchAllCollisionPairs(pairCache, world->getDispatchInfo(), world->getDispatcher());
  521. // Store our current world position.
  522. Vector3 startPosition;
  523. _node->getWorldMatrix().getTranslation(&startPosition);
  524. btVector3 currentPosition = BV(startPosition);
  525. // Handle all collisions/overlappign pairs.
  526. btScalar maxPenetration = btScalar(0.0);
  527. for (int i = 0, count = pairCache->getNumOverlappingPairs(); i < count; ++i)
  528. {
  529. _manifoldArray.resize(0);
  530. // Query contacts between this overlapping pair (store in _manifoldArray).
  531. btBroadphasePair* collisionPair = &pairCache->getOverlappingPairArray()[i];
  532. if (collisionPair->m_algorithm)
  533. {
  534. collisionPair->m_algorithm->getAllContactManifolds(_manifoldArray);
  535. }
  536. for (int j = 0, manifoldCount = _manifoldArray.size(); j < manifoldCount; ++j)
  537. {
  538. btPersistentManifold* manifold = _manifoldArray[j];
  539. GP_ASSERT(manifold);
  540. // Get the direction of the contact points (used to scale normal vector in the correct direction).
  541. btScalar directionSign = manifold->getBody0() == _ghostObject ? -1.0f : 1.0f;
  542. // Skip ghost objects.
  543. PhysicsCollisionObject* object = Game::getInstance()->getPhysicsController()->getCollisionObject(
  544. (btCollisionObject*)(manifold->getBody0() == _ghostObject ? manifold->getBody1() : manifold->getBody0()));
  545. if (!object || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
  546. continue;
  547. for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
  548. {
  549. const btManifoldPoint& pt = manifold->getContactPoint(p);
  550. // Get penetration distance for this contact point.
  551. btScalar dist = pt.getDistance();
  552. if (dist < 0.0)
  553. {
  554. // A negative distance means the objects are overlapping.
  555. if (dist < maxPenetration)
  556. {
  557. // Store collision normal for this point.
  558. maxPenetration = dist;
  559. _collisionNormal = pt.m_normalWorldOnB * directionSign;
  560. }
  561. // Calculate new position for object, which is translated back along the collision normal.
  562. currentPosition += pt.m_normalWorldOnB * directionSign * dist * 0.2f;
  563. collision = true;
  564. }
  565. }
  566. }
  567. }
  568. // Set the new world transformation to apply to fix the collision.
  569. _node->translate(Vector3(currentPosition.x(), currentPosition.y(), currentPosition.z()) - startPosition);
  570. return collision;
  571. }
  572. void PhysicsCharacter::debugDraw(btIDebugDraw* debugDrawer)
  573. {
  574. // debug drawing handled by PhysicsController
  575. }
  576. }