btPlayer.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "T3D/physics/bullet/btPlayer.h"
  24. #include "T3D/physics/physicsPlugin.h"
  25. #include "T3D/physics/bullet/btWorld.h"
  26. #include "T3D/physics/bullet/btCasts.h"
  27. #include "collision/collision.h"
  28. BtPlayer::BtPlayer()
  29. : PhysicsPlayer(),
  30. mWorld( NULL ),
  31. mObject( NULL ),
  32. mGhostObject( NULL ),
  33. mColShape( NULL ),
  34. mOriginOffset( 0.0f )
  35. {
  36. }
  37. BtPlayer::~BtPlayer()
  38. {
  39. _releaseController();
  40. }
  41. void BtPlayer::_releaseController()
  42. {
  43. if ( !mGhostObject )
  44. return;
  45. mWorld->getDynamicsWorld()->removeCollisionObject( mGhostObject );
  46. SAFE_DELETE( mGhostObject );
  47. SAFE_DELETE( mColShape );
  48. }
  49. void BtPlayer::init( const char *type,
  50. const Point3F &size,
  51. F32 runSurfaceCos,
  52. F32 stepHeight,
  53. SceneObject *obj,
  54. PhysicsWorld *world )
  55. {
  56. AssertFatal( obj, "BtPlayer::init - Got a null scene object!" );
  57. AssertFatal( world, "BtPlayer::init - Got a null world!" );
  58. AssertFatal( dynamic_cast<BtWorld*>( world ), "BtPlayer::init - The world is the wrong type!" );
  59. // Cleanup any previous controller.
  60. _releaseController();
  61. mObject = obj;
  62. mWorld = (BtWorld*)world;
  63. mStepHeight = stepHeight;
  64. //if ( dStricmp( type, "Capsule" ) == 0 )
  65. {
  66. F32 radius = getMax( size.x, size.y ) * 0.5f;
  67. F32 height = size.z - ( radius * 2.0f );
  68. mColShape = new btCapsuleShapeZ( radius, height );
  69. mColShape->setMargin( 0.05f );
  70. mOriginOffset = ( height * 0.5 ) + radius;
  71. }
  72. //else
  73. {
  74. //mColShape = new btBoxShape( btVector3( 0.5f, 0.5f, 1.0f ) );
  75. //mOriginOffset = 1.0f;
  76. }
  77. mGhostObject = new btPairCachingGhostObject();
  78. mGhostObject->setCollisionShape( mColShape );
  79. mGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT );
  80. mWorld->getDynamicsWorld()->addCollisionObject( mGhostObject,
  81. btBroadphaseProxy::CharacterFilter,
  82. btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter );
  83. mUserData.setObject( obj );
  84. mGhostObject->setUserPointer( &mUserData );
  85. }
  86. Point3F BtPlayer::move( const VectorF &disp, CollisionList &outCol )
  87. {
  88. AssertFatal( mGhostObject, "BtPlayer::move - The controller is null!" );
  89. // First recover from any penetrations from the previous tick.
  90. U32 numPenetrationLoops = 0;
  91. bool touchingContact = false;
  92. while ( _recoverFromPenetration() )
  93. {
  94. numPenetrationLoops++;
  95. touchingContact = true;
  96. if ( numPenetrationLoops > 4 )
  97. break;
  98. }
  99. btTransform newTrans = mGhostObject->getWorldTransform();
  100. btVector3 newPos = newTrans.getOrigin();
  101. // The move consists of 3 steps... the up step, the forward
  102. // step, and the down step.
  103. btVector3 forwardSweep( disp.x, disp.y, 0.0f );
  104. const bool hasForwardSweep = forwardSweep.length2() > 0.0f;
  105. F32 upSweep = 0.0f;
  106. F32 downSweep = 0.0f;
  107. if ( disp[2] < 0.0f )
  108. downSweep = disp[2];
  109. else
  110. upSweep = disp[2];
  111. // Only do auto stepping if the character is moving forward.
  112. F32 stepOffset = mStepHeight;
  113. if ( hasForwardSweep )
  114. upSweep += stepOffset;
  115. // First we do the up step which includes the passed in
  116. // upward displacement as well as the auto stepping.
  117. if ( upSweep > 0.0f &&
  118. _sweep( &newPos, btVector3( 0.0f, 0.0f, upSweep ), NULL ) )
  119. {
  120. // Keep track of how far we actually swept to make sure
  121. // we do not remove too much in the down sweep.
  122. F32 delta = newPos[2] - newTrans.getOrigin()[2];
  123. if ( delta < stepOffset )
  124. stepOffset = delta;
  125. }
  126. // Now do the forward step.
  127. _stepForward( &newPos, forwardSweep, &outCol );
  128. // Now remove what remains of our auto step
  129. // from the down sweep.
  130. if ( hasForwardSweep )
  131. downSweep -= stepOffset;
  132. // Do the downward sweep.
  133. if ( downSweep < 0.0f )
  134. _sweep( &newPos, btVector3( 0.0f, 0.0f, downSweep ), &outCol );
  135. // Finally update the ghost with its new position.
  136. newTrans.setOrigin( newPos );
  137. mGhostObject->setWorldTransform( newTrans );
  138. // Return the current position of the ghost.
  139. newPos[2] -= mOriginOffset;
  140. return btCast<Point3F>( newPos );
  141. }
  142. bool BtPlayer::_recoverFromPenetration()
  143. {
  144. bool penetration = false;
  145. btDynamicsWorld *collWorld = mWorld->getDynamicsWorld();
  146. collWorld->getDispatcher()->dispatchAllCollisionPairs( mGhostObject->getOverlappingPairCache(),
  147. collWorld->getDispatchInfo(),
  148. collWorld->getDispatcher() );
  149. btVector3 currPos = mGhostObject->getWorldTransform().getOrigin();
  150. btScalar maxPen = 0.0f;
  151. btManifoldArray manifoldArray;
  152. for ( U32 i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++ )
  153. {
  154. btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
  155. if ( ((btCollisionObject*)collisionPair->m_pProxy0->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE ||
  156. ((btCollisionObject*)collisionPair->m_pProxy1->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
  157. continue;
  158. manifoldArray.resize(0);
  159. if (collisionPair->m_algorithm)
  160. collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
  161. for ( U32 j=0; j < manifoldArray.size(); j++ )
  162. {
  163. btPersistentManifold* manifold = manifoldArray[j];
  164. btScalar directionSign = manifold->getBody0() == mGhostObject ? -1.0f : 1.0f;
  165. for ( U32 p=0; p < manifold->getNumContacts(); p++ )
  166. {
  167. const btManifoldPoint&pt = manifold->getContactPoint(p);
  168. if ( pt.getDistance() < -mColShape->getMargin() )
  169. {
  170. if ( pt.getDistance() < maxPen )
  171. {
  172. maxPen = pt.getDistance();
  173. //m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
  174. }
  175. currPos += pt.m_normalWorldOnB * directionSign * pt.getDistance(); // * 0.25f;
  176. penetration = true;
  177. }
  178. else
  179. {
  180. //printf("touching %f\n", pt.getDistance());
  181. }
  182. }
  183. //manifold->clearManifold();
  184. }
  185. }
  186. // Update the ghost transform.
  187. btTransform newTrans = mGhostObject->getWorldTransform();
  188. newTrans.setOrigin( currPos );
  189. mGhostObject->setWorldTransform( newTrans );
  190. return penetration;
  191. }
  192. class BtPlayerSweepCallback : public btCollisionWorld::ClosestConvexResultCallback
  193. {
  194. typedef btCollisionWorld::ClosestConvexResultCallback Parent;
  195. public:
  196. BtPlayerSweepCallback( btCollisionObject *me, const btVector3 &moveVec )
  197. : Parent( btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0) ),
  198. mMe( me ),
  199. mMoveVec( moveVec )
  200. {
  201. }
  202. virtual bool needsCollision(btBroadphaseProxy* proxy0) const
  203. {
  204. if ( proxy0->m_clientObject == mMe )
  205. return false;
  206. return Parent::needsCollision( proxy0 );
  207. }
  208. virtual btScalar addSingleResult( btCollisionWorld::LocalConvexResult &convexResult,
  209. bool normalInWorldSpace )
  210. {
  211. // NOTE: I shouldn't have to do any of this, but Bullet
  212. // has some weird bugs.
  213. //
  214. // For one the plane type will return hits on a Z up surface
  215. // for sweeps that have no Z sweep component.
  216. //
  217. // Second the normal returned here is sometimes backwards
  218. // to the sweep direction... no clue why.
  219. //
  220. F32 dotN = mMoveVec.dot( convexResult.m_hitNormalLocal );
  221. if ( mFabs( dotN ) < 0.1f )
  222. return 1.0f;
  223. if ( convexResult.m_hitCollisionObject->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
  224. return 1.0f;
  225. return Parent::addSingleResult( convexResult, normalInWorldSpace );
  226. }
  227. protected:
  228. btVector3 mMoveVec;
  229. btCollisionObject *mMe;
  230. };
  231. bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, CollisionList *outCol )
  232. {
  233. btTransform start( btTransform::getIdentity() );
  234. start.setOrigin ( *inOutCurrPos );
  235. btTransform end( btTransform::getIdentity() );
  236. end.setOrigin ( *inOutCurrPos + disp );
  237. BtPlayerSweepCallback callback( mGhostObject, disp.normalized() );
  238. callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
  239. callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
  240. if (disp.length()>0.0001)
  241. mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
  242. inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
  243. if ( callback.hasHit() )
  244. {
  245. if ( outCol )
  246. {
  247. Collision& col = outCol->increment();
  248. dMemset( &col, 0, sizeof( col ) );
  249. col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
  250. col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
  251. if (disp.z() < 0.0f)
  252. {
  253. // We're sweeping down as part of the stepping routine. In this
  254. // case we want to have the collision normal only point in the opposite direction.
  255. // i.e. up If we include the sideways part of the normal then the Player class
  256. // velocity calculations using this normal will affect the player's forwards
  257. // momentum. This is especially noticable on stairs as the rounded bottom of
  258. // the capsule slides up the corner of a stair.
  259. col.normal.set(0.0f, 0.0f, 1.0f);
  260. }
  261. }
  262. return true;
  263. }
  264. return false;
  265. }
  266. void BtPlayer::_stepForward( btVector3 *inOutCurrPos, const btVector3 &displacement, CollisionList *outCol )
  267. {
  268. btTransform start( btTransform::getIdentity() );
  269. btTransform end( btTransform::getIdentity() );
  270. F32 fraction = 1.0f;
  271. S32 maxIter = 10;
  272. btVector3 disp = displacement;
  273. while ( fraction > 0.01f && maxIter-- > 0 )
  274. {
  275. // Setup the sweep start and end transforms.
  276. start.setOrigin( *inOutCurrPos );
  277. end.setOrigin( *inOutCurrPos + disp );
  278. BtPlayerSweepCallback callback( mGhostObject, disp.length2() > 0.0f ? disp.normalized() : disp );
  279. callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
  280. callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
  281. mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
  282. // Subtract from the travel fraction.
  283. fraction -= callback.m_closestHitFraction;
  284. // Did we get a hit?
  285. if ( callback.hasHit() )
  286. {
  287. /*
  288. // Get the real hit normal... Bullet returns the 'seperating normal' and not
  289. // the normal of the hit object.
  290. btTransform rayStart( btTransform::getIdentity() );
  291. rayStart.setOrigin( callback.m_hitPointWorld + callback.m_hitNormalWorld );
  292. btTransform rayEnd( btTransform::getIdentity() );
  293. rayEnd.setOrigin( callback.m_hitPointWorld - callback.m_hitNormalWorld );
  294. btCollisionWorld::ClosestRayResultCallback rayHit( rayStart.getOrigin(), rayEnd.getOrigin() );
  295. mWorld->getDynamicsWorld()->rayTestSingle( rayStart,
  296. rayEnd,
  297. callback.m_hitCollisionObject,
  298. callback.m_hitCollisionObject->getCollisionShape(),
  299. callback.m_hitCollisionObject->getWorldTransform(),
  300. rayHit );
  301. if ( !rayHit.hasHit() )
  302. break;
  303. */
  304. Collision& col = outCol->increment();
  305. dMemset( &col, 0, sizeof( col ) );
  306. col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
  307. col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
  308. // If the collision direction is sideways then modify the collision normal
  309. // to remove any z component. This takes care of any sideways collisions
  310. // with the round bottom of the capsule when it comes to the Player class
  311. // velocity calculations. We want all sideways collisions to be treated
  312. // as if they hit the side of a cylinder.
  313. if (col.normal.z > 0.0f)
  314. {
  315. // This will only remove the z component of the collision normal
  316. // for the bottom of the character controller, which would hit during
  317. // a step. We'll leave the top hemisphere of the character's capsule
  318. // alone as bumping one's head is an entirely different story. This
  319. // helps with low doorways.
  320. col.normal.z = 0.0f;
  321. col.normal.normalizeSafe();
  322. }
  323. // Interpolate to the new position.
  324. inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
  325. // Subtract out the displacement along the collision normal.
  326. F32 bd = -disp.dot( callback.m_hitNormalWorld );
  327. btVector3 dv = callback.m_hitNormalWorld * bd;
  328. disp += dv;
  329. }
  330. else
  331. {
  332. // we moved whole way
  333. *inOutCurrPos = end.getOrigin();
  334. break;
  335. }
  336. }
  337. }
  338. void BtPlayer::findContact( SceneObject **contactObject,
  339. VectorF *contactNormal,
  340. Vector<SceneObject*> *outOverlapObjects ) const
  341. {
  342. AssertFatal( mGhostObject, "BtPlayer::findContact - The controller is null!" );
  343. VectorF normal;
  344. F32 maxDot = -1.0f;
  345. // Go thru the contact points... get the first contact.
  346. btHashedOverlappingPairCache *pairCache = mGhostObject->getOverlappingPairCache();
  347. btBroadphasePairArray& pairArray = pairCache->getOverlappingPairArray();
  348. U32 numPairs = pairArray.size();
  349. btManifoldArray manifoldArray;
  350. for ( U32 i=0; i < numPairs; i++ )
  351. {
  352. const btBroadphasePair &pair = pairArray[i];
  353. btBroadphasePair *collisionPair = pairCache->findPair( pair.m_pProxy0, pair.m_pProxy1 );
  354. if ( !collisionPair || !collisionPair->m_algorithm )
  355. continue;
  356. btCollisionObject *other = (btCollisionObject*)pair.m_pProxy0->m_clientObject;
  357. if ( other == mGhostObject )
  358. other = (btCollisionObject*)pair.m_pProxy1->m_clientObject;
  359. if (!outOverlapObjects->contains(PhysicsUserData::getObject(other->getUserPointer())))
  360. outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
  361. if ( other->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
  362. continue;
  363. manifoldArray.clear();
  364. collisionPair->m_algorithm->getAllContactManifolds( manifoldArray );
  365. for ( U32 j=0; j < manifoldArray.size(); j++ )
  366. {
  367. btPersistentManifold *manifold = manifoldArray[j];
  368. btScalar directionSign = manifold->getBody0() == mGhostObject ? 1.0f : -1.0f;
  369. for ( U32 p=0; p < manifold->getNumContacts(); p++ )
  370. {
  371. const btManifoldPoint &pt = manifold->getContactPoint(p);
  372. // Test the normal... is it the most vertical one we got?
  373. normal = btCast<Point3F>( pt.m_normalWorldOnB * directionSign );
  374. F32 dot = mDot( normal, VectorF( 0, 0, 1 ) );
  375. if ( dot > maxDot )
  376. {
  377. maxDot = dot;
  378. btCollisionObject *colObject = (btCollisionObject*)collisionPair->m_pProxy0->m_clientObject;
  379. *contactObject = PhysicsUserData::getObject( colObject->getUserPointer() );
  380. *contactNormal = normal;
  381. }
  382. }
  383. }
  384. }
  385. }
  386. void BtPlayer::enableCollision()
  387. {
  388. AssertFatal( mGhostObject, "BtPlayer::enableCollision - The controller is null!" );
  389. //mController->setCollision( true );
  390. }
  391. void BtPlayer::disableCollision()
  392. {
  393. AssertFatal( mGhostObject, "BtPlayer::disableCollision - The controller is null!" );
  394. //mController->setCollision( false );
  395. }
  396. PhysicsWorld* BtPlayer::getWorld()
  397. {
  398. return mWorld;
  399. }
  400. void BtPlayer::setTransform( const MatrixF &transform )
  401. {
  402. AssertFatal( mGhostObject, "BtPlayer::setTransform - The ghost object is null!" );
  403. btTransform xfm = btCast<btTransform>( transform );
  404. xfm.getOrigin()[2] += mOriginOffset;
  405. mGhostObject->setWorldTransform( xfm );
  406. }
  407. MatrixF& BtPlayer::getTransform( MatrixF *outMatrix )
  408. {
  409. AssertFatal( mGhostObject, "BtPlayer::getTransform - The ghost object is null!" );
  410. *outMatrix = btCast<MatrixF>( mGhostObject->getWorldTransform() );
  411. *outMatrix[11] -= mOriginOffset;
  412. return *outMatrix;
  413. }
  414. void BtPlayer::setScale( const Point3F &scale )
  415. {
  416. }