BsPhysX.cpp 35 KB

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