2
0

btPlayer.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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. mSlopeAngle = runSurfaceCos;
  64. mStepHeight = stepHeight;
  65. //if ( dStricmp( type, "Capsule" ) == 0 )
  66. {
  67. F32 radius = getMax( size.x, size.y ) * 0.5f;
  68. F32 height = size.z - ( radius * 2.0f );
  69. mColShape = new btCapsuleShapeZ( radius, height );
  70. mColShape->setMargin( 0.05f );
  71. mOriginOffset = ( height * 0.5 ) + radius;
  72. }
  73. //else
  74. {
  75. //mColShape = new btBoxShape( btVector3( 0.5f, 0.5f, 1.0f ) );
  76. //mOriginOffset = 1.0f;
  77. }
  78. mGhostObject = new btPairCachingGhostObject();
  79. mGhostObject->setCollisionShape( mColShape );
  80. mGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT );
  81. mWorld->getDynamicsWorld()->addCollisionObject( mGhostObject,
  82. btBroadphaseProxy::CharacterFilter,
  83. btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter );
  84. mUserData.setObject( obj );
  85. mGhostObject->setUserPointer( &mUserData );
  86. }
  87. Point3F BtPlayer::move( const VectorF &disp, CollisionList &outCol )
  88. {
  89. AssertFatal( mGhostObject, "BtPlayer::move - The controller is null!" );
  90. if (!mWorld->isEnabled())
  91. {
  92. btTransform currentTrans = mGhostObject->getWorldTransform();
  93. btVector3 currentPos = currentTrans.getOrigin();
  94. Point3F returnPos = btCast<Point3F>(currentPos);
  95. returnPos.z -= mOriginOffset;
  96. return returnPos;
  97. }
  98. // First recover from any penetrations from the previous tick.
  99. U32 numPenetrationLoops = 0;
  100. bool touchingContact = false;
  101. while ( _recoverFromPenetration() )
  102. {
  103. numPenetrationLoops++;
  104. touchingContact = true;
  105. if ( numPenetrationLoops > 4 )
  106. break;
  107. }
  108. btTransform newTrans = mGhostObject->getWorldTransform();
  109. btVector3 newPos = newTrans.getOrigin();
  110. // The move consists of 3 steps... the up step, the forward
  111. // step, and the down step.
  112. btVector3 forwardSweep( disp.x, disp.y, 0.0f );
  113. const bool hasForwardSweep = forwardSweep.length2() > 0.0f;
  114. F32 upSweep = 0.0f;
  115. F32 downSweep = 0.0f;
  116. if ( disp[2] < 0.0f )
  117. downSweep = disp[2];
  118. else
  119. upSweep = disp[2];
  120. // Only do auto stepping if the character is moving forward.
  121. F32 stepOffset = mStepHeight;
  122. if ( hasForwardSweep )
  123. upSweep += stepOffset;
  124. // First we do the up step which includes the passed in
  125. // upward displacement as well as the auto stepping.
  126. if ( upSweep > 0.0f &&
  127. _sweep( &newPos, btVector3( 0.0f, 0.0f, upSweep ), NULL ) )
  128. {
  129. // Keep track of how far we actually swept to make sure
  130. // we do not remove too much in the down sweep.
  131. F32 delta = newPos[2] - newTrans.getOrigin()[2];
  132. if ( delta < stepOffset )
  133. stepOffset = delta;
  134. }
  135. // Now do the forward step.
  136. _stepForward( &newPos, forwardSweep, &outCol );
  137. // Now remove what remains of our auto step
  138. // from the down sweep.
  139. if ( hasForwardSweep )
  140. downSweep -= stepOffset;
  141. // Do the downward sweep.
  142. if ( downSweep < 0.0f )
  143. _sweep( &newPos, btVector3( 0.0f, 0.0f, downSweep ), &outCol );
  144. // Finally update the ghost with its new position.
  145. newTrans.setOrigin( newPos );
  146. mGhostObject->setWorldTransform( newTrans );
  147. // Return the current position of the ghost.
  148. newPos[2] -= mOriginOffset;
  149. return btCast<Point3F>( newPos );
  150. }
  151. bool BtPlayer::_recoverFromPenetration()
  152. {
  153. bool penetration = false;
  154. btDynamicsWorld *collWorld = mWorld->getDynamicsWorld();
  155. collWorld->getDispatcher()->dispatchAllCollisionPairs( mGhostObject->getOverlappingPairCache(),
  156. collWorld->getDispatchInfo(),
  157. collWorld->getDispatcher() );
  158. btVector3 currPos = mGhostObject->getWorldTransform().getOrigin();
  159. btScalar maxPen = 0.0f;
  160. btManifoldArray manifoldArray;
  161. for ( U32 i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++ )
  162. {
  163. btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
  164. if ( ((btCollisionObject*)collisionPair->m_pProxy0->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE ||
  165. ((btCollisionObject*)collisionPair->m_pProxy1->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
  166. continue;
  167. manifoldArray.resize(0);
  168. if (collisionPair->m_algorithm)
  169. collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
  170. for ( U32 j=0; j < manifoldArray.size(); j++ )
  171. {
  172. btPersistentManifold* manifold = manifoldArray[j];
  173. btScalar directionSign = manifold->getBody0() == mGhostObject ? -1.0f : 1.0f;
  174. for ( U32 p=0; p < manifold->getNumContacts(); p++ )
  175. {
  176. const btManifoldPoint&pt = manifold->getContactPoint(p);
  177. if ( pt.getDistance() < -mColShape->getMargin() )
  178. {
  179. if ( pt.getDistance() < maxPen )
  180. {
  181. maxPen = pt.getDistance();
  182. //m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
  183. }
  184. currPos += pt.m_normalWorldOnB * directionSign * pt.getDistance(); // * 0.25f;
  185. penetration = true;
  186. }
  187. else
  188. {
  189. //printf("touching %f\n", pt.getDistance());
  190. }
  191. }
  192. //manifold->clearManifold();
  193. }
  194. }
  195. // Update the ghost transform.
  196. btTransform newTrans = mGhostObject->getWorldTransform();
  197. newTrans.setOrigin( currPos );
  198. mGhostObject->setWorldTransform( newTrans );
  199. return penetration;
  200. }
  201. class BtPlayerSweepCallback : public btCollisionWorld::ClosestConvexResultCallback
  202. {
  203. typedef btCollisionWorld::ClosestConvexResultCallback Parent;
  204. public:
  205. BtPlayerSweepCallback( btCollisionObject *me, const btVector3 &moveVec )
  206. : Parent( btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0) ),
  207. mMe( me ),
  208. mMoveVec( moveVec )
  209. {
  210. }
  211. virtual bool needsCollision(btBroadphaseProxy* proxy0) const
  212. {
  213. if ( proxy0->m_clientObject == mMe )
  214. return false;
  215. return Parent::needsCollision( proxy0 );
  216. }
  217. virtual btScalar addSingleResult( btCollisionWorld::LocalConvexResult &convexResult,
  218. bool normalInWorldSpace )
  219. {
  220. // NOTE: I shouldn't have to do any of this, but Bullet
  221. // has some weird bugs.
  222. //
  223. // For one the plane type will return hits on a Z up surface
  224. // for sweeps that have no Z sweep component.
  225. //
  226. // Second the normal returned here is sometimes backwards
  227. // to the sweep direction... no clue why.
  228. //
  229. F32 dotN = mMoveVec.dot( convexResult.m_hitNormalLocal );
  230. if ( mFabs( dotN ) < 0.1f )
  231. return 1.0f;
  232. if ( convexResult.m_hitCollisionObject->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
  233. return 1.0f;
  234. return Parent::addSingleResult( convexResult, normalInWorldSpace );
  235. }
  236. protected:
  237. btVector3 mMoveVec;
  238. btCollisionObject *mMe;
  239. };
  240. bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, CollisionList *outCol )
  241. {
  242. btTransform start( btTransform::getIdentity() );
  243. start.setOrigin ( *inOutCurrPos );
  244. btTransform end( btTransform::getIdentity() );
  245. end.setOrigin ( *inOutCurrPos + disp );
  246. BtPlayerSweepCallback callback( mGhostObject, disp.normalized() );
  247. callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
  248. callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
  249. if (disp.length()>0.0001)
  250. mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
  251. inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
  252. if ( callback.hasHit() )
  253. {
  254. if ( outCol )
  255. {
  256. Collision& col = outCol->increment();
  257. dMemset( &col, 0, sizeof( col ) );
  258. col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
  259. col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
  260. F32 vd = col.normal.z;
  261. if (vd < mSlopeAngle)
  262. return false;
  263. }
  264. return true;
  265. }
  266. return false;
  267. }
  268. void BtPlayer::_stepForward( btVector3 *inOutCurrPos, const btVector3 &displacement, CollisionList *outCol )
  269. {
  270. btTransform start( btTransform::getIdentity() );
  271. btTransform end( btTransform::getIdentity() );
  272. F32 fraction = 1.0f;
  273. S32 maxIter = 10;
  274. btVector3 disp = displacement;
  275. while ( fraction > 0.01f && maxIter-- > 0 )
  276. {
  277. // Setup the sweep start and end transforms.
  278. start.setOrigin( *inOutCurrPos );
  279. end.setOrigin( *inOutCurrPos + disp );
  280. BtPlayerSweepCallback callback( mGhostObject, disp.length2() > SIMD_EPSILON ? disp.normalized() : disp );
  281. callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
  282. callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
  283. if (disp.length()>0.0001)
  284. mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
  285. // Subtract from the travel fraction.
  286. fraction -= callback.m_closestHitFraction;
  287. // Did we get a hit?
  288. if ( callback.hasHit() )
  289. {
  290. /*
  291. // Get the real hit normal... Bullet returns the 'seperating normal' and not
  292. // the normal of the hit object.
  293. btTransform rayStart( btTransform::getIdentity() );
  294. rayStart.setOrigin( callback.m_hitPointWorld + callback.m_hitNormalWorld );
  295. btTransform rayEnd( btTransform::getIdentity() );
  296. rayEnd.setOrigin( callback.m_hitPointWorld - callback.m_hitNormalWorld );
  297. btCollisionWorld::ClosestRayResultCallback rayHit( rayStart.getOrigin(), rayEnd.getOrigin() );
  298. mWorld->getDynamicsWorld()->rayTestSingle( rayStart,
  299. rayEnd,
  300. callback.m_hitCollisionObject,
  301. callback.m_hitCollisionObject->getCollisionShape(),
  302. callback.m_hitCollisionObject->getWorldTransform(),
  303. rayHit );
  304. if ( !rayHit.hasHit() )
  305. break;
  306. */
  307. Collision& col = outCol->increment();
  308. dMemset( &col, 0, sizeof( col ) );
  309. col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
  310. col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
  311. // If the collision direction is sideways then modify the collision normal
  312. // to remove any z component. This takes care of any sideways collisions
  313. // with the round bottom of the capsule when it comes to the Player class
  314. // velocity calculations. We want all sideways collisions to be treated
  315. // as if they hit the side of a cylinder.
  316. if (col.normal.z > 0.0f)
  317. {
  318. // This will only remove the z component of the collision normal
  319. // for the bottom of the character controller, which would hit during
  320. // a step. We'll leave the top hemisphere of the character's capsule
  321. // alone as bumping one's head is an entirely different story. This
  322. // helps with low doorways.
  323. col.normal.z = 0.0f;
  324. col.normal.normalizeSafe();
  325. }
  326. // Interpolate to the new position.
  327. inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
  328. // Subtract out the displacement along the collision normal.
  329. F32 bd = -disp.dot( callback.m_hitNormalWorld );
  330. btVector3 dv = callback.m_hitNormalWorld * bd;
  331. disp += dv;
  332. }
  333. else
  334. {
  335. // we moved whole way
  336. *inOutCurrPos = end.getOrigin();
  337. break;
  338. }
  339. }
  340. }
  341. void BtPlayer::findContact( SceneObject **contactObject,
  342. VectorF *contactNormal,
  343. Vector<SceneObject*> *outOverlapObjects ) const
  344. {
  345. AssertFatal( mGhostObject, "BtPlayer::findContact - The controller is null!" );
  346. VectorF normal;
  347. F32 maxDot = -1.0f;
  348. // Go thru the contact points... get the first contact.
  349. btHashedOverlappingPairCache *pairCache = mGhostObject->getOverlappingPairCache();
  350. btBroadphasePairArray& pairArray = pairCache->getOverlappingPairArray();
  351. U32 numPairs = pairArray.size();
  352. btManifoldArray manifoldArray;
  353. for ( U32 i=0; i < numPairs; i++ )
  354. {
  355. const btBroadphasePair &pair = pairArray[i];
  356. btBroadphasePair *collisionPair = pairCache->findPair( pair.m_pProxy0, pair.m_pProxy1 );
  357. if ( !collisionPair || !collisionPair->m_algorithm )
  358. continue;
  359. btCollisionObject *other = (btCollisionObject*)pair.m_pProxy0->m_clientObject;
  360. if ( other == mGhostObject )
  361. other = (btCollisionObject*)pair.m_pProxy1->m_clientObject;
  362. if (!outOverlapObjects->contains(PhysicsUserData::getObject(other->getUserPointer())))
  363. outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
  364. if ( other->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
  365. continue;
  366. manifoldArray.clear();
  367. collisionPair->m_algorithm->getAllContactManifolds( manifoldArray );
  368. for ( U32 j=0; j < manifoldArray.size(); j++ )
  369. {
  370. btPersistentManifold *manifold = manifoldArray[j];
  371. btScalar directionSign = manifold->getBody0() == mGhostObject ? 1.0f : -1.0f;
  372. for ( U32 p=0; p < manifold->getNumContacts(); p++ )
  373. {
  374. const btManifoldPoint &pt = manifold->getContactPoint(p);
  375. // Test the normal... is it the most vertical one we got?
  376. normal = btCast<Point3F>( pt.m_normalWorldOnB * directionSign );
  377. F32 dot = mDot( normal, VectorF( 0, 0, 1 ) );
  378. if ( dot > maxDot )
  379. {
  380. maxDot = dot;
  381. btCollisionObject *colObject = (btCollisionObject*)collisionPair->m_pProxy0->m_clientObject;
  382. *contactObject = PhysicsUserData::getObject( colObject->getUserPointer() );
  383. *contactNormal = normal;
  384. }
  385. }
  386. }
  387. }
  388. }
  389. void BtPlayer::enableCollision()
  390. {
  391. AssertFatal( mGhostObject, "BtPlayer::enableCollision - The controller is null!" );
  392. //mController->setCollision( true );
  393. }
  394. void BtPlayer::disableCollision()
  395. {
  396. AssertFatal( mGhostObject, "BtPlayer::disableCollision - The controller is null!" );
  397. //mController->setCollision( false );
  398. }
  399. PhysicsWorld* BtPlayer::getWorld()
  400. {
  401. return mWorld;
  402. }
  403. void BtPlayer::setTransform( const MatrixF &transform )
  404. {
  405. AssertFatal( mGhostObject, "BtPlayer::setTransform - The ghost object is null!" );
  406. btTransform xfm = btCast<btTransform>( transform );
  407. xfm.getOrigin()[2] += mOriginOffset;
  408. mGhostObject->setWorldTransform( xfm );
  409. }
  410. MatrixF& BtPlayer::getTransform( MatrixF *outMatrix )
  411. {
  412. AssertFatal( mGhostObject, "BtPlayer::getTransform - The ghost object is null!" );
  413. *outMatrix = btCast<MatrixF>( mGhostObject->getWorldTransform() );
  414. *outMatrix[11] -= mOriginOffset;
  415. return *outMatrix;
  416. }
  417. void BtPlayer::setScale( const Point3F &scale )
  418. {
  419. }