BsPhysX.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  1. #include "BsPhysX.h"
  2. #include "PxPhysicsAPI.h"
  3. #include "BsPhysXMaterial.h"
  4. #include "BsPhysXMesh.h"
  5. #include "BsPhysXRigidbody.h"
  6. #include "BsPhysXBoxCollider.h"
  7. #include "BsPhysXSphereCollider.h"
  8. #include "BsPhysXPlaneCollider.h"
  9. #include "BsPhysXCapsuleCollider.h"
  10. #include "BsPhysXMeshCollider.h"
  11. #include "BsPhysXFixedJoint.h"
  12. #include "BsPhysXDistanceJoint.h"
  13. #include "BsPhysXHingeJoint.h"
  14. #include "BsPhysXSphericalJoint.h"
  15. #include "BsPhysXSliderJoint.h"
  16. #include "BsPhysXD6Joint.h"
  17. #include "BsPhysXCharacterController.h"
  18. #include "Threading/BsTaskScheduler.h"
  19. #include "Components/BsCCollider.h"
  20. #include "BsFPhysXCollider.h"
  21. #include "Utility/BsTime.h"
  22. #include "Math/BsVector3.h"
  23. #include "Math/BsAABox.h"
  24. #include "Math/BsCapsule.h"
  25. #include "foundation/PxTransform.h"
  26. using namespace physx;
  27. namespace bs
  28. {
  29. class PhysXAllocator : public PxAllocatorCallback
  30. {
  31. public:
  32. void* allocate(size_t size, const char*, const char*, int) override
  33. {
  34. void* ptr = bs_alloc_aligned16((UINT32)size);
  35. PX_ASSERT((reinterpret_cast<size_t>(ptr) & 15) == 0);
  36. return ptr;
  37. }
  38. void deallocate(void* ptr) override
  39. {
  40. bs_free_aligned16(ptr);
  41. }
  42. };
  43. class PhysXErrorCallback : public PxErrorCallback
  44. {
  45. public:
  46. void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) override
  47. {
  48. const char* errorCode = nullptr;
  49. UINT32 severity = 0;
  50. if ((code & PxErrorCode::eDEBUG_INFO) != 0)
  51. {
  52. errorCode = "Info";
  53. severity = 0;
  54. }
  55. if((code & PxErrorCode::eINVALID_PARAMETER) != 0)
  56. {
  57. errorCode = "Invalid parameter";
  58. severity = 1;
  59. }
  60. if ((code & PxErrorCode::eINVALID_OPERATION) != 0)
  61. {
  62. errorCode = "Invalid operation";
  63. severity = 1;
  64. }
  65. if ((code & PxErrorCode::eDEBUG_WARNING) != 0)
  66. {
  67. errorCode = "Generic";
  68. severity = 1;
  69. }
  70. if ((code & PxErrorCode::ePERF_WARNING) != 0)
  71. {
  72. errorCode = "Performance";
  73. severity = 1;
  74. }
  75. if ((code & PxErrorCode::eOUT_OF_MEMORY) != 0)
  76. {
  77. errorCode = "Out of memory";
  78. severity = 2;
  79. }
  80. if ((code & PxErrorCode::eABORT) != 0)
  81. {
  82. errorCode = "Abort";
  83. severity = 2;
  84. }
  85. if ((code & PxErrorCode::eINTERNAL_ERROR) != 0)
  86. {
  87. errorCode = "Internal";
  88. severity = 2;
  89. }
  90. StringStream ss;
  91. switch(severity)
  92. {
  93. case 0:
  94. ss << "PhysX info (" << errorCode << "): " << message << " at " << file << ":" << line;
  95. LOGDBG(ss.str());
  96. break;
  97. case 1:
  98. ss << "PhysX warning (" << errorCode << "): " << message << " at " << file << ":" << line;
  99. LOGWRN(ss.str());
  100. break;
  101. case 2:
  102. ss << "PhysX error (" << errorCode << "): " << message << " at " << file << ":" << line;
  103. LOGERR(ss.str());
  104. BS_ASSERT(false); // Halt execution on debug builds when error occurs
  105. break;
  106. }
  107. }
  108. };
  109. class PhysXEventCallback : public PxSimulationEventCallback
  110. {
  111. void onWake(PxActor** actors, PxU32 count) override { /* Do nothing */ }
  112. void onSleep(PxActor** actors, PxU32 count) override { /* Do nothing */ }
  113. void onTrigger(PxTriggerPair* pairs, PxU32 count) override
  114. {
  115. for (PxU32 i = 0; i < count; i++)
  116. {
  117. const PxTriggerPair& pair = pairs[i];
  118. if (pair.triggerShape->userData == nullptr)
  119. continue;
  120. PhysX::ContactEventType type;
  121. bool ignoreContact = false;
  122. PhysXObjectFilterFlags flags = PhysXObjectFilterFlags(pair.triggerShape->getSimulationFilterData().word2);
  123. if (flags.isSet(PhysXObjectFilterFlag::ReportAll))
  124. {
  125. switch ((UINT32)pair.status)
  126. {
  127. case PxPairFlag::eNOTIFY_TOUCH_FOUND:
  128. type = PhysX::ContactEventType::ContactBegin;
  129. break;
  130. case PxPairFlag::eNOTIFY_TOUCH_PERSISTS:
  131. type = PhysX::ContactEventType::ContactStay;
  132. break;
  133. case PxPairFlag::eNOTIFY_TOUCH_LOST:
  134. type = PhysX::ContactEventType::ContactEnd;
  135. break;
  136. default:
  137. ignoreContact = true;
  138. break;
  139. }
  140. }
  141. else if (flags.isSet(PhysXObjectFilterFlag::ReportBasic))
  142. {
  143. switch ((UINT32)pair.status)
  144. {
  145. case PxPairFlag::eNOTIFY_TOUCH_FOUND:
  146. type = PhysX::ContactEventType::ContactBegin;
  147. break;
  148. case PxPairFlag::eNOTIFY_TOUCH_LOST:
  149. type = PhysX::ContactEventType::ContactEnd;
  150. break;
  151. default:
  152. ignoreContact = true;
  153. break;
  154. }
  155. }
  156. else
  157. ignoreContact = true;
  158. if (ignoreContact)
  159. continue;
  160. PhysX::TriggerEvent event;
  161. event.trigger = (Collider*)pair.triggerShape->userData;
  162. event.other = (Collider*)pair.otherShape->userData;
  163. event.type = type;
  164. gPhysX()._reportTriggerEvent(event);
  165. }
  166. }
  167. void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 count) override
  168. {
  169. for (PxU32 i = 0; i < count; i++)
  170. {
  171. const PxContactPair& pair = pairs[i];
  172. PhysX::ContactEventType type;
  173. bool ignoreContact = false;
  174. switch((UINT32)pair.events)
  175. {
  176. case PxPairFlag::eNOTIFY_TOUCH_FOUND:
  177. type = PhysX::ContactEventType::ContactBegin;
  178. break;
  179. case PxPairFlag::eNOTIFY_TOUCH_PERSISTS:
  180. type = PhysX::ContactEventType::ContactStay;
  181. break;
  182. case PxPairFlag::eNOTIFY_TOUCH_LOST:
  183. type = PhysX::ContactEventType::ContactEnd;
  184. break;
  185. default:
  186. ignoreContact = true;
  187. break;
  188. }
  189. if (ignoreContact)
  190. continue;
  191. PhysX::ContactEvent event;
  192. event.type = type;
  193. PxU32 contactCount = pair.contactCount;
  194. const PxU8* stream = pair.contactStream;
  195. PxU16 streamSize = pair.contactStreamSize;
  196. if (contactCount > 0 && streamSize > 0)
  197. {
  198. PxU32 contactIdx = 0;
  199. PxContactStreamIterator iter((PxU8*)stream, streamSize);
  200. stream += ((streamSize + 15) & ~15);
  201. const PxReal* impulses = reinterpret_cast<const PxReal*>(stream);
  202. PxU32 hasImpulses = (pair.flags & PxContactPairFlag::eINTERNAL_HAS_IMPULSES);
  203. while (iter.hasNextPatch())
  204. {
  205. iter.nextPatch();
  206. while (iter.hasNextContact())
  207. {
  208. iter.nextContact();
  209. ContactPoint point;
  210. point.position = fromPxVector(iter.getContactPoint());
  211. point.separation = iter.getSeparation();
  212. point.normal = fromPxVector(iter.getContactNormal());
  213. if (hasImpulses)
  214. point.impulse = impulses[contactIdx];
  215. else
  216. point.impulse = 0.0f;
  217. event.points.push_back(point);
  218. contactIdx++;
  219. }
  220. }
  221. }
  222. event.colliderA = (Collider*)pair.shapes[0]->userData;
  223. event.colliderB = (Collider*)pair.shapes[1]->userData;
  224. gPhysX()._reportContactEvent(event);
  225. }
  226. }
  227. void onConstraintBreak(PxConstraintInfo* constraints, PxU32 count) override
  228. {
  229. for (UINT32 i = 0; i < count; i++)
  230. {
  231. PxConstraintInfo& constraintInfo = constraints[i];
  232. if (constraintInfo.type != PxConstraintExtIDs::eJOINT)
  233. continue;
  234. PxJoint* pxJoint = (PxJoint*)constraintInfo.externalReference;
  235. PhysX::JointBreakEvent event;
  236. event.joint = (Joint*)pxJoint->userData;
  237. if(event.joint != nullptr)
  238. gPhysX()._reportJointBreakEvent(event);
  239. }
  240. }
  241. };
  242. class PhysXCPUDispatcher : public PxCpuDispatcher
  243. {
  244. public:
  245. void submitTask(PxBaseTask& physxTask) override
  246. {
  247. // Note: Banshee's task scheduler is pretty low granularity. Consider a better task manager in case PhysX ends
  248. // up submitting many tasks.
  249. // - PhysX's task manager doesn't seem much lighter either. But perhaps I can at least create a task pool to
  250. // avoid allocating them constantly.
  251. auto runTask = [&]() { physxTask.run(); physxTask.release(); };
  252. SPtr<Task> task = Task::create("PhysX", runTask);
  253. TaskScheduler::instance().addTask(task);
  254. }
  255. PxU32 getWorkerCount() const override
  256. {
  257. return (PxU32)TaskScheduler::instance().getNumWorkers();
  258. }
  259. };
  260. class PhysXBroadPhaseCallback : public PxBroadPhaseCallback
  261. {
  262. void onObjectOutOfBounds(PxShape& shape, PxActor& actor) override
  263. {
  264. Collider* collider = (Collider*)shape.userData;
  265. if (collider != nullptr)
  266. LOGWRN("Physics object out of bounds. Consider increasing broadphase region!");
  267. }
  268. void onObjectOutOfBounds(PxAggregate& aggregate) override { /* Do nothing */ }
  269. };
  270. PxFilterFlags PhysXFilterShader(PxFilterObjectAttributes attr0, PxFilterData data0, PxFilterObjectAttributes attr1,
  271. PxFilterData data1, PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
  272. {
  273. PhysXObjectFilterFlags flags0 = PhysXObjectFilterFlags(data0.word2);
  274. PhysXObjectFilterFlags flags1 = PhysXObjectFilterFlags(data1.word2);
  275. if (flags0.isSet(PhysXObjectFilterFlag::ReportAll) || flags1.isSet(PhysXObjectFilterFlag::ReportAll))
  276. pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_LOST | PxPairFlag::eNOTIFY_TOUCH_PERSISTS | PxPairFlag::eNOTIFY_CONTACT_POINTS;
  277. else if (flags0.isSet(PhysXObjectFilterFlag::ReportBasic) || flags1.isSet(PhysXObjectFilterFlag::ReportBasic))
  278. pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_LOST | PxPairFlag::eNOTIFY_CONTACT_POINTS;
  279. if (PxFilterObjectIsTrigger(attr0) || PxFilterObjectIsTrigger(attr1))
  280. {
  281. if (!pairFlags)
  282. return PxFilterFlag::eSUPPRESS; // Trigger with no notify flags
  283. pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
  284. return PxFilterFlags();
  285. }
  286. UINT64 groupA = *(UINT64*)&data0.word0;
  287. UINT64 groupB = *(UINT64*)&data1.word0;
  288. bool canCollide = gPhysics().isCollisionEnabled(groupA, groupB);
  289. if (!canCollide)
  290. return PxFilterFlag::eSUPPRESS;
  291. if (flags0.isSet(PhysXObjectFilterFlag::CCD) || flags1.isSet(PhysXObjectFilterFlag::CCD))
  292. pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT;
  293. pairFlags |= PxPairFlag::eSOLVE_CONTACT | PxPairFlag::eDETECT_DISCRETE_CONTACT;
  294. return PxFilterFlags();
  295. }
  296. void parseHit(const PxRaycastHit& input, PhysicsQueryHit& output)
  297. {
  298. output.point = fromPxVector(input.position);
  299. output.normal = fromPxVector(input.normal);
  300. output.distance = input.distance;
  301. output.triangleIdx = input.faceIndex;
  302. output.uv = Vector2(input.u, input.v);
  303. output.colliderRaw = (Collider*)input.shape->userData;
  304. if (output.colliderRaw != nullptr)
  305. {
  306. CCollider* component = (CCollider*)output.colliderRaw->_getOwner(PhysicsOwnerType::Component);
  307. if (component != nullptr)
  308. output.collider = component->getHandle();
  309. }
  310. }
  311. void parseHit(const PxSweepHit& input, PhysicsQueryHit& output)
  312. {
  313. output.point = fromPxVector(input.position);
  314. output.normal = fromPxVector(input.normal);
  315. output.uv = Vector2::ZERO;
  316. output.distance = input.distance;
  317. output.triangleIdx = input.faceIndex;
  318. output.colliderRaw = (Collider*)input.shape->userData;
  319. if (output.colliderRaw != nullptr)
  320. {
  321. CCollider* component = (CCollider*)output.colliderRaw->_getOwner(PhysicsOwnerType::Component);
  322. if (component != nullptr)
  323. output.collider = component->getHandle();
  324. }
  325. }
  326. struct PhysXRaycastQueryCallback : PxRaycastCallback
  327. {
  328. static const int MAX_HITS = 32;
  329. PxRaycastHit buffer[MAX_HITS];
  330. Vector<PhysicsQueryHit> data;
  331. PhysXRaycastQueryCallback()
  332. :PxRaycastCallback(buffer, MAX_HITS)
  333. { }
  334. PxAgain processTouches(const PxRaycastHit* buffer, PxU32 nbHits) override
  335. {
  336. for (PxU32 i = 0; i < nbHits; i++)
  337. {
  338. data.push_back(PhysicsQueryHit());
  339. parseHit(buffer[i], data.back());
  340. }
  341. return true;
  342. }
  343. };
  344. struct PhysXSweepQueryCallback : PxSweepCallback
  345. {
  346. static const int MAX_HITS = 32;
  347. PxSweepHit buffer[MAX_HITS];
  348. Vector<PhysicsQueryHit> data;
  349. PhysXSweepQueryCallback()
  350. :PxSweepCallback(buffer, MAX_HITS)
  351. { }
  352. PxAgain processTouches(const PxSweepHit* buffer, PxU32 nbHits) override
  353. {
  354. for (PxU32 i = 0; i < nbHits; i++)
  355. {
  356. data.push_back(PhysicsQueryHit());
  357. parseHit(buffer[i], data.back());
  358. }
  359. return true;
  360. }
  361. };
  362. struct PhysXOverlapQueryCallback : PxOverlapCallback
  363. {
  364. static const int MAX_HITS = 32;
  365. PxOverlapHit buffer[MAX_HITS];
  366. Vector<Collider*> data;
  367. PhysXOverlapQueryCallback()
  368. :PxOverlapCallback(buffer, MAX_HITS)
  369. { }
  370. PxAgain processTouches(const PxOverlapHit* buffer, PxU32 nbHits) override
  371. {
  372. for (PxU32 i = 0; i < nbHits; i++)
  373. data.push_back((Collider*)buffer[i].shape->userData);
  374. return true;
  375. }
  376. };
  377. static PhysXAllocator gPhysXAllocator;
  378. static PhysXErrorCallback gPhysXErrorHandler;
  379. static PhysXCPUDispatcher gPhysXCPUDispatcher;
  380. static PhysXEventCallback gPhysXEventCallback;
  381. static PhysXBroadPhaseCallback gPhysXBroadphaseCallback;
  382. static const UINT32 SIZE_16K = 1 << 14;
  383. const UINT32 PhysX::SCRATCH_BUFFER_SIZE = SIZE_16K * 64; // 1MB by default
  384. const UINT32 PhysX::MAX_ITERATIONS_PER_FRAME = 4; // At 60 physics updates per second this would mean user is running at 15fps
  385. PhysX::PhysX(const PHYSICS_INIT_DESC& input)
  386. :Physics(input)
  387. {
  388. mScale.length = input.typicalLength;
  389. mScale.speed = input.typicalSpeed;
  390. mFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gPhysXAllocator, gPhysXErrorHandler);
  391. mPhysics = PxCreateBasePhysics(PX_PHYSICS_VERSION, *mFoundation, mScale);
  392. PxRegisterArticulations(*mPhysics);
  393. if (input.initCooking)
  394. {
  395. // Note: PhysX supports cooking for specific platforms to make the generated results better. Consider
  396. // allowing the meshes to be re-cooked when target platform is changed. Right now we just use the default value.
  397. PxCookingParams cookingParams(mScale);
  398. mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, cookingParams);
  399. }
  400. PxSceneDesc sceneDesc(mScale); // TODO - Test out various other parameters provided by scene desc
  401. sceneDesc.gravity = toPxVector(input.gravity);
  402. sceneDesc.cpuDispatcher = &gPhysXCPUDispatcher;
  403. sceneDesc.filterShader = PhysXFilterShader;
  404. sceneDesc.simulationEventCallback = &gPhysXEventCallback;
  405. sceneDesc.broadPhaseCallback = &gPhysXBroadphaseCallback;
  406. // Optionally: eENABLE_KINEMATIC_STATIC_PAIRS, eENABLE_KINEMATIC_PAIRS, eENABLE_PCM
  407. sceneDesc.flags = PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
  408. if (input.flags.isSet(PhysicsFlag::CCD_Enable))
  409. sceneDesc.flags |= PxSceneFlag::eENABLE_CCD;
  410. // Optionally: eMBP
  411. sceneDesc.broadPhaseType = PxBroadPhaseType::eSAP;
  412. mScene = mPhysics->createScene(sceneDesc);
  413. // Character controller
  414. mCharManager = PxCreateControllerManager(*mScene);
  415. mSimulationStep = input.timeStep;
  416. mSimulationTime = -mSimulationStep * 1.01f; // Ensures simulation runs on the first frame
  417. mDefaultMaterial = mPhysics->createMaterial(0.0f, 0.0f, 0.0f);
  418. }
  419. PhysX::~PhysX()
  420. {
  421. mCharManager->release();
  422. mScene->release();
  423. if (mCooking != nullptr)
  424. mCooking->release();
  425. mPhysics->release();
  426. mFoundation->release();
  427. }
  428. void PhysX::update()
  429. {
  430. if (mPaused)
  431. return;
  432. mUpdateInProgress = true;
  433. float nextFrameTime = mSimulationTime + mSimulationStep;
  434. mFrameTime += gTime().getFrameDelta();
  435. if(mFrameTime < nextFrameTime)
  436. {
  437. // Note: Potentially interpolate (would mean a one frame delay needs to be introduced)
  438. return;
  439. }
  440. float simulationAmount = std::max(mFrameTime - mSimulationTime, mSimulationStep); // At least one step
  441. INT32 numIterations = Math::floorToInt(simulationAmount / mSimulationStep);
  442. // If too many iterations are required, increase time step. This should only happen in extreme situations (or when
  443. // debugging).
  444. float step = mSimulationStep;
  445. if (numIterations > (INT32)MAX_ITERATIONS_PER_FRAME)
  446. step = (simulationAmount / MAX_ITERATIONS_PER_FRAME) * 0.99f;
  447. UINT32 iterationCount = 0;
  448. while (simulationAmount >= step) // In case we're running really slow multiple updates might be needed
  449. {
  450. // Note: Consider delaying fetchResults one frame. This could improve performance because Physics update would be
  451. // able to run parallel to the simulation thread, but at a cost to input latency.
  452. bs_frame_mark();
  453. UINT8* scratchBuffer = bs_frame_alloc_aligned(SCRATCH_BUFFER_SIZE, 16);
  454. mScene->simulate(step, nullptr, scratchBuffer, SCRATCH_BUFFER_SIZE);
  455. simulationAmount -= step;
  456. mSimulationTime += step;
  457. UINT32 errorState;
  458. if(!mScene->fetchResults(true, &errorState))
  459. {
  460. LOGWRN("Physics simulation failed. Error code: " + toString(errorState));
  461. bs_frame_free_aligned(scratchBuffer);
  462. bs_frame_clear();
  463. iterationCount++;
  464. continue;
  465. }
  466. bs_frame_free_aligned(scratchBuffer);
  467. bs_frame_clear();
  468. iterationCount++;
  469. }
  470. // Update rigidbodies with new transforms
  471. PxU32 numActiveTransforms;
  472. const PxActiveTransform* activeTransforms = mScene->getActiveTransforms(numActiveTransforms);
  473. for (PxU32 i = 0; i < numActiveTransforms; i++)
  474. {
  475. Rigidbody* rigidbody = static_cast<Rigidbody*>(activeTransforms[i].userData);
  476. // Note: This should never happen, as actors gets their userData set to null when they're destroyed. However
  477. // in some cases PhysX seems to keep those actors alive for a frame or few, and reports their state here. Until
  478. // I find out why I need to perform this check.
  479. if(activeTransforms[i].actor->userData == nullptr)
  480. continue;
  481. const PxTransform& transform = activeTransforms[i].actor2World;
  482. // Note: Make this faster, avoid dereferencing Rigidbody and attempt to access pos/rot destination directly,
  483. // use non-temporal writes
  484. rigidbody->_setTransform(fromPxVector(transform.p), fromPxQuaternion(transform.q));
  485. }
  486. // Note: Consider extrapolating for the remaining "simulationAmount" value
  487. mUpdateInProgress = false;
  488. triggerEvents();
  489. }
  490. void PhysX::_reportContactEvent(const ContactEvent& event)
  491. {
  492. mContactEvents.push_back(event);
  493. }
  494. void PhysX::_reportTriggerEvent(const TriggerEvent& event)
  495. {
  496. mTriggerEvents.push_back(event);
  497. }
  498. void PhysX::_reportJointBreakEvent(const JointBreakEvent& event)
  499. {
  500. mJointBreakEvents.push_back(event);
  501. }
  502. void PhysX::triggerEvents()
  503. {
  504. CollisionDataRaw data;
  505. for(auto& entry : mTriggerEvents)
  506. {
  507. data.colliders[0] = entry.trigger;
  508. data.colliders[1] = entry.other;
  509. switch (entry.type)
  510. {
  511. case ContactEventType::ContactBegin:
  512. entry.trigger->onCollisionBegin(data);
  513. break;
  514. case ContactEventType::ContactStay:
  515. entry.trigger->onCollisionStay(data);
  516. break;
  517. case ContactEventType::ContactEnd:
  518. entry.trigger->onCollisionEnd(data);
  519. break;
  520. }
  521. }
  522. auto notifyContact = [&](Collider* obj, Collider* other, ContactEventType type,
  523. const Vector<ContactPoint>& points, bool flipNormals = false)
  524. {
  525. data.colliders[0] = obj;
  526. data.colliders[1] = other;
  527. data.contactPoints = points;
  528. if(flipNormals)
  529. {
  530. for (auto& point : data.contactPoints)
  531. point.normal = -point.normal;
  532. }
  533. Rigidbody* rigidbody = obj->getRigidbody();
  534. if(rigidbody != nullptr)
  535. {
  536. switch (type)
  537. {
  538. case ContactEventType::ContactBegin:
  539. rigidbody->onCollisionBegin(data);
  540. break;
  541. case ContactEventType::ContactStay:
  542. rigidbody->onCollisionStay(data);
  543. break;
  544. case ContactEventType::ContactEnd:
  545. rigidbody->onCollisionEnd(data);
  546. break;
  547. }
  548. }
  549. else
  550. {
  551. switch (type)
  552. {
  553. case ContactEventType::ContactBegin:
  554. obj->onCollisionBegin(data);
  555. break;
  556. case ContactEventType::ContactStay:
  557. obj->onCollisionStay(data);
  558. break;
  559. case ContactEventType::ContactEnd:
  560. obj->onCollisionEnd(data);
  561. break;
  562. }
  563. }
  564. };
  565. for (auto& entry : mContactEvents)
  566. {
  567. if (entry.colliderA != nullptr)
  568. {
  569. CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
  570. if (reportModeA == CollisionReportMode::ReportPersistent)
  571. notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
  572. else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
  573. notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
  574. }
  575. if (entry.colliderB != nullptr)
  576. {
  577. CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
  578. if (reportModeB == CollisionReportMode::ReportPersistent)
  579. notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
  580. else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
  581. notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
  582. }
  583. }
  584. for(auto& entry : mJointBreakEvents)
  585. {
  586. entry.joint->onJointBreak();
  587. }
  588. mTriggerEvents.clear();
  589. mContactEvents.clear();
  590. mJointBreakEvents.clear();
  591. }
  592. SPtr<PhysicsMaterial> PhysX::createMaterial(float staticFriction, float dynamicFriction, float restitution)
  593. {
  594. return bs_core_ptr_new<PhysXMaterial>(mPhysics, staticFriction, dynamicFriction, restitution);
  595. }
  596. SPtr<PhysicsMesh> PhysX::createMesh(const SPtr<MeshData>& meshData, PhysicsMeshType type)
  597. {
  598. return bs_core_ptr_new<PhysXMesh>(meshData, type);
  599. }
  600. SPtr<Rigidbody> PhysX::createRigidbody(const HSceneObject& linkedSO)
  601. {
  602. return bs_shared_ptr_new<PhysXRigidbody>(mPhysics, mScene, linkedSO);
  603. }
  604. SPtr<BoxCollider> PhysX::createBoxCollider(const Vector3& extents, const Vector3& position,
  605. const Quaternion& rotation)
  606. {
  607. return bs_shared_ptr_new<PhysXBoxCollider>(mPhysics, position, rotation, extents);
  608. }
  609. SPtr<SphereCollider> PhysX::createSphereCollider(float radius, const Vector3& position, const Quaternion& rotation)
  610. {
  611. return bs_shared_ptr_new<PhysXSphereCollider>(mPhysics, position, rotation, radius);
  612. }
  613. SPtr<PlaneCollider> PhysX::createPlaneCollider(const Vector3& position, const Quaternion& rotation)
  614. {
  615. return bs_shared_ptr_new<PhysXPlaneCollider>(mPhysics, position, rotation);
  616. }
  617. SPtr<CapsuleCollider> PhysX::createCapsuleCollider(float radius, float halfHeight, const Vector3& position,
  618. const Quaternion& rotation)
  619. {
  620. return bs_shared_ptr_new<PhysXCapsuleCollider>(mPhysics, position, rotation, radius, halfHeight);
  621. }
  622. SPtr<MeshCollider> PhysX::createMeshCollider(const Vector3& position, const Quaternion& rotation)
  623. {
  624. return bs_shared_ptr_new<PhysXMeshCollider>(mPhysics, position, rotation);
  625. }
  626. SPtr<FixedJoint> PhysX::createFixedJoint(const FIXED_JOINT_DESC& desc)
  627. {
  628. return bs_shared_ptr_new<PhysXFixedJoint>(mPhysics, desc);
  629. }
  630. SPtr<DistanceJoint> PhysX::createDistanceJoint(const DISTANCE_JOINT_DESC& desc)
  631. {
  632. return bs_shared_ptr_new<PhysXDistanceJoint>(mPhysics, desc);
  633. }
  634. SPtr<HingeJoint> PhysX::createHingeJoint(const HINGE_JOINT_DESC& desc)
  635. {
  636. return bs_shared_ptr_new<PhysXHingeJoint>(mPhysics, desc);
  637. }
  638. SPtr<SphericalJoint> PhysX::createSphericalJoint(const SPHERICAL_JOINT_DESC& desc)
  639. {
  640. return bs_shared_ptr_new<PhysXSphericalJoint>(mPhysics, desc);
  641. }
  642. SPtr<SliderJoint> PhysX::createSliderJoint(const SLIDER_JOINT_DESC& desc)
  643. {
  644. return bs_shared_ptr_new<PhysXSliderJoint>(mPhysics, desc);
  645. }
  646. SPtr<D6Joint> PhysX::createD6Joint(const D6_JOINT_DESC& desc)
  647. {
  648. return bs_shared_ptr_new<PhysXD6Joint>(mPhysics, desc);
  649. }
  650. SPtr<CharacterController> PhysX::createCharacterController(const CHAR_CONTROLLER_DESC& desc)
  651. {
  652. return bs_shared_ptr_new<PhysXCharacterController>(mCharManager, desc);
  653. }
  654. Vector<PhysicsQueryHit> PhysX::sweepAll(const PxGeometry& geometry, const PxTransform& tfrm, const Vector3& unitDir,
  655. UINT64 layer, float maxDist) const
  656. {
  657. PhysXSweepQueryCallback output;
  658. PxQueryFilterData filterData;
  659. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  660. mScene->sweep(geometry, tfrm, toPxVector(unitDir), maxDist, output,
  661. PxHitFlag::eDEFAULT | PxHitFlag::eUV, filterData);
  662. return output.data;
  663. }
  664. bool PhysX::sweepAny(const PxGeometry& geometry, const PxTransform& tfrm, const Vector3& unitDir, UINT64 layer,
  665. float maxDist) const
  666. {
  667. PxSweepBuffer output;
  668. PxQueryFilterData filterData;
  669. filterData.flags |= PxQueryFlag::eANY_HIT;
  670. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  671. return mScene->sweep(geometry, tfrm, toPxVector(unitDir), maxDist, output,
  672. PxHitFlag::eDEFAULT | PxHitFlag::eUV | PxHitFlag::eMESH_ANY, filterData);
  673. }
  674. bool PhysX::rayCast(const Vector3& origin, const Vector3& unitDir, PhysicsQueryHit& hit, UINT64 layer, float max) const
  675. {
  676. PxRaycastBuffer output;
  677. PxQueryFilterData filterData;
  678. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  679. bool wasHit = mScene->raycast(toPxVector(origin),
  680. toPxVector(unitDir), max, output, PxHitFlag::eDEFAULT | PxHitFlag::eUV, filterData);
  681. if (wasHit)
  682. parseHit(output.block, hit);
  683. return wasHit;
  684. }
  685. bool PhysX::boxCast(const AABox& box, const Quaternion& rotation, const Vector3& unitDir, PhysicsQueryHit& hit,
  686. UINT64 layer, float max) const
  687. {
  688. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  689. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  690. return sweep(geometry, transform, unitDir, hit, layer, max);
  691. }
  692. bool PhysX::sphereCast(const Sphere& sphere, const Vector3& unitDir, PhysicsQueryHit& hit,
  693. UINT64 layer, float max) const
  694. {
  695. PxSphereGeometry geometry(sphere.getRadius());
  696. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  697. return sweep(geometry, transform, unitDir, hit, layer, max);
  698. }
  699. bool PhysX::capsuleCast(const Capsule& capsule, const Quaternion& rotation, const Vector3& unitDir,
  700. PhysicsQueryHit& hit, UINT64 layer, float max) const
  701. {
  702. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  703. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  704. return sweep(geometry, transform, unitDir, hit, layer, max);
  705. }
  706. bool PhysX::convexCast(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
  707. const Vector3& unitDir, PhysicsQueryHit& hit, UINT64 layer, float max) const
  708. {
  709. if (mesh == nullptr)
  710. return false;
  711. if (mesh->getType() != PhysicsMeshType::Convex)
  712. return false;
  713. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  714. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  715. PxTransform transform = toPxTransform(position, rotation);
  716. return sweep(geometry, transform, unitDir, hit, layer, max);
  717. }
  718. Vector<PhysicsQueryHit> PhysX::rayCastAll(const Vector3& origin, const Vector3& unitDir,
  719. UINT64 layer, float max) const
  720. {
  721. PhysXRaycastQueryCallback output;
  722. PxQueryFilterData filterData;
  723. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  724. mScene->raycast(toPxVector(origin), toPxVector(unitDir), max, output,
  725. PxHitFlag::eDEFAULT | PxHitFlag::eUV | PxHitFlag::eMESH_MULTIPLE, filterData);
  726. return output.data;
  727. }
  728. Vector<PhysicsQueryHit> PhysX::boxCastAll(const AABox& box, const Quaternion& rotation,
  729. const Vector3& unitDir, UINT64 layer, float max) const
  730. {
  731. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  732. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  733. return sweepAll(geometry, transform, unitDir, layer, max);
  734. }
  735. Vector<PhysicsQueryHit> PhysX::sphereCastAll(const Sphere& sphere, const Vector3& unitDir,
  736. UINT64 layer, float max) const
  737. {
  738. PxSphereGeometry geometry(sphere.getRadius());
  739. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  740. return sweepAll(geometry, transform, unitDir, layer, max);
  741. }
  742. Vector<PhysicsQueryHit> PhysX::capsuleCastAll(const Capsule& capsule, const Quaternion& rotation,
  743. const Vector3& unitDir, UINT64 layer, float max) const
  744. {
  745. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  746. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  747. return sweepAll(geometry, transform, unitDir, layer, max);
  748. }
  749. Vector<PhysicsQueryHit> PhysX::convexCastAll(const HPhysicsMesh& mesh, const Vector3& position,
  750. const Quaternion& rotation, const Vector3& unitDir, UINT64 layer, float max) const
  751. {
  752. if (mesh == nullptr)
  753. return Vector<PhysicsQueryHit>(0);
  754. if (mesh->getType() != PhysicsMeshType::Convex)
  755. return Vector<PhysicsQueryHit>(0);
  756. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  757. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  758. PxTransform transform = toPxTransform(position, rotation);
  759. return sweepAll(geometry, transform, unitDir, layer, max);
  760. }
  761. bool PhysX::rayCastAny(const Vector3& origin, const Vector3& unitDir,
  762. UINT64 layer, float max) const
  763. {
  764. PxRaycastBuffer output;
  765. PxQueryFilterData filterData;
  766. filterData.flags |= PxQueryFlag::eANY_HIT;
  767. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  768. return mScene->raycast(toPxVector(origin),
  769. toPxVector(unitDir), max, output, PxHitFlag::eDEFAULT | PxHitFlag::eUV | PxHitFlag::eMESH_ANY, filterData);
  770. }
  771. bool PhysX::boxCastAny(const AABox& box, const Quaternion& rotation, const Vector3& unitDir,
  772. UINT64 layer, float max) const
  773. {
  774. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  775. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  776. return sweepAny(geometry, transform, unitDir, layer, max);
  777. }
  778. bool PhysX::sphereCastAny(const Sphere& sphere, const Vector3& unitDir,
  779. UINT64 layer, float max) const
  780. {
  781. PxSphereGeometry geometry(sphere.getRadius());
  782. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  783. return sweepAny(geometry, transform, unitDir, layer, max);
  784. }
  785. bool PhysX::capsuleCastAny(const Capsule& capsule, const Quaternion& rotation, const Vector3& unitDir,
  786. UINT64 layer, float max) const
  787. {
  788. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  789. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  790. return sweepAny(geometry, transform, unitDir, layer, max);
  791. }
  792. bool PhysX::convexCastAny(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
  793. const Vector3& unitDir, UINT64 layer, float max) const
  794. {
  795. if (mesh == nullptr)
  796. return false;
  797. if (mesh->getType() != PhysicsMeshType::Convex)
  798. return false;
  799. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  800. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  801. PxTransform transform = toPxTransform(position, rotation);
  802. return sweepAny(geometry, transform, unitDir, layer, max);
  803. }
  804. Vector<Collider*> PhysX::_boxOverlap(const AABox& box, const Quaternion& rotation,
  805. UINT64 layer) const
  806. {
  807. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  808. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  809. return overlap(geometry, transform, layer);
  810. }
  811. Vector<Collider*> PhysX::_sphereOverlap(const Sphere& sphere, UINT64 layer) const
  812. {
  813. PxSphereGeometry geometry(sphere.getRadius());
  814. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  815. return overlap(geometry, transform, layer);
  816. }
  817. Vector<Collider*> PhysX::_capsuleOverlap(const Capsule& capsule, const Quaternion& rotation,
  818. UINT64 layer) const
  819. {
  820. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  821. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  822. return overlap(geometry, transform, layer);
  823. }
  824. Vector<Collider*> PhysX::_convexOverlap(const HPhysicsMesh& mesh, const Vector3& position,
  825. const Quaternion& rotation, UINT64 layer) const
  826. {
  827. if (mesh == nullptr)
  828. return Vector<Collider*>(0);
  829. if (mesh->getType() != PhysicsMeshType::Convex)
  830. return Vector<Collider*>(0);
  831. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  832. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  833. PxTransform transform = toPxTransform(position, rotation);
  834. return overlap(geometry, transform, layer);
  835. }
  836. bool PhysX::boxOverlapAny(const AABox& box, const Quaternion& rotation, UINT64 layer) const
  837. {
  838. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  839. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  840. return overlapAny(geometry, transform, layer);
  841. }
  842. bool PhysX::sphereOverlapAny(const Sphere& sphere, UINT64 layer) const
  843. {
  844. PxSphereGeometry geometry(sphere.getRadius());
  845. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  846. return overlapAny(geometry, transform, layer);
  847. }
  848. bool PhysX::capsuleOverlapAny(const Capsule& capsule, const Quaternion& rotation,
  849. UINT64 layer) const
  850. {
  851. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  852. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  853. return overlapAny(geometry, transform, layer);
  854. }
  855. bool PhysX::convexOverlapAny(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
  856. UINT64 layer) const
  857. {
  858. if (mesh == nullptr)
  859. return false;
  860. if (mesh->getType() != PhysicsMeshType::Convex)
  861. return false;
  862. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  863. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  864. PxTransform transform = toPxTransform(position, rotation);
  865. return overlapAny(geometry, transform, layer);
  866. }
  867. bool PhysX::_rayCast(const Vector3& origin, const Vector3& unitDir, const Collider& collider, PhysicsQueryHit& hit,
  868. float maxDist) const
  869. {
  870. FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider._getInternal());
  871. PxShape* shape = physxCollider->_getShape();
  872. PxTransform transform = toPxTransform(collider.getPosition(), collider.getRotation());
  873. PxRaycastHit hitInfo;
  874. PxU32 maxHits = 1;
  875. bool anyHit = false;
  876. PxHitFlags hitFlags = PxHitFlag::eDEFAULT | PxHitFlag::eUV;
  877. PxU32 hitCount = PxGeometryQuery::raycast(toPxVector(origin), toPxVector(unitDir),
  878. shape->getGeometry().any(), transform,
  879. maxDist, hitFlags, maxHits, &hitInfo, anyHit);
  880. if(hitCount > 0)
  881. parseHit(hitInfo, hit);
  882. return hitCount > 0;
  883. }
  884. bool PhysX::sweep(const PxGeometry& geometry, const PxTransform& tfrm, const Vector3& unitDir,
  885. PhysicsQueryHit& hit, UINT64 layer, float maxDist) const
  886. {
  887. PxSweepBuffer output;
  888. PxQueryFilterData filterData;
  889. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  890. bool wasHit = mScene->sweep(geometry, tfrm, toPxVector(unitDir), maxDist, output,
  891. PxHitFlag::eDEFAULT | PxHitFlag::eUV, filterData);
  892. if (wasHit)
  893. parseHit(output.block, hit);
  894. return wasHit;
  895. }
  896. bool PhysX::overlapAny(const PxGeometry& geometry, const PxTransform& tfrm, UINT64 layer) const
  897. {
  898. PxOverlapBuffer output;
  899. PxQueryFilterData filterData;
  900. filterData.flags |= PxQueryFlag::eANY_HIT;
  901. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  902. return mScene->overlap(geometry, tfrm, output, filterData);
  903. }
  904. Vector<Collider*> PhysX::overlap(const PxGeometry& geometry, const PxTransform& tfrm, UINT64 layer) const
  905. {
  906. PhysXOverlapQueryCallback output;
  907. PxQueryFilterData filterData;
  908. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  909. mScene->overlap(geometry, tfrm, output, filterData);
  910. return output.data;
  911. }
  912. void PhysX::setFlag(PhysicsFlags flag, bool enabled)
  913. {
  914. Physics::setFlag(flag, enabled);
  915. mCharManager->setOverlapRecoveryModule(mFlags.isSet(PhysicsFlag::CCT_OverlapRecovery));
  916. mCharManager->setPreciseSweeps(mFlags.isSet(PhysicsFlag::CCT_PreciseSweeps));
  917. mCharManager->setTessellation(mFlags.isSet(PhysicsFlag::CCT_Tesselation), mTesselationLength);
  918. }
  919. void PhysX::setPaused(bool paused)
  920. {
  921. mPaused = paused;
  922. }
  923. Vector3 PhysX::getGravity() const
  924. {
  925. return fromPxVector(mScene->getGravity());
  926. }
  927. void PhysX::setGravity(const Vector3& gravity)
  928. {
  929. mScene->setGravity(toPxVector(gravity));
  930. }
  931. void PhysX::setMaxTesselationEdgeLength(float length)
  932. {
  933. mTesselationLength = length;
  934. mCharManager->setTessellation(mFlags.isSet(PhysicsFlag::CCT_Tesselation), mTesselationLength);
  935. }
  936. UINT32 PhysX::addBroadPhaseRegion(const AABox& region)
  937. {
  938. UINT32 id = mNextRegionIdx++;
  939. PxBroadPhaseRegion pxRegion;
  940. pxRegion.bounds = PxBounds3(toPxVector(region.getMin()), toPxVector(region.getMax()));
  941. pxRegion.userData = (void*)(UINT64)id;
  942. UINT32 handle = mScene->addBroadPhaseRegion(pxRegion, true);
  943. mBroadPhaseRegionHandles[id] = handle;
  944. return handle;
  945. }
  946. void PhysX::removeBroadPhaseRegion(UINT32 regionId)
  947. {
  948. auto iterFind = mBroadPhaseRegionHandles.find(regionId);
  949. if (iterFind == mBroadPhaseRegionHandles.end())
  950. return;
  951. mScene->removeBroadPhaseRegion(iterFind->second);
  952. mBroadPhaseRegionHandles.erase(iterFind);
  953. }
  954. void PhysX::clearBroadPhaseRegions()
  955. {
  956. for(auto& entry : mBroadPhaseRegionHandles)
  957. mScene->removeBroadPhaseRegion(entry.second);
  958. mBroadPhaseRegionHandles.clear();
  959. }
  960. PhysX& gPhysX()
  961. {
  962. return static_cast<PhysX&>(PhysX::instance());
  963. }
  964. }