BsPhysX.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208
  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 "BsTaskScheduler.h"
  19. #include "BsCCollider.h"
  20. #include "BsFPhysXCollider.h"
  21. #include "BsTime.h"
  22. #include "Bsvector3.h"
  23. #include "BsAABox.h"
  24. #include "BsCapsule.h"
  25. #include "foundation\PxTransform.h"
  26. using namespace physx;
  27. namespace BansheeEngine
  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.distance = input.distance;
  316. output.triangleIdx = input.faceIndex;
  317. output.colliderRaw = (Collider*)input.shape->userData;
  318. if (output.colliderRaw != nullptr)
  319. {
  320. CCollider* component = (CCollider*)output.colliderRaw->_getOwner(PhysicsOwnerType::Component);
  321. if (component != nullptr)
  322. output.collider = component->getHandle();
  323. }
  324. }
  325. struct PhysXRaycastQueryCallback : PxRaycastCallback
  326. {
  327. static const int MAX_HITS = 32;
  328. PxRaycastHit buffer[MAX_HITS];
  329. Vector<PhysicsQueryHit> data;
  330. PhysXRaycastQueryCallback()
  331. :PxRaycastCallback(buffer, MAX_HITS)
  332. { }
  333. PxAgain processTouches(const PxRaycastHit* buffer, PxU32 nbHits) override
  334. {
  335. for (PxU32 i = 0; i < nbHits; i++)
  336. {
  337. data.push_back(PhysicsQueryHit());
  338. parseHit(buffer[i], data.back());
  339. }
  340. return true;
  341. }
  342. };
  343. struct PhysXSweepQueryCallback : PxSweepCallback
  344. {
  345. static const int MAX_HITS = 32;
  346. PxSweepHit buffer[MAX_HITS];
  347. Vector<PhysicsQueryHit> data;
  348. PhysXSweepQueryCallback()
  349. :PxSweepCallback(buffer, MAX_HITS)
  350. { }
  351. PxAgain processTouches(const PxSweepHit* buffer, PxU32 nbHits) override
  352. {
  353. for (PxU32 i = 0; i < nbHits; i++)
  354. {
  355. data.push_back(PhysicsQueryHit());
  356. parseHit(buffer[i], data.back());
  357. }
  358. return true;
  359. }
  360. };
  361. struct PhysXOverlapQueryCallback : PxOverlapCallback
  362. {
  363. static const int MAX_HITS = 32;
  364. PxOverlapHit buffer[MAX_HITS];
  365. Vector<Collider*> data;
  366. PhysXOverlapQueryCallback()
  367. :PxOverlapCallback(buffer, MAX_HITS)
  368. { }
  369. PxAgain processTouches(const PxOverlapHit* buffer, PxU32 nbHits) override
  370. {
  371. for (PxU32 i = 0; i < nbHits; i++)
  372. data.push_back((Collider*)buffer[i].shape->userData);
  373. return true;
  374. }
  375. };
  376. static PhysXAllocator gPhysXAllocator;
  377. static PhysXErrorCallback gPhysXErrorHandler;
  378. static PhysXCPUDispatcher gPhysXCPUDispatcher;
  379. static PhysXEventCallback gPhysXEventCallback;
  380. static PhysXBroadPhaseCallback gPhysXBroadphaseCallback;
  381. static const UINT32 SIZE_16K = 1 << 14;
  382. const UINT32 PhysX::SCRATCH_BUFFER_SIZE = SIZE_16K * 64; // 1MB by default
  383. const UINT32 PhysX::MAX_ITERATIONS_PER_FRAME = 4; // At 60 physics updates per second this would mean user is running at 15fps
  384. PhysX::PhysX(const PHYSICS_INIT_DESC& input)
  385. :Physics(input)
  386. {
  387. mScale.length = input.typicalLength;
  388. mScale.speed = input.typicalSpeed;
  389. mFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gPhysXAllocator, gPhysXErrorHandler);
  390. mPhysics = PxCreateBasePhysics(PX_PHYSICS_VERSION, *mFoundation, mScale);
  391. PxRegisterArticulations(*mPhysics);
  392. if (input.initCooking)
  393. {
  394. // Note: PhysX supports cooking for specific platforms to make the generated results better. Consider
  395. // allowing the meshes to be re-cooked when target platform is changed. Right now we just use the default value.
  396. PxCookingParams cookingParams(mScale);
  397. mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, cookingParams);
  398. }
  399. PxSceneDesc sceneDesc(mScale); // TODO - Test out various other parameters provided by scene desc
  400. sceneDesc.gravity = toPxVector(input.gravity);
  401. sceneDesc.cpuDispatcher = &gPhysXCPUDispatcher;
  402. sceneDesc.filterShader = PhysXFilterShader;
  403. sceneDesc.simulationEventCallback = &gPhysXEventCallback;
  404. sceneDesc.broadPhaseCallback = &gPhysXBroadphaseCallback;
  405. // Optionally: eENABLE_KINEMATIC_STATIC_PAIRS, eENABLE_KINEMATIC_PAIRS, eENABLE_PCM
  406. sceneDesc.flags = PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
  407. if (input.flags.isSet(PhysicsFlag::CCD_Enable))
  408. sceneDesc.flags |= PxSceneFlag::eENABLE_CCD;
  409. // Optionally: eMBP
  410. sceneDesc.broadPhaseType = PxBroadPhaseType::eSAP;
  411. mScene = mPhysics->createScene(sceneDesc);
  412. // Character controller
  413. mCharManager = PxCreateControllerManager(*mScene);
  414. mSimulationStep = input.timeStep;
  415. mSimulationTime = -mSimulationStep * 1.01f; // Ensures simulation runs on the first frame
  416. mDefaultMaterial = mPhysics->createMaterial(0.0f, 0.0f, 0.0f);
  417. }
  418. PhysX::~PhysX()
  419. {
  420. mCharManager->release();
  421. mScene->release();
  422. if (mCooking != nullptr)
  423. mCooking->release();
  424. mPhysics->release();
  425. mFoundation->release();
  426. }
  427. void PhysX::update()
  428. {
  429. if (mPaused)
  430. return;
  431. mUpdateInProgress = true;
  432. float nextFrameTime = mSimulationTime + mSimulationStep;
  433. mFrameTime += gTime().getFrameDelta();
  434. if(mFrameTime < nextFrameTime)
  435. {
  436. // Note: Potentially interpolate (would mean a one frame delay needs to be introduced)
  437. return;
  438. }
  439. float simulationAmount = std::max(mFrameTime - mSimulationTime, mSimulationStep); // At least one step
  440. INT32 numIterations = Math::floorToInt(simulationAmount / mSimulationStep);
  441. // If too many iterations are required, increase time step. This should only happen in extreme situations (or when
  442. // debugging).
  443. float step = mSimulationStep;
  444. if (numIterations > MAX_ITERATIONS_PER_FRAME)
  445. step = (simulationAmount / MAX_ITERATIONS_PER_FRAME) * 0.99f;
  446. UINT32 iterationCount = 0;
  447. while (simulationAmount >= step) // In case we're running really slow multiple updates might be needed
  448. {
  449. // Note: Consider delaying fetchResults one frame. This could improve performance because Physics update would be
  450. // able to run parallel to the simulation thread, but at a cost to input latency.
  451. bs_frame_mark();
  452. UINT8* scratchBuffer = bs_frame_alloc_aligned(SCRATCH_BUFFER_SIZE, 16);
  453. mScene->simulate(step, nullptr, scratchBuffer, SCRATCH_BUFFER_SIZE);
  454. simulationAmount -= step;
  455. mSimulationTime += step;
  456. UINT32 errorState;
  457. if(!mScene->fetchResults(true, &errorState))
  458. {
  459. LOGWRN("Physics simulation failed. Error code: " + toString(errorState));
  460. bs_frame_free_aligned(scratchBuffer);
  461. bs_frame_clear();
  462. iterationCount++;
  463. continue;
  464. }
  465. bs_frame_free_aligned(scratchBuffer);
  466. bs_frame_clear();
  467. iterationCount++;
  468. }
  469. // Update rigidbodies with new transforms
  470. PxU32 numActiveTransforms;
  471. const PxActiveTransform* activeTransforms = mScene->getActiveTransforms(numActiveTransforms);
  472. for (PxU32 i = 0; i < numActiveTransforms; i++)
  473. {
  474. Rigidbody* rigidbody = static_cast<Rigidbody*>(activeTransforms[i].userData);
  475. // Note: This should never happen, as actors gets their userData set to null when they're destroyed. However
  476. // in some cases PhysX seems to keep those actors alive for a frame or few, and reports their state here. Until
  477. // I find out why I need to perform this check.
  478. if(activeTransforms[i].actor->userData == nullptr)
  479. continue;
  480. const PxTransform& transform = activeTransforms[i].actor2World;
  481. // Note: Make this faster, avoid dereferencing Rigidbody and attempt to access pos/rot destination directly,
  482. // use non-temporal writes
  483. rigidbody->_setTransform(fromPxVector(transform.p), fromPxQuaternion(transform.q));
  484. }
  485. // Note: Consider extrapolating for the remaining "simulationAmount" value
  486. mUpdateInProgress = false;
  487. triggerEvents();
  488. }
  489. void PhysX::_reportContactEvent(const ContactEvent& event)
  490. {
  491. mContactEvents.push_back(event);
  492. }
  493. void PhysX::_reportTriggerEvent(const TriggerEvent& event)
  494. {
  495. mTriggerEvents.push_back(event);
  496. }
  497. void PhysX::_reportJointBreakEvent(const JointBreakEvent& event)
  498. {
  499. mJointBreakEvents.push_back(event);
  500. }
  501. void PhysX::triggerEvents()
  502. {
  503. CollisionData data;
  504. for(auto& entry : mTriggerEvents)
  505. {
  506. data.collidersRaw[0] = entry.trigger;
  507. data.collidersRaw[1] = entry.other;
  508. switch (entry.type)
  509. {
  510. case ContactEventType::ContactBegin:
  511. entry.trigger->onCollisionBegin(data);
  512. break;
  513. case ContactEventType::ContactStay:
  514. entry.trigger->onCollisionStay(data);
  515. break;
  516. case ContactEventType::ContactEnd:
  517. entry.trigger->onCollisionEnd(data);
  518. break;
  519. }
  520. }
  521. auto notifyContact = [&](Collider* obj, Collider* other, ContactEventType type,
  522. const Vector<ContactPoint>& points, bool flipNormals = false)
  523. {
  524. data.collidersRaw[0] = obj;
  525. data.collidersRaw[1] = other;
  526. data.contactPoints = points;
  527. if(flipNormals)
  528. {
  529. for (auto& point : data.contactPoints)
  530. point.normal = -point.normal;
  531. }
  532. Rigidbody* rigidbody = obj->getRigidbody();
  533. if(rigidbody != nullptr)
  534. {
  535. switch (type)
  536. {
  537. case ContactEventType::ContactBegin:
  538. rigidbody->onCollisionBegin(data);
  539. break;
  540. case ContactEventType::ContactStay:
  541. rigidbody->onCollisionStay(data);
  542. break;
  543. case ContactEventType::ContactEnd:
  544. rigidbody->onCollisionEnd(data);
  545. break;
  546. }
  547. }
  548. else
  549. {
  550. switch (type)
  551. {
  552. case ContactEventType::ContactBegin:
  553. obj->onCollisionBegin(data);
  554. break;
  555. case ContactEventType::ContactStay:
  556. obj->onCollisionStay(data);
  557. break;
  558. case ContactEventType::ContactEnd:
  559. obj->onCollisionEnd(data);
  560. break;
  561. }
  562. }
  563. };
  564. for (auto& entry : mContactEvents)
  565. {
  566. if (entry.colliderA != nullptr)
  567. {
  568. CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
  569. if (reportModeA == CollisionReportMode::ReportPersistent)
  570. notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
  571. else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
  572. notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
  573. }
  574. if (entry.colliderB != nullptr)
  575. {
  576. CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
  577. if (reportModeB == CollisionReportMode::ReportPersistent)
  578. notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
  579. else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
  580. notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
  581. }
  582. }
  583. for(auto& entry : mJointBreakEvents)
  584. {
  585. entry.joint->onJointBreak();
  586. }
  587. mTriggerEvents.clear();
  588. mContactEvents.clear();
  589. mJointBreakEvents.clear();
  590. }
  591. SPtr<PhysicsMaterial> PhysX::createMaterial(float staticFriction, float dynamicFriction, float restitution)
  592. {
  593. return bs_core_ptr_new<PhysXMaterial>(mPhysics, staticFriction, dynamicFriction, restitution);
  594. }
  595. SPtr<PhysicsMesh> PhysX::createMesh(const SPtr<MeshData>& meshData, PhysicsMeshType type)
  596. {
  597. return bs_core_ptr_new<PhysXMesh>(meshData, type);
  598. }
  599. SPtr<Rigidbody> PhysX::createRigidbody(const HSceneObject& linkedSO)
  600. {
  601. return bs_shared_ptr_new<PhysXRigidbody>(mPhysics, mScene, linkedSO);
  602. }
  603. SPtr<BoxCollider> PhysX::createBoxCollider(const Vector3& extents, const Vector3& position,
  604. const Quaternion& rotation)
  605. {
  606. return bs_shared_ptr_new<PhysXBoxCollider>(mPhysics, position, rotation, extents);
  607. }
  608. SPtr<SphereCollider> PhysX::createSphereCollider(float radius, const Vector3& position, const Quaternion& rotation)
  609. {
  610. return bs_shared_ptr_new<PhysXSphereCollider>(mPhysics, position, rotation, radius);
  611. }
  612. SPtr<PlaneCollider> PhysX::createPlaneCollider(const Vector3& position, const Quaternion& rotation)
  613. {
  614. return bs_shared_ptr_new<PhysXPlaneCollider>(mPhysics, position, rotation);
  615. }
  616. SPtr<CapsuleCollider> PhysX::createCapsuleCollider(float radius, float halfHeight, const Vector3& position,
  617. const Quaternion& rotation)
  618. {
  619. return bs_shared_ptr_new<PhysXCapsuleCollider>(mPhysics, position, rotation, radius, halfHeight);
  620. }
  621. SPtr<MeshCollider> PhysX::createMeshCollider(const Vector3& position, const Quaternion& rotation)
  622. {
  623. return bs_shared_ptr_new<PhysXMeshCollider>(mPhysics, position, rotation);
  624. }
  625. SPtr<FixedJoint> PhysX::createFixedJoint(const FIXED_JOINT_DESC& desc)
  626. {
  627. return bs_shared_ptr_new<PhysXFixedJoint>(mPhysics, desc);
  628. }
  629. SPtr<DistanceJoint> PhysX::createDistanceJoint(const DISTANCE_JOINT_DESC& desc)
  630. {
  631. return bs_shared_ptr_new<PhysXDistanceJoint>(mPhysics, desc);
  632. }
  633. SPtr<HingeJoint> PhysX::createHingeJoint(const HINGE_JOINT_DESC& desc)
  634. {
  635. return bs_shared_ptr_new<PhysXHingeJoint>(mPhysics, desc);
  636. }
  637. SPtr<SphericalJoint> PhysX::createSphericalJoint(const SPHERICAL_JOINT_DESC& desc)
  638. {
  639. return bs_shared_ptr_new<PhysXSphericalJoint>(mPhysics, desc);
  640. }
  641. SPtr<SliderJoint> PhysX::createSliderJoint(const SLIDER_JOINT_DESC& desc)
  642. {
  643. return bs_shared_ptr_new<PhysXSliderJoint>(mPhysics, desc);
  644. }
  645. SPtr<D6Joint> PhysX::createD6Joint(const D6_JOINT_DESC& desc)
  646. {
  647. return bs_shared_ptr_new<PhysXD6Joint>(mPhysics, desc);
  648. }
  649. SPtr<CharacterController> PhysX::createCharacterController(const CHAR_CONTROLLER_DESC& desc)
  650. {
  651. return bs_shared_ptr_new<PhysXCharacterController>(mCharManager, desc);
  652. }
  653. Vector<PhysicsQueryHit> PhysX::sweepAll(const PxGeometry& geometry, const PxTransform& tfrm, const Vector3& unitDir,
  654. UINT64 layer, float maxDist) const
  655. {
  656. PhysXSweepQueryCallback output;
  657. PxQueryFilterData filterData;
  658. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  659. mScene->sweep(geometry, tfrm, toPxVector(unitDir), maxDist, output,
  660. PxHitFlag::eDEFAULT | PxHitFlag::eUV, filterData);
  661. return output.data;
  662. }
  663. bool PhysX::sweepAny(const PxGeometry& geometry, const PxTransform& tfrm, const Vector3& unitDir, UINT64 layer,
  664. float maxDist) const
  665. {
  666. PxSweepBuffer output;
  667. PxQueryFilterData filterData;
  668. filterData.flags |= PxQueryFlag::eANY_HIT;
  669. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  670. return mScene->sweep(geometry, tfrm, toPxVector(unitDir), maxDist, output,
  671. PxHitFlag::eDEFAULT | PxHitFlag::eUV | PxHitFlag::eMESH_ANY, filterData);
  672. }
  673. bool PhysX::rayCast(const Vector3& origin, const Vector3& unitDir, PhysicsQueryHit& hit, UINT64 layer, float max) const
  674. {
  675. PxRaycastBuffer output;
  676. PxQueryFilterData filterData;
  677. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  678. bool wasHit = mScene->raycast(toPxVector(origin),
  679. toPxVector(unitDir), max, output, PxHitFlag::eDEFAULT | PxHitFlag::eUV, filterData);
  680. if (wasHit)
  681. parseHit(output.block, hit);
  682. return wasHit;
  683. }
  684. bool PhysX::boxCast(const AABox& box, const Quaternion& rotation, const Vector3& unitDir, PhysicsQueryHit& hit,
  685. UINT64 layer, float max) const
  686. {
  687. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  688. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  689. return sweep(geometry, transform, unitDir, hit, layer, max);
  690. }
  691. bool PhysX::sphereCast(const Sphere& sphere, const Vector3& unitDir, PhysicsQueryHit& hit,
  692. UINT64 layer, float max) const
  693. {
  694. PxSphereGeometry geometry(sphere.getRadius());
  695. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  696. return sweep(geometry, transform, unitDir, hit, layer, max);
  697. }
  698. bool PhysX::capsuleCast(const Capsule& capsule, const Quaternion& rotation, const Vector3& unitDir,
  699. PhysicsQueryHit& hit, UINT64 layer, float max) const
  700. {
  701. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  702. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  703. return sweep(geometry, transform, unitDir, hit, layer, max);
  704. }
  705. bool PhysX::convexCast(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
  706. const Vector3& unitDir, PhysicsQueryHit& hit, UINT64 layer, float max) const
  707. {
  708. if (mesh == nullptr)
  709. return false;
  710. if (mesh->getType() != PhysicsMeshType::Convex)
  711. return false;
  712. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  713. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  714. PxTransform transform = toPxTransform(position, rotation);
  715. return sweep(geometry, transform, unitDir, hit, layer, max);
  716. }
  717. Vector<PhysicsQueryHit> PhysX::rayCastAll(const Vector3& origin, const Vector3& unitDir,
  718. UINT64 layer, float max) const
  719. {
  720. PhysXRaycastQueryCallback output;
  721. PxQueryFilterData filterData;
  722. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  723. mScene->raycast(toPxVector(origin), toPxVector(unitDir), max, output,
  724. PxHitFlag::eDEFAULT | PxHitFlag::eUV | PxHitFlag::eMESH_MULTIPLE, filterData);
  725. return output.data;
  726. }
  727. Vector<PhysicsQueryHit> PhysX::boxCastAll(const AABox& box, const Quaternion& rotation,
  728. const Vector3& unitDir, UINT64 layer, float max) const
  729. {
  730. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  731. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  732. return sweepAll(geometry, transform, unitDir, layer, max);
  733. }
  734. Vector<PhysicsQueryHit> PhysX::sphereCastAll(const Sphere& sphere, const Vector3& unitDir,
  735. UINT64 layer, float max) const
  736. {
  737. PxSphereGeometry geometry(sphere.getRadius());
  738. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  739. return sweepAll(geometry, transform, unitDir, layer, max);
  740. }
  741. Vector<PhysicsQueryHit> PhysX::capsuleCastAll(const Capsule& capsule, const Quaternion& rotation,
  742. const Vector3& unitDir, UINT64 layer, float max) const
  743. {
  744. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  745. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  746. return sweepAll(geometry, transform, unitDir, layer, max);
  747. }
  748. Vector<PhysicsQueryHit> PhysX::convexCastAll(const HPhysicsMesh& mesh, const Vector3& position,
  749. const Quaternion& rotation, const Vector3& unitDir, UINT64 layer, float max) const
  750. {
  751. if (mesh == nullptr)
  752. return Vector<PhysicsQueryHit>(0);
  753. if (mesh->getType() != PhysicsMeshType::Convex)
  754. return Vector<PhysicsQueryHit>(0);
  755. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  756. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  757. PxTransform transform = toPxTransform(position, rotation);
  758. return sweepAll(geometry, transform, unitDir, layer, max);
  759. }
  760. bool PhysX::rayCastAny(const Vector3& origin, const Vector3& unitDir,
  761. UINT64 layer, float max) const
  762. {
  763. PxRaycastBuffer output;
  764. PxQueryFilterData filterData;
  765. filterData.flags |= PxQueryFlag::eANY_HIT;
  766. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  767. return mScene->raycast(toPxVector(origin),
  768. toPxVector(unitDir), max, output, PxHitFlag::eDEFAULT | PxHitFlag::eUV | PxHitFlag::eMESH_ANY, filterData);
  769. }
  770. bool PhysX::boxCastAny(const AABox& box, const Quaternion& rotation, const Vector3& unitDir,
  771. UINT64 layer, float max) const
  772. {
  773. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  774. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  775. return sweepAny(geometry, transform, unitDir, layer, max);
  776. }
  777. bool PhysX::sphereCastAny(const Sphere& sphere, const Vector3& unitDir,
  778. UINT64 layer, float max) const
  779. {
  780. PxSphereGeometry geometry(sphere.getRadius());
  781. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  782. return sweepAny(geometry, transform, unitDir, layer, max);
  783. }
  784. bool PhysX::capsuleCastAny(const Capsule& capsule, const Quaternion& rotation, const Vector3& unitDir,
  785. UINT64 layer, float max) const
  786. {
  787. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  788. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  789. return sweepAny(geometry, transform, unitDir, layer, max);
  790. }
  791. bool PhysX::convexCastAny(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
  792. const Vector3& unitDir, UINT64 layer, float max) const
  793. {
  794. if (mesh == nullptr)
  795. return false;
  796. if (mesh->getType() != PhysicsMeshType::Convex)
  797. return false;
  798. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  799. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  800. PxTransform transform = toPxTransform(position, rotation);
  801. return sweepAny(geometry, transform, unitDir, layer, max);
  802. }
  803. Vector<Collider*> PhysX::_boxOverlap(const AABox& box, const Quaternion& rotation,
  804. UINT64 layer) const
  805. {
  806. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  807. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  808. return overlap(geometry, transform, layer);
  809. }
  810. Vector<Collider*> PhysX::_sphereOverlap(const Sphere& sphere, UINT64 layer) const
  811. {
  812. PxSphereGeometry geometry(sphere.getRadius());
  813. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  814. return overlap(geometry, transform, layer);
  815. }
  816. Vector<Collider*> PhysX::_capsuleOverlap(const Capsule& capsule, const Quaternion& rotation,
  817. UINT64 layer) const
  818. {
  819. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  820. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  821. return overlap(geometry, transform, layer);
  822. }
  823. Vector<Collider*> PhysX::_convexOverlap(const HPhysicsMesh& mesh, const Vector3& position,
  824. const Quaternion& rotation, UINT64 layer) const
  825. {
  826. if (mesh == nullptr)
  827. return Vector<Collider*>(0);
  828. if (mesh->getType() != PhysicsMeshType::Convex)
  829. return Vector<Collider*>(0);
  830. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  831. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  832. PxTransform transform = toPxTransform(position, rotation);
  833. return overlap(geometry, transform, layer);
  834. }
  835. bool PhysX::boxOverlapAny(const AABox& box, const Quaternion& rotation, UINT64 layer) const
  836. {
  837. PxBoxGeometry geometry(toPxVector(box.getHalfSize()));
  838. PxTransform transform = toPxTransform(box.getCenter(), rotation);
  839. return overlapAny(geometry, transform, layer);
  840. }
  841. bool PhysX::sphereOverlapAny(const Sphere& sphere, UINT64 layer) const
  842. {
  843. PxSphereGeometry geometry(sphere.getRadius());
  844. PxTransform transform = toPxTransform(sphere.getCenter(), Quaternion::IDENTITY);
  845. return overlapAny(geometry, transform, layer);
  846. }
  847. bool PhysX::capsuleOverlapAny(const Capsule& capsule, const Quaternion& rotation,
  848. UINT64 layer) const
  849. {
  850. PxCapsuleGeometry geometry(capsule.getRadius(), capsule.getHeight() * 0.5f);
  851. PxTransform transform = toPxTransform(capsule.getCenter(), Quaternion::IDENTITY);
  852. return overlapAny(geometry, transform, layer);
  853. }
  854. bool PhysX::convexOverlapAny(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
  855. UINT64 layer) const
  856. {
  857. if (mesh == nullptr)
  858. return false;
  859. if (mesh->getType() != PhysicsMeshType::Convex)
  860. return false;
  861. FPhysXMesh* physxMesh = static_cast<FPhysXMesh*>(mesh->_getInternal());
  862. PxConvexMeshGeometry geometry(physxMesh->_getConvex());
  863. PxTransform transform = toPxTransform(position, rotation);
  864. return overlapAny(geometry, transform, layer);
  865. }
  866. bool PhysX::_rayCast(const Vector3& origin, const Vector3& unitDir, const Collider& collider, PhysicsQueryHit& hit,
  867. float maxDist) const
  868. {
  869. FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider._getInternal());
  870. PxShape* shape = physxCollider->_getShape();
  871. PxTransform transform = toPxTransform(collider.getPosition(), collider.getRotation());
  872. PxRaycastHit hitInfo;
  873. PxU32 maxHits = 1;
  874. bool anyHit = false;
  875. PxHitFlags hitFlags = PxHitFlag::eDEFAULT | PxHitFlag::eUV;
  876. PxU32 hitCount = PxGeometryQuery::raycast(toPxVector(origin), toPxVector(unitDir),
  877. shape->getGeometry().any(), transform,
  878. maxDist, hitFlags, maxHits, &hitInfo, anyHit);
  879. if(hitCount > 0)
  880. parseHit(hitInfo, hit);
  881. return hitCount > 0;
  882. }
  883. bool PhysX::sweep(const PxGeometry& geometry, const PxTransform& tfrm, const Vector3& unitDir,
  884. PhysicsQueryHit& hit, UINT64 layer, float maxDist) const
  885. {
  886. PxSweepBuffer output;
  887. PxQueryFilterData filterData;
  888. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  889. bool wasHit = mScene->sweep(geometry, tfrm, toPxVector(unitDir), maxDist, output,
  890. PxHitFlag::eDEFAULT | PxHitFlag::eUV, filterData);
  891. if (wasHit)
  892. parseHit(output.block, hit);
  893. return wasHit;
  894. }
  895. bool PhysX::overlapAny(const PxGeometry& geometry, const PxTransform& tfrm, UINT64 layer) const
  896. {
  897. PxOverlapBuffer output;
  898. PxQueryFilterData filterData;
  899. filterData.flags |= PxQueryFlag::eANY_HIT;
  900. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  901. return mScene->overlap(geometry, tfrm, output, filterData);
  902. }
  903. Vector<Collider*> PhysX::overlap(const PxGeometry& geometry, const PxTransform& tfrm, UINT64 layer) const
  904. {
  905. PhysXOverlapQueryCallback output;
  906. PxQueryFilterData filterData;
  907. memcpy(&filterData.data.word0, &layer, sizeof(layer));
  908. mScene->overlap(geometry, tfrm, output, filterData);
  909. return output.data;
  910. }
  911. void PhysX::setFlag(PhysicsFlags flag, bool enabled)
  912. {
  913. Physics::setFlag(flag, enabled);
  914. mCharManager->setOverlapRecoveryModule(mFlags.isSet(PhysicsFlag::CCT_OverlapRecovery));
  915. mCharManager->setPreciseSweeps(mFlags.isSet(PhysicsFlag::CCT_PreciseSweeps));
  916. mCharManager->setTessellation(mFlags.isSet(PhysicsFlag::CCT_Tesselation), mTesselationLength);
  917. }
  918. void PhysX::setPaused(bool paused)
  919. {
  920. mPaused = paused;
  921. }
  922. Vector3 PhysX::getGravity() const
  923. {
  924. return fromPxVector(mScene->getGravity());
  925. }
  926. void PhysX::setGravity(const Vector3& gravity)
  927. {
  928. mScene->setGravity(toPxVector(gravity));
  929. }
  930. void PhysX::setMaxTesselationEdgeLength(float length)
  931. {
  932. mTesselationLength = length;
  933. mCharManager->setTessellation(mFlags.isSet(PhysicsFlag::CCT_Tesselation), mTesselationLength);
  934. }
  935. UINT32 PhysX::addBroadPhaseRegion(const AABox& region)
  936. {
  937. UINT32 id = mNextRegionIdx++;
  938. PxBroadPhaseRegion pxRegion;
  939. pxRegion.bounds = PxBounds3(toPxVector(region.getMin()), toPxVector(region.getMax()));
  940. pxRegion.userData = (void*)(UINT64)id;
  941. UINT32 handle = mScene->addBroadPhaseRegion(pxRegion, true);
  942. mBroadPhaseRegionHandles[id] = handle;
  943. return handle;
  944. }
  945. void PhysX::removeBroadPhaseRegion(UINT32 regionId)
  946. {
  947. auto iterFind = mBroadPhaseRegionHandles.find(regionId);
  948. if (iterFind == mBroadPhaseRegionHandles.end())
  949. return;
  950. mScene->removeBroadPhaseRegion(iterFind->second);
  951. mBroadPhaseRegionHandles.erase(iterFind);
  952. }
  953. void PhysX::clearBroadPhaseRegions()
  954. {
  955. for(auto& entry : mBroadPhaseRegionHandles)
  956. mScene->removeBroadPhaseRegion(entry.second);
  957. mBroadPhaseRegionHandles.clear();
  958. }
  959. PhysX& gPhysX()
  960. {
  961. return static_cast<PhysX&>(PhysX::instance());
  962. }
  963. }