px3Player.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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/physx3/px3Player.h"
  24. #include "T3D/physics/physicsPlugin.h"
  25. #include "T3D/physics/physx3/px3World.h"
  26. #include "T3D/physics/physx3/px3Casts.h"
  27. #include "T3D/physics/physx3/px3Utils.h"
  28. #include "collision/collision.h"
  29. Px3Player::Px3Player()
  30. : PhysicsPlayer(),
  31. mController( NULL ),
  32. mWorld( NULL ),
  33. mObject( NULL ),
  34. mSkinWidth( 0.05f ),
  35. mOriginOffset( 0.0f ),
  36. mElapsed(0)
  37. {
  38. PHYSICSMGR->getPhysicsResetSignal().notify( this, &Px3Player::_onPhysicsReset );
  39. }
  40. Px3Player::~Px3Player()
  41. {
  42. _releaseController();
  43. PHYSICSMGR->getPhysicsResetSignal().remove( this, &Px3Player::_onPhysicsReset );
  44. }
  45. void Px3Player::_releaseController()
  46. {
  47. if ( mController )
  48. {
  49. mController->getActor()->userData = NULL;
  50. mWorld->getStaticChangedSignal().remove( this, &Px3Player::_onStaticChanged );
  51. mController->release();
  52. }
  53. }
  54. void Px3Player::init( const char *type,
  55. const Point3F &size,
  56. F32 runSurfaceCos,
  57. F32 stepHeight,
  58. SceneObject *obj,
  59. PhysicsWorld *world )
  60. {
  61. AssertFatal( obj, "Px3Player::init - Got a null scene object!" );
  62. AssertFatal( world, "Px3Player::init - Got a null world!" );
  63. AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Player::init - The world is the wrong type!" );
  64. // Cleanup any previous controller.
  65. _releaseController();
  66. mObject = obj;
  67. mWorld = (Px3World*)world;
  68. mOriginOffset = size.z * 0.5f;
  69. physx::PxCapsuleControllerDesc desc;
  70. desc.contactOffset = mSkinWidth;
  71. desc.radius = getMax( size.x, size.y ) * 0.5f;
  72. desc.radius -= mSkinWidth;
  73. desc.height = size.z - ( desc.radius * 2.0f );
  74. desc.height -= mSkinWidth * 2.0f;
  75. desc.climbingMode = physx::PxCapsuleClimbingMode::eCONSTRAINED;
  76. desc.position.set( 0, 0, 0 );
  77. desc.upDirection = physx::PxVec3(0,0,1);
  78. desc.reportCallback = this;
  79. desc.slopeLimit = runSurfaceCos;
  80. desc.stepOffset = stepHeight;
  81. desc.behaviorCallback = NULL;
  82. desc.material = gPhysics3SDK->createMaterial(0.1f, 0.1f, 0.2f);
  83. mController = mWorld->createController( desc );
  84. mWorld->getStaticChangedSignal().notify( this, &Px3Player::_onStaticChanged );
  85. physx::PxRigidDynamic *kineActor = mController->getActor();
  86. //player only has one shape
  87. physx::PxShape *shape = px3GetFirstShape(kineActor);
  88. physx::PxFilterData colData;
  89. colData.word0 = PX3_PLAYER;
  90. shape->setSimulationFilterData(colData);
  91. shape->setQueryFilterData(colData);
  92. //store geometry for later use in findContact calls
  93. shape->getCapsuleGeometry(mGeometry);
  94. mUserData.setObject( obj );
  95. kineActor->userData = &mUserData;
  96. }
  97. void Px3Player::_onStaticChanged()
  98. {
  99. if(mController)
  100. mController->invalidateCache();
  101. }
  102. void Px3Player::_onPhysicsReset( PhysicsResetEvent reset )
  103. {
  104. if(mController)
  105. mController->invalidateCache();
  106. }
  107. Point3F Px3Player::move( const VectorF &disp, CollisionList &outCol )
  108. {
  109. AssertFatal( mController, "Px3Player::move - The controller is null!" );
  110. // Return the last position if the simulation is stopped.
  111. //
  112. // See PxPlayer::_onPhysicsReset
  113. if ( !mWorld->isEnabled() )
  114. {
  115. Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
  116. newPos.z -= mOriginOffset;
  117. return newPos;
  118. }
  119. mWorld->releaseWriteLock();
  120. mCollisionList = &outCol;
  121. physx::PxVec3 dispNx( disp.x, disp.y, disp.z );
  122. if (mIsZero(disp.z))
  123. dispNx.z = 0.0f;
  124. U32 groups = 0xffffffff;
  125. groups &= ~( PX3_TRIGGER ); // No trigger shapes!
  126. groups &= ~( PX3_DEBRIS);
  127. physx::PxControllerFilters filter;
  128. physx::PxFilterData data;
  129. data.word0=groups;
  130. filter.mFilterData = &data;
  131. filter.mFilterFlags = physx::PxSceneQueryFilterFlags(physx::PxControllerFlag::eCOLLISION_DOWN|physx::PxControllerFlag::eCOLLISION_SIDES|physx::PxControllerFlag::eCOLLISION_UP);
  132. mController->move( dispNx,0.0001f,0, filter );
  133. Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
  134. newPos.z -= mOriginOffset;
  135. mCollisionList = NULL;
  136. return newPos;
  137. }
  138. void Px3Player::onShapeHit( const physx::PxControllerShapeHit& hit )
  139. {
  140. if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
  141. return;
  142. physx::PxRigidActor *actor = hit.actor;
  143. PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
  144. // Fill out the Collision
  145. // structure for use later.
  146. Collision &col = mCollisionList->increment();
  147. dMemset( &col, 0, sizeof( col ) );
  148. col.normal = px3Cast<Point3F>( hit.worldNormal );
  149. col.point = px3Cast<Point3F>( hit.worldPos );
  150. col.distance = hit.length;
  151. if ( userData )
  152. col.object = userData->getObject();
  153. if (mIsZero(hit.dir.z))
  154. {
  155. if (col.normal.z > 0.0f)
  156. {
  157. col.normal.z = 0.0f;
  158. col.normal.normalizeSafe();
  159. }
  160. }
  161. else
  162. {
  163. col.normal.set(0.0f, 0.0f, 1.0f);
  164. }
  165. }
  166. void Px3Player::onControllerHit( const physx::PxControllersHit& hit )
  167. {
  168. if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
  169. return;
  170. physx::PxRigidActor *actor = hit.other->getActor();
  171. PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
  172. // For controller-to-controller hit we don't have an actual hit point, so all
  173. // we can do is set the hit object.
  174. Collision &col = mCollisionList->increment();
  175. dMemset( &col, 0, sizeof( col ) );
  176. if ( userData )
  177. col.object = userData->getObject();
  178. }
  179. void Px3Player::findContact( SceneObject **contactObject,
  180. VectorF *contactNormal,
  181. Vector<SceneObject*> *outOverlapObjects ) const
  182. {
  183. // Calculate the sweep motion...
  184. F32 halfCapSize = mOriginOffset;
  185. F32 halfSmallCapSize = halfCapSize * 0.8f;
  186. F32 diff = halfCapSize - halfSmallCapSize;
  187. F32 distance = diff + mSkinWidth + 0.01f;
  188. physx::PxVec3 dir(0,0,-1);
  189. physx::PxScene *scene = mWorld->getScene();
  190. physx::PxHitFlags hitFlags(physx::PxHitFlag::eDEFAULT);
  191. physx::PxQueryFilterData filterData(physx::PxQueryFlag::eDYNAMIC|physx::PxQueryFlag::eSTATIC);
  192. filterData.data.word0 = PX3_DEFAULT;
  193. physx::PxSweepHit sweepHit;
  194. physx::PxRigidDynamic *actor= mController->getActor();
  195. physx::PxU32 shapeIndex;
  196. bool hit = physx::PxRigidBodyExt::linearSweepSingle(*actor,*scene,dir,distance,hitFlags,sweepHit,shapeIndex,filterData);
  197. if ( hit )
  198. {
  199. PhysicsUserData *data = PhysicsUserData::cast( sweepHit.actor->userData);
  200. if ( data )
  201. {
  202. *contactObject = data->getObject();
  203. *contactNormal = px3Cast<Point3F>( sweepHit.normal );
  204. }
  205. }
  206. // Check for overlapped objects ( triggers )
  207. if ( !outOverlapObjects )
  208. return;
  209. filterData.data.word0 = PX3_TRIGGER;
  210. const physx::PxU32 bufferSize = 10;
  211. physx::PxOverlapBufferN<bufferSize> hitBuffer;
  212. hit = scene->overlap(mGeometry,actor->getGlobalPose(),hitBuffer,filterData);
  213. if(hit)
  214. {
  215. for ( U32 i = 0; i < hitBuffer.nbTouches; i++ )
  216. {
  217. PhysicsUserData *data = PhysicsUserData::cast( hitBuffer.touches[i].actor->userData );
  218. if ( data )
  219. outOverlapObjects->push_back( data->getObject() );
  220. }
  221. }
  222. }
  223. void Px3Player::enableCollision()
  224. {
  225. AssertFatal( mController, "Px3Player::enableCollision - The controller is null!" );
  226. mWorld->releaseWriteLock();
  227. px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,true);
  228. }
  229. void Px3Player::disableCollision()
  230. {
  231. AssertFatal( mController, "Px3Player::disableCollision - The controller is null!" );
  232. mWorld->releaseWriteLock();
  233. px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false);
  234. }
  235. PhysicsWorld* Px3Player::getWorld()
  236. {
  237. return mWorld;
  238. }
  239. void Px3Player::setTransform( const MatrixF &transform )
  240. {
  241. AssertFatal( mController, "Px3Player::setTransform - The controller is null!" );
  242. mWorld->releaseWriteLock();
  243. Point3F newPos = transform.getPosition();
  244. newPos.z += mOriginOffset;
  245. const Point3F &curPos = px3Cast<Point3F>(mController->getPosition());
  246. if ( !(newPos - curPos ).isZero() )
  247. mController->setPosition( px3Cast<physx::PxExtendedVec3>(newPos) );
  248. }
  249. MatrixF& Px3Player::getTransform( MatrixF *outMatrix )
  250. {
  251. AssertFatal( mController, "Px3Player::getTransform - The controller is null!" );
  252. Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
  253. newPos.z -= mOriginOffset;
  254. outMatrix->setPosition( newPos );
  255. return *outMatrix;
  256. }
  257. void Px3Player::setScale( const Point3F &scale )
  258. {
  259. //Ignored
  260. }
  261. Box3F Px3Player::getWorldBounds()
  262. {
  263. physx::PxBounds3 bounds;
  264. physx::PxRigidDynamic *actor = mController->getActor();
  265. physx::PxShape *shape = px3GetFirstShape(actor);
  266. bounds = physx::PxShapeExt::getWorldBounds(*shape,*actor);
  267. return px3Cast<Box3F>( bounds );
  268. }
  269. bool Px3Player::testSpacials(const Point3F &nPos, const Point3F &nSize) const
  270. {
  271. F32 offset = nSize.z * 0.5f;
  272. F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
  273. F32 height = (nSize.z - (radius * 2.0f)) * 0.5f;
  274. height -= mSkinWidth * 2.0f;
  275. physx::PxCapsuleGeometry geom(radius, height);
  276. physx::PxVec3 pos(nPos.x, nPos.y, nPos.z + offset);
  277. physx::PxQuat orientation(Float_HalfPi, physx::PxVec3(0.0f, 1.0f, 0.0f));
  278. physx::PxOverlapBuffer hit;
  279. physx::PxQueryFilterData queryFilter(physx::PxQueryFlag::eANY_HIT | physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC);
  280. queryFilter.data.word0 = PX3_DEFAULT;
  281. bool hasHit = mWorld->getScene()->overlap(geom, physx::PxTransform(pos, orientation), hit, queryFilter);
  282. return !hasHit; // Return true if there are no overlapping objects
  283. }
  284. void Px3Player::setSpacials(const Point3F &nPos, const Point3F &nSize)
  285. {
  286. mOriginOffset = nSize.z * 0.5f;
  287. F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
  288. F32 height = nSize.z - (radius * 2.0f);
  289. height -= mSkinWidth * 2.0f;
  290. mWorld->releaseWriteLock();
  291. mController->resize(height);
  292. px3GetFirstShape(mController->getActor())->getCapsuleGeometry(mGeometry);
  293. }