PhysicsWorld.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. // Copyright (c) 2008-2022 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Core/Context.h"
  5. #include "../Core/Mutex.h"
  6. #include "../Core/Profiler.h"
  7. #include "../Graphics/DebugRenderer.h"
  8. #include "../Graphics/Model.h"
  9. #include "../IO/Log.h"
  10. #include "../Math/Ray.h"
  11. #include "../Physics/CollisionShape.h"
  12. #include "../Physics/Constraint.h"
  13. #include "../Physics/PhysicsEvents.h"
  14. #include "../Physics/PhysicsUtils.h"
  15. #include "../Physics/PhysicsWorld.h"
  16. #include "../Physics/RaycastVehicle.h"
  17. #include "../Physics/RigidBody.h"
  18. #include "../Scene/Scene.h"
  19. #include "../Scene/SceneEvents.h"
  20. #include <Bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
  21. #include <Bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
  22. #include <Bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
  23. #include <Bullet/BulletCollision/CollisionShapes/btBoxShape.h>
  24. #include <Bullet/BulletCollision/CollisionShapes/btSphereShape.h>
  25. #include <Bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h>
  26. #include <Bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h>
  27. #include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
  28. extern ContactAddedCallback gContactAddedCallback;
  29. using namespace std;
  30. namespace Urho3D
  31. {
  32. const char* PHYSICS_CATEGORY = "Physics";
  33. extern const char* SUBSYSTEM_CATEGORY;
  34. static const int MAX_SOLVER_ITERATIONS = 256;
  35. static const Vector3 DEFAULT_GRAVITY = Vector3(0.0f, -9.81f, 0.0f);
  36. PhysicsWorldConfig PhysicsWorld::config;
  37. static bool CompareRaycastResults(const PhysicsRaycastResult& lhs, const PhysicsRaycastResult& rhs)
  38. {
  39. return lhs.distance_ < rhs.distance_;
  40. }
  41. void InternalPreTickCallback(btDynamicsWorld* world, btScalar timeStep)
  42. {
  43. static_cast<PhysicsWorld*>(world->getWorldUserInfo())->PreStep(timeStep);
  44. }
  45. void InternalTickCallback(btDynamicsWorld* world, btScalar timeStep)
  46. {
  47. static_cast<PhysicsWorld*>(world->getWorldUserInfo())->PostStep(timeStep);
  48. }
  49. static bool CustomMaterialCombinerCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0,
  50. int index0, const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1)
  51. {
  52. // Ensure that shape type of colObj1Wrap is either btScaledBvhTriangleMeshShape or btBvhTriangleMeshShape
  53. // because btAdjustInternalEdgeContacts doesn't check types properly. Bug in the Bullet?
  54. const int shapeType = colObj1Wrap->getCollisionObject()->getCollisionShape()->getShapeType();
  55. if (shapeType == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE || shapeType == TRIANGLE_SHAPE_PROXYTYPE
  56. || shapeType == MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE)
  57. {
  58. btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1);
  59. }
  60. cp.m_combinedFriction = colObj0Wrap->getCollisionObject()->getFriction() * colObj1Wrap->getCollisionObject()->getFriction();
  61. cp.m_combinedRestitution =
  62. colObj0Wrap->getCollisionObject()->getRestitution() * colObj1Wrap->getCollisionObject()->getRestitution();
  63. return true;
  64. }
  65. void RemoveCachedGeometryImpl(CollisionGeometryDataCache& cache, Model* model)
  66. {
  67. for (auto i = cache.Begin(); i != cache.End();)
  68. {
  69. auto current = i++;
  70. if (current->first_.first_ == model)
  71. cache.Erase(current);
  72. }
  73. }
  74. void CleanupGeometryCacheImpl(CollisionGeometryDataCache& cache)
  75. {
  76. for (auto i = cache.Begin(); i != cache.End();)
  77. {
  78. auto current = i++;
  79. if (current->second_.Refs() == 1)
  80. cache.Erase(current);
  81. }
  82. }
  83. /// Callback for physics world queries.
  84. struct PhysicsQueryCallback : public btCollisionWorld::ContactResultCallback
  85. {
  86. /// Construct.
  87. PhysicsQueryCallback(PODVector<RigidBody*>& result, unsigned collisionMask) :
  88. result_(result),
  89. collisionMask_(collisionMask)
  90. {
  91. }
  92. /// Add a contact result.
  93. btScalar addSingleResult(btManifoldPoint&, const btCollisionObjectWrapper* colObj0Wrap, int, int,
  94. const btCollisionObjectWrapper* colObj1Wrap, int, int) override
  95. {
  96. auto* body = reinterpret_cast<RigidBody*>(colObj0Wrap->getCollisionObject()->getUserPointer());
  97. if (body && !result_.Contains(body) && (body->GetCollisionLayer() & collisionMask_))
  98. result_.Push(body);
  99. body = reinterpret_cast<RigidBody*>(colObj1Wrap->getCollisionObject()->getUserPointer());
  100. if (body && !result_.Contains(body) && (body->GetCollisionLayer() & collisionMask_))
  101. result_.Push(body);
  102. return 0.0f;
  103. }
  104. /// Found rigid bodies.
  105. PODVector<RigidBody*>& result_;
  106. /// Collision mask for the query.
  107. unsigned collisionMask_;
  108. };
  109. PhysicsWorld::PhysicsWorld(Context* context) :
  110. Component(context),
  111. fps_(DEFAULT_FPS),
  112. debugMode_(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits)
  113. {
  114. gContactAddedCallback = CustomMaterialCombinerCallback;
  115. if (PhysicsWorld::config.collisionConfig_)
  116. collisionConfiguration_ = PhysicsWorld::config.collisionConfig_;
  117. else
  118. collisionConfiguration_ = new btDefaultCollisionConfiguration();
  119. collisionDispatcher_ = make_unique<btCollisionDispatcher>(collisionConfiguration_);
  120. btGImpactCollisionAlgorithm::registerAlgorithm(static_cast<btCollisionDispatcher*>(collisionDispatcher_.get()));
  121. broadphase_ = make_unique<btDbvtBroadphase>();
  122. solver_ = make_unique<btSequentialImpulseConstraintSolver>();
  123. world_ = make_unique<btDiscreteDynamicsWorld>(collisionDispatcher_.get(), broadphase_.get(), solver_.get(), collisionConfiguration_);
  124. world_->setGravity(ToBtVector3(DEFAULT_GRAVITY));
  125. world_->getDispatchInfo().m_useContinuous = true;
  126. world_->getSolverInfo().m_splitImpulse = false; // Disable by default for performance
  127. world_->setDebugDrawer(this);
  128. world_->setInternalTickCallback(InternalPreTickCallback, static_cast<void*>(this), true);
  129. world_->setInternalTickCallback(InternalTickCallback, static_cast<void*>(this), false);
  130. world_->setSynchronizeAllMotionStates(true);
  131. }
  132. PhysicsWorld::~PhysicsWorld()
  133. {
  134. if (scene_)
  135. {
  136. // Force all remaining constraints, rigid bodies and collision shapes to release themselves
  137. for (PODVector<Constraint*>::Iterator i = constraints_.Begin(); i != constraints_.End(); ++i)
  138. (*i)->ReleaseConstraint();
  139. for (PODVector<RigidBody*>::Iterator i = rigidBodies_.Begin(); i != rigidBodies_.End(); ++i)
  140. (*i)->ReleaseBody();
  141. for (PODVector<CollisionShape*>::Iterator i = collisionShapes_.Begin(); i != collisionShapes_.End(); ++i)
  142. (*i)->ReleaseShape();
  143. }
  144. world_.reset();
  145. solver_.reset();
  146. broadphase_.reset();
  147. collisionDispatcher_.reset();
  148. // Delete configuration only if it was the default created by PhysicsWorld
  149. if (!PhysicsWorld::config.collisionConfig_)
  150. delete collisionConfiguration_;
  151. collisionConfiguration_ = nullptr;
  152. }
  153. void PhysicsWorld::RegisterObject(Context* context)
  154. {
  155. context->RegisterFactory<PhysicsWorld>(SUBSYSTEM_CATEGORY);
  156. URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Gravity", GetGravity, SetGravity, Vector3, DEFAULT_GRAVITY, AM_DEFAULT);
  157. URHO3D_ATTRIBUTE("Physics FPS", int, fps_, DEFAULT_FPS, AM_DEFAULT);
  158. URHO3D_ATTRIBUTE("Max Substeps", int, maxSubSteps_, 0, AM_DEFAULT);
  159. URHO3D_ACCESSOR_ATTRIBUTE("Solver Iterations", GetNumIterations, SetNumIterations, int, 10, AM_DEFAULT);
  160. URHO3D_ATTRIBUTE("Net Max Angular Vel.", float, maxNetworkAngularVelocity_, DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY, AM_DEFAULT);
  161. URHO3D_ATTRIBUTE("Interpolation", bool, interpolation_, true, AM_FILE);
  162. URHO3D_ATTRIBUTE("Internal Edge Utility", bool, internalEdge_, true, AM_DEFAULT);
  163. URHO3D_ACCESSOR_ATTRIBUTE("Split Impulse", GetSplitImpulse, SetSplitImpulse, bool, false, AM_DEFAULT);
  164. }
  165. bool PhysicsWorld::isVisible(const btVector3& aabbMin, const btVector3& aabbMax)
  166. {
  167. if (debugRenderer_)
  168. return debugRenderer_->IsInside(BoundingBox(ToVector3(aabbMin), ToVector3(aabbMax)));
  169. else
  170. return false;
  171. }
  172. void PhysicsWorld::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
  173. {
  174. if (debugRenderer_)
  175. debugRenderer_->AddLine(ToVector3(from), ToVector3(to), Color(color.x(), color.y(), color.z()), debugDepthTest_);
  176. }
  177. void PhysicsWorld::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  178. {
  179. if (debug)
  180. {
  181. URHO3D_PROFILE(PhysicsDrawDebug);
  182. debugRenderer_ = debug;
  183. debugDepthTest_ = depthTest;
  184. world_->debugDrawWorld();
  185. debugRenderer_ = nullptr;
  186. }
  187. }
  188. void PhysicsWorld::reportErrorWarning(const char* warningString)
  189. {
  190. URHO3D_LOGWARNING("Physics: " + String(warningString));
  191. }
  192. void PhysicsWorld::drawContactPoint(const btVector3& pointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime,
  193. const btVector3& color)
  194. {
  195. }
  196. void PhysicsWorld::draw3dText(const btVector3& location, const char* textString)
  197. {
  198. }
  199. void PhysicsWorld::Update(float timeStep)
  200. {
  201. URHO3D_PROFILE(UpdatePhysics);
  202. float internalTimeStep = 1.0f / fps_;
  203. int maxSubSteps = (int)(timeStep * fps_) + 1;
  204. if (maxSubSteps_ < 0)
  205. {
  206. internalTimeStep = timeStep;
  207. maxSubSteps = 1;
  208. }
  209. else if (maxSubSteps_ > 0)
  210. maxSubSteps = Min(maxSubSteps, maxSubSteps_);
  211. delayedWorldTransforms_.Clear();
  212. simulating_ = true;
  213. if (interpolation_)
  214. world_->stepSimulation(timeStep, maxSubSteps, internalTimeStep);
  215. else
  216. {
  217. timeAcc_ += timeStep;
  218. while (timeAcc_ >= internalTimeStep && maxSubSteps > 0)
  219. {
  220. world_->stepSimulation(internalTimeStep, 0, internalTimeStep);
  221. timeAcc_ -= internalTimeStep;
  222. --maxSubSteps;
  223. }
  224. }
  225. simulating_ = false;
  226. // Apply delayed (parented) world transforms now
  227. while (!delayedWorldTransforms_.Empty())
  228. {
  229. for (HashMap<RigidBody*, DelayedWorldTransform>::Iterator i = delayedWorldTransforms_.Begin();
  230. i != delayedWorldTransforms_.End();)
  231. {
  232. const DelayedWorldTransform& transform = i->second_;
  233. // If parent's transform has already been assigned, can proceed
  234. if (!delayedWorldTransforms_.Contains(transform.parentRigidBody_))
  235. {
  236. transform.rigidBody_->ApplyWorldTransform(transform.worldPosition_, transform.worldRotation_);
  237. i = delayedWorldTransforms_.Erase(i);
  238. }
  239. else
  240. ++i;
  241. }
  242. }
  243. }
  244. void PhysicsWorld::UpdateCollisions()
  245. {
  246. world_->performDiscreteCollisionDetection();
  247. }
  248. void PhysicsWorld::SetFps(int fps)
  249. {
  250. fps_ = (unsigned)Clamp(fps, 1, 1000);
  251. MarkNetworkUpdate();
  252. }
  253. void PhysicsWorld::SetGravity(const Vector3& gravity)
  254. {
  255. world_->setGravity(ToBtVector3(gravity));
  256. MarkNetworkUpdate();
  257. }
  258. void PhysicsWorld::SetMaxSubSteps(int num)
  259. {
  260. maxSubSteps_ = num;
  261. MarkNetworkUpdate();
  262. }
  263. void PhysicsWorld::SetNumIterations(int num)
  264. {
  265. num = Clamp(num, 1, MAX_SOLVER_ITERATIONS);
  266. world_->getSolverInfo().m_numIterations = num;
  267. MarkNetworkUpdate();
  268. }
  269. void PhysicsWorld::SetUpdateEnabled(bool enable)
  270. {
  271. updateEnabled_ = enable;
  272. }
  273. void PhysicsWorld::SetInterpolation(bool enable)
  274. {
  275. interpolation_ = enable;
  276. }
  277. void PhysicsWorld::SetInternalEdge(bool enable)
  278. {
  279. internalEdge_ = enable;
  280. MarkNetworkUpdate();
  281. }
  282. void PhysicsWorld::SetSplitImpulse(bool enable)
  283. {
  284. world_->getSolverInfo().m_splitImpulse = enable;
  285. MarkNetworkUpdate();
  286. }
  287. void PhysicsWorld::SetMaxNetworkAngularVelocity(float velocity)
  288. {
  289. maxNetworkAngularVelocity_ = Clamp(velocity, 1.0f, 32767.0f);
  290. MarkNetworkUpdate();
  291. }
  292. void PhysicsWorld::Raycast(PODVector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask)
  293. {
  294. URHO3D_PROFILE(PhysicsRaycast);
  295. if (maxDistance >= M_INFINITY)
  296. URHO3D_LOGWARNING("Infinite maxDistance in physics raycast is not supported");
  297. btCollisionWorld::AllHitsRayResultCallback
  298. rayCallback(ToBtVector3(ray.origin_), ToBtVector3(ray.origin_ + maxDistance * ray.direction_));
  299. rayCallback.m_collisionFilterGroup = (short)0xffff;
  300. rayCallback.m_collisionFilterMask = (short)collisionMask;
  301. world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);
  302. for (int i = 0; i < rayCallback.m_collisionObjects.size(); ++i)
  303. {
  304. PhysicsRaycastResult newResult;
  305. newResult.body_ = static_cast<RigidBody*>(rayCallback.m_collisionObjects[i]->getUserPointer());
  306. newResult.position_ = ToVector3(rayCallback.m_hitPointWorld[i]);
  307. newResult.normal_ = ToVector3(rayCallback.m_hitNormalWorld[i]);
  308. newResult.distance_ = (newResult.position_ - ray.origin_).Length();
  309. newResult.hitFraction_ = rayCallback.m_closestHitFraction;
  310. result.Push(newResult);
  311. }
  312. Sort(result.Begin(), result.End(), CompareRaycastResults);
  313. }
  314. void PhysicsWorld::RaycastSingle(PhysicsRaycastResult& result, const Ray& ray, float maxDistance, unsigned collisionMask)
  315. {
  316. URHO3D_PROFILE(PhysicsRaycastSingle);
  317. if (maxDistance >= M_INFINITY)
  318. URHO3D_LOGWARNING("Infinite maxDistance in physics raycast is not supported");
  319. btCollisionWorld::ClosestRayResultCallback
  320. rayCallback(ToBtVector3(ray.origin_), ToBtVector3(ray.origin_ + maxDistance * ray.direction_));
  321. rayCallback.m_collisionFilterGroup = (short)0xffff;
  322. rayCallback.m_collisionFilterMask = (short)collisionMask;
  323. world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);
  324. if (rayCallback.hasHit())
  325. {
  326. result.position_ = ToVector3(rayCallback.m_hitPointWorld);
  327. result.normal_ = ToVector3(rayCallback.m_hitNormalWorld);
  328. result.distance_ = (result.position_ - ray.origin_).Length();
  329. result.hitFraction_ = rayCallback.m_closestHitFraction;
  330. result.body_ = static_cast<RigidBody*>(rayCallback.m_collisionObject->getUserPointer());
  331. }
  332. else
  333. {
  334. result.position_ = Vector3::ZERO;
  335. result.normal_ = Vector3::ZERO;
  336. result.distance_ = M_INFINITY;
  337. result.hitFraction_ = 0.0f;
  338. result.body_ = nullptr;
  339. }
  340. }
  341. void PhysicsWorld::RaycastSingleSegmented(PhysicsRaycastResult& result, const Ray& ray, float maxDistance, float segmentDistance, unsigned collisionMask, float overlapDistance)
  342. {
  343. URHO3D_PROFILE(PhysicsRaycastSingleSegmented);
  344. assert(overlapDistance < segmentDistance);
  345. if (maxDistance >= M_INFINITY)
  346. URHO3D_LOGWARNING("Infinite maxDistance in physics raycast is not supported");
  347. const btVector3 direction = ToBtVector3(ray.direction_);
  348. const auto count = CeilToInt(maxDistance / segmentDistance);
  349. btVector3 start = ToBtVector3(ray.origin_);
  350. // overlap a bit with the previous segment for better precision, to avoid missing hits
  351. const btVector3 overlap = direction * overlapDistance;
  352. float remainingDistance = maxDistance;
  353. for (auto i = 0; i < count; ++i)
  354. {
  355. const float distance = Min(remainingDistance, segmentDistance); // The last segment may be shorter
  356. const btVector3 end = start + distance * direction;
  357. btCollisionWorld::ClosestRayResultCallback rayCallback(start, end);
  358. rayCallback.m_collisionFilterGroup = (short)0xffff;
  359. rayCallback.m_collisionFilterMask = (short)collisionMask;
  360. world_->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);
  361. if (rayCallback.hasHit())
  362. {
  363. result.position_ = ToVector3(rayCallback.m_hitPointWorld);
  364. result.normal_ = ToVector3(rayCallback.m_hitNormalWorld);
  365. result.distance_ = (result.position_ - ray.origin_).Length();
  366. result.hitFraction_ = rayCallback.m_closestHitFraction;
  367. result.body_ = static_cast<RigidBody*>(rayCallback.m_collisionObject->getUserPointer());
  368. // No need to cast the rest of the segments
  369. return;
  370. }
  371. // Use the end position as the new start position
  372. start = end - overlap;
  373. remainingDistance -= segmentDistance;
  374. }
  375. // Didn't hit anything
  376. result.position_ = Vector3::ZERO;
  377. result.normal_ = Vector3::ZERO;
  378. result.distance_ = M_INFINITY;
  379. result.hitFraction_ = 0.0f;
  380. result.body_ = nullptr;
  381. }
  382. void PhysicsWorld::SphereCast(PhysicsRaycastResult& result, const Ray& ray, float radius, float maxDistance, unsigned collisionMask)
  383. {
  384. URHO3D_PROFILE(PhysicsSphereCast);
  385. if (maxDistance >= M_INFINITY)
  386. URHO3D_LOGWARNING("Infinite maxDistance in physics sphere cast is not supported");
  387. btSphereShape shape(radius);
  388. Vector3 endPos = ray.origin_ + maxDistance * ray.direction_;
  389. btCollisionWorld::ClosestConvexResultCallback
  390. convexCallback(ToBtVector3(ray.origin_), ToBtVector3(endPos));
  391. convexCallback.m_collisionFilterGroup = (short)0xffff;
  392. convexCallback.m_collisionFilterMask = (short)collisionMask;
  393. world_->convexSweepTest(&shape, btTransform(btQuaternion::getIdentity(), convexCallback.m_convexFromWorld),
  394. btTransform(btQuaternion::getIdentity(), convexCallback.m_convexToWorld), convexCallback);
  395. if (convexCallback.hasHit())
  396. {
  397. result.body_ = static_cast<RigidBody*>(convexCallback.m_hitCollisionObject->getUserPointer());
  398. result.position_ = ToVector3(convexCallback.m_hitPointWorld);
  399. result.normal_ = ToVector3(convexCallback.m_hitNormalWorld);
  400. result.distance_ = convexCallback.m_closestHitFraction * (endPos - ray.origin_).Length();
  401. result.hitFraction_ = convexCallback.m_closestHitFraction;
  402. }
  403. else
  404. {
  405. result.body_ = nullptr;
  406. result.position_ = Vector3::ZERO;
  407. result.normal_ = Vector3::ZERO;
  408. result.distance_ = M_INFINITY;
  409. result.hitFraction_ = 0.0f;
  410. }
  411. }
  412. void PhysicsWorld::ConvexCast(PhysicsRaycastResult& result, CollisionShape* shape, const Vector3& startPos,
  413. const Quaternion& startRot, const Vector3& endPos, const Quaternion& endRot, unsigned collisionMask)
  414. {
  415. if (!shape || !shape->GetCollisionShape())
  416. {
  417. URHO3D_LOGERROR("Null collision shape for convex cast");
  418. result.body_ = nullptr;
  419. result.position_ = Vector3::ZERO;
  420. result.normal_ = Vector3::ZERO;
  421. result.distance_ = M_INFINITY;
  422. result.hitFraction_ = 0.0f;
  423. return;
  424. }
  425. // If shape is attached in a rigidbody, set its collision group temporarily to 0 to make sure it is not returned in the sweep result
  426. auto* bodyComp = shape->GetComponent<RigidBody>();
  427. btRigidBody* body = bodyComp ? bodyComp->GetBody() : nullptr;
  428. btBroadphaseProxy* proxy = body ? body->getBroadphaseProxy() : nullptr;
  429. short group = 0;
  430. if (proxy)
  431. {
  432. group = proxy->m_collisionFilterGroup;
  433. proxy->m_collisionFilterGroup = 0;
  434. }
  435. // Take the shape's offset position & rotation into account
  436. Node* shapeNode = shape->GetNode();
  437. Matrix3x4 startTransform(startPos, startRot, shapeNode ? shapeNode->GetWorldScale() : Vector3::ONE);
  438. Matrix3x4 endTransform(endPos, endRot, shapeNode ? shapeNode->GetWorldScale() : Vector3::ONE);
  439. Vector3 effectiveStartPos = startTransform * shape->GetPosition();
  440. Vector3 effectiveEndPos = endTransform * shape->GetPosition();
  441. Quaternion effectiveStartRot = startRot * shape->GetRotation();
  442. Quaternion effectiveEndRot = endRot * shape->GetRotation();
  443. ConvexCast(result, shape->GetCollisionShape(), effectiveStartPos, effectiveStartRot, effectiveEndPos, effectiveEndRot, collisionMask);
  444. // Restore the collision group
  445. if (proxy)
  446. proxy->m_collisionFilterGroup = group;
  447. }
  448. void PhysicsWorld::ConvexCast(PhysicsRaycastResult& result, btCollisionShape* shape, const Vector3& startPos,
  449. const Quaternion& startRot, const Vector3& endPos, const Quaternion& endRot, unsigned collisionMask)
  450. {
  451. if (!shape)
  452. {
  453. URHO3D_LOGERROR("Null collision shape for convex cast");
  454. result.body_ = nullptr;
  455. result.position_ = Vector3::ZERO;
  456. result.normal_ = Vector3::ZERO;
  457. result.distance_ = M_INFINITY;
  458. result.hitFraction_ = 0.0f;
  459. return;
  460. }
  461. if (!shape->isConvex())
  462. {
  463. URHO3D_LOGERROR("Can not use non-convex collision shape for convex cast");
  464. result.body_ = nullptr;
  465. result.position_ = Vector3::ZERO;
  466. result.normal_ = Vector3::ZERO;
  467. result.distance_ = M_INFINITY;
  468. result.hitFraction_ = 0.0f;
  469. return;
  470. }
  471. URHO3D_PROFILE(PhysicsConvexCast);
  472. btCollisionWorld::ClosestConvexResultCallback convexCallback(ToBtVector3(startPos), ToBtVector3(endPos));
  473. convexCallback.m_collisionFilterGroup = (short)0xffff;
  474. convexCallback.m_collisionFilterMask = (short)collisionMask;
  475. world_->convexSweepTest(static_cast<btConvexShape*>(shape), btTransform(ToBtQuaternion(startRot),
  476. convexCallback.m_convexFromWorld), btTransform(ToBtQuaternion(endRot), convexCallback.m_convexToWorld),
  477. convexCallback);
  478. if (convexCallback.hasHit())
  479. {
  480. result.body_ = static_cast<RigidBody*>(convexCallback.m_hitCollisionObject->getUserPointer());
  481. result.position_ = ToVector3(convexCallback.m_hitPointWorld);
  482. result.normal_ = ToVector3(convexCallback.m_hitNormalWorld);
  483. result.distance_ = convexCallback.m_closestHitFraction * (endPos - startPos).Length();
  484. result.hitFraction_ = convexCallback.m_closestHitFraction;
  485. }
  486. else
  487. {
  488. result.body_ = nullptr;
  489. result.position_ = Vector3::ZERO;
  490. result.normal_ = Vector3::ZERO;
  491. result.distance_ = M_INFINITY;
  492. result.hitFraction_ = 0.0f;
  493. }
  494. }
  495. void PhysicsWorld::RemoveCachedGeometry(Model* model)
  496. {
  497. RemoveCachedGeometryImpl(triMeshCache_, model);
  498. RemoveCachedGeometryImpl(convexCache_, model);
  499. RemoveCachedGeometryImpl(gimpactTrimeshCache_, model);
  500. }
  501. void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const Sphere& sphere, unsigned collisionMask)
  502. {
  503. URHO3D_PROFILE(PhysicsSphereQuery);
  504. result.Clear();
  505. btSphereShape sphereShape(sphere.radius_);
  506. unique_ptr<btRigidBody> tempRigidBody(new btRigidBody(1.0f, nullptr, &sphereShape));
  507. tempRigidBody->setWorldTransform(btTransform(btQuaternion::getIdentity(), ToBtVector3(sphere.center_)));
  508. // Need to activate the temporary rigid body to get reliable results from static, sleeping objects
  509. tempRigidBody->activate();
  510. world_->addRigidBody(tempRigidBody.get());
  511. PhysicsQueryCallback callback(result, collisionMask);
  512. world_->contactTest(tempRigidBody.get(), callback);
  513. world_->removeRigidBody(tempRigidBody.get());
  514. }
  515. void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const BoundingBox& box, unsigned collisionMask)
  516. {
  517. URHO3D_PROFILE(PhysicsBoxQuery);
  518. result.Clear();
  519. btBoxShape boxShape(ToBtVector3(box.HalfSize()));
  520. unique_ptr<btRigidBody> tempRigidBody(new btRigidBody(1.0f, nullptr, &boxShape));
  521. tempRigidBody->setWorldTransform(btTransform(btQuaternion::getIdentity(), ToBtVector3(box.Center())));
  522. tempRigidBody->activate();
  523. world_->addRigidBody(tempRigidBody.get());
  524. PhysicsQueryCallback callback(result, collisionMask);
  525. world_->contactTest(tempRigidBody.get(), callback);
  526. world_->removeRigidBody(tempRigidBody.get());
  527. }
  528. void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const RigidBody* body)
  529. {
  530. URHO3D_PROFILE(PhysicsBodyQuery);
  531. result.Clear();
  532. if (!body || !body->GetBody())
  533. return;
  534. PhysicsQueryCallback callback(result, body->GetCollisionMask());
  535. world_->contactTest(body->GetBody(), callback);
  536. // Remove the body itself from the returned list
  537. for (unsigned i = 0; i < result.Size(); i++)
  538. {
  539. if (result[i] == body)
  540. {
  541. result.Erase(i);
  542. break;
  543. }
  544. }
  545. }
  546. void PhysicsWorld::GetCollidingBodies(PODVector<RigidBody*>& result, const RigidBody* body)
  547. {
  548. URHO3D_PROFILE(GetCollidingBodies);
  549. result.Clear();
  550. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody>>, ManifoldPair>::Iterator i = currentCollisions_.Begin();
  551. i != currentCollisions_.End(); ++i)
  552. {
  553. if (i->first_.first_ == body)
  554. {
  555. if (i->first_.second_)
  556. result.Push(i->first_.second_);
  557. }
  558. else if (i->first_.second_ == body)
  559. {
  560. if (i->first_.first_)
  561. result.Push(i->first_.first_);
  562. }
  563. }
  564. }
  565. Vector3 PhysicsWorld::GetGravity() const
  566. {
  567. return ToVector3(world_->getGravity());
  568. }
  569. int PhysicsWorld::GetNumIterations() const
  570. {
  571. return world_->getSolverInfo().m_numIterations;
  572. }
  573. bool PhysicsWorld::GetSplitImpulse() const
  574. {
  575. return world_->getSolverInfo().m_splitImpulse != 0;
  576. }
  577. void PhysicsWorld::AddRigidBody(RigidBody* body)
  578. {
  579. rigidBodies_.Push(body);
  580. }
  581. void PhysicsWorld::RemoveRigidBody(RigidBody* body)
  582. {
  583. rigidBodies_.Remove(body);
  584. // Remove possible dangling pointer from the delayedWorldTransforms structure
  585. delayedWorldTransforms_.Erase(body);
  586. }
  587. void PhysicsWorld::AddCollisionShape(CollisionShape* shape)
  588. {
  589. collisionShapes_.Push(shape);
  590. }
  591. void PhysicsWorld::RemoveCollisionShape(CollisionShape* shape)
  592. {
  593. collisionShapes_.Remove(shape);
  594. }
  595. void PhysicsWorld::AddConstraint(Constraint* constraint)
  596. {
  597. constraints_.Push(constraint);
  598. }
  599. void PhysicsWorld::RemoveConstraint(Constraint* constraint)
  600. {
  601. constraints_.Remove(constraint);
  602. }
  603. void PhysicsWorld::AddDelayedWorldTransform(const DelayedWorldTransform& transform)
  604. {
  605. delayedWorldTransforms_[transform.rigidBody_] = transform;
  606. }
  607. void PhysicsWorld::DrawDebugGeometry(bool depthTest)
  608. {
  609. auto* debug = GetComponent<DebugRenderer>();
  610. DrawDebugGeometry(debug, depthTest);
  611. }
  612. void PhysicsWorld::SetDebugRenderer(DebugRenderer* debug)
  613. {
  614. debugRenderer_ = debug;
  615. }
  616. void PhysicsWorld::SetDebugDepthTest(bool enable)
  617. {
  618. debugDepthTest_ = enable;
  619. }
  620. void PhysicsWorld::CleanupGeometryCache()
  621. {
  622. // Remove cached shapes whose only reference is the cache itself
  623. CleanupGeometryCacheImpl(triMeshCache_);
  624. CleanupGeometryCacheImpl(convexCache_);
  625. CleanupGeometryCacheImpl(gimpactTrimeshCache_);
  626. }
  627. void PhysicsWorld::OnSceneSet(Scene* scene)
  628. {
  629. // Subscribe to the scene subsystem update, which will trigger the physics simulation step
  630. if (scene)
  631. {
  632. scene_ = GetScene();
  633. SubscribeToEvent(scene_, E_SCENESUBSYSTEMUPDATE, URHO3D_HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
  634. }
  635. else
  636. UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
  637. }
  638. void PhysicsWorld::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
  639. {
  640. if (!updateEnabled_)
  641. return;
  642. using namespace SceneSubsystemUpdate;
  643. Update(eventData[P_TIMESTEP].GetFloat());
  644. }
  645. void PhysicsWorld::PreStep(float timeStep)
  646. {
  647. // Send pre-step event
  648. using namespace PhysicsPreStep;
  649. VariantMap& eventData = GetEventDataMap();
  650. eventData[P_WORLD] = this;
  651. eventData[P_TIMESTEP] = timeStep;
  652. SendEvent(E_PHYSICSPRESTEP, eventData);
  653. // Start profiling block for the actual simulation step
  654. #ifdef URHO3D_PROFILING
  655. auto* profiler = GetSubsystem<Profiler>();
  656. if (profiler)
  657. profiler->BeginBlock("StepSimulation");
  658. #endif
  659. }
  660. void PhysicsWorld::PostStep(float timeStep)
  661. {
  662. #ifdef URHO3D_PROFILING
  663. auto* profiler = GetSubsystem<Profiler>();
  664. if (profiler)
  665. profiler->EndBlock();
  666. #endif
  667. SendCollisionEvents();
  668. // Send post-step event
  669. using namespace PhysicsPostStep;
  670. VariantMap& eventData = GetEventDataMap();
  671. eventData[P_WORLD] = this;
  672. eventData[P_TIMESTEP] = timeStep;
  673. SendEvent(E_PHYSICSPOSTSTEP, eventData);
  674. }
  675. void PhysicsWorld::SendCollisionEvents()
  676. {
  677. URHO3D_PROFILE(SendCollisionEvents);
  678. currentCollisions_.Clear();
  679. physicsCollisionData_.Clear();
  680. nodeCollisionData_.Clear();
  681. int numManifolds = collisionDispatcher_->getNumManifolds();
  682. if (numManifolds)
  683. {
  684. physicsCollisionData_[PhysicsCollision::P_WORLD] = this;
  685. for (int i = 0; i < numManifolds; ++i)
  686. {
  687. btPersistentManifold* contactManifold = collisionDispatcher_->getManifoldByIndexInternal(i);
  688. // First check that there are actual contacts, as the manifold exists also when objects are close but not touching
  689. if (!contactManifold->getNumContacts())
  690. continue;
  691. const btCollisionObject* objectA = contactManifold->getBody0();
  692. const btCollisionObject* objectB = contactManifold->getBody1();
  693. auto* bodyA = static_cast<RigidBody*>(objectA->getUserPointer());
  694. auto* bodyB = static_cast<RigidBody*>(objectB->getUserPointer());
  695. // If it's not a rigidbody, maybe a ghost object
  696. if (!bodyA || !bodyB)
  697. continue;
  698. // Skip collision event signaling if both objects are static, or if collision event mode does not match
  699. if (bodyA->GetMass() == 0.0f && bodyB->GetMass() == 0.0f)
  700. continue;
  701. if (bodyA->GetCollisionEventMode() == COLLISION_NEVER || bodyB->GetCollisionEventMode() == COLLISION_NEVER)
  702. continue;
  703. if (bodyA->GetCollisionEventMode() == COLLISION_ACTIVE && bodyB->GetCollisionEventMode() == COLLISION_ACTIVE &&
  704. !bodyA->IsActive() && !bodyB->IsActive())
  705. continue;
  706. WeakPtr<RigidBody> bodyWeakA(bodyA);
  707. WeakPtr<RigidBody> bodyWeakB(bodyB);
  708. // First only store the collision pair as weak pointers and the manifold pointer, so user code can safely destroy
  709. // objects during collision event handling
  710. Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody>> bodyPair;
  711. if (bodyA < bodyB)
  712. {
  713. bodyPair = MakePair(bodyWeakA, bodyWeakB);
  714. currentCollisions_[bodyPair].manifold_ = contactManifold;
  715. }
  716. else
  717. {
  718. bodyPair = MakePair(bodyWeakB, bodyWeakA);
  719. currentCollisions_[bodyPair].flippedManifold_ = contactManifold;
  720. }
  721. }
  722. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody>>, ManifoldPair>::Iterator i = currentCollisions_.Begin();
  723. i != currentCollisions_.End(); ++i)
  724. {
  725. RigidBody* bodyA = i->first_.first_;
  726. RigidBody* bodyB = i->first_.second_;
  727. if (!bodyA || !bodyB)
  728. continue;
  729. Node* nodeA = bodyA->GetNode();
  730. Node* nodeB = bodyB->GetNode();
  731. WeakPtr<Node> nodeWeakA(nodeA);
  732. WeakPtr<Node> nodeWeakB(nodeB);
  733. bool trigger = bodyA->IsTrigger() || bodyB->IsTrigger();
  734. bool newCollision = !previousCollisions_.Contains(i->first_);
  735. physicsCollisionData_[PhysicsCollision::P_NODEA] = nodeA;
  736. physicsCollisionData_[PhysicsCollision::P_NODEB] = nodeB;
  737. physicsCollisionData_[PhysicsCollision::P_BODYA] = bodyA;
  738. physicsCollisionData_[PhysicsCollision::P_BODYB] = bodyB;
  739. physicsCollisionData_[PhysicsCollision::P_TRIGGER] = trigger;
  740. contacts_.Clear();
  741. // "Pointers not flipped"-manifold, send unmodified normals
  742. btPersistentManifold* contactManifold = i->second_.manifold_;
  743. if (contactManifold)
  744. {
  745. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  746. {
  747. btManifoldPoint& point = contactManifold->getContactPoint(j);
  748. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  749. contacts_.WriteVector3(ToVector3(point.m_normalWorldOnB));
  750. contacts_.WriteFloat(point.m_distance1);
  751. contacts_.WriteFloat(point.m_appliedImpulse);
  752. }
  753. }
  754. // "Pointers flipped"-manifold, flip normals also
  755. contactManifold = i->second_.flippedManifold_;
  756. if (contactManifold)
  757. {
  758. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  759. {
  760. btManifoldPoint& point = contactManifold->getContactPoint(j);
  761. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  762. contacts_.WriteVector3(-ToVector3(point.m_normalWorldOnB));
  763. contacts_.WriteFloat(point.m_distance1);
  764. contacts_.WriteFloat(point.m_appliedImpulse);
  765. }
  766. }
  767. physicsCollisionData_[PhysicsCollision::P_CONTACTS] = contacts_.GetBuffer();
  768. // Send separate collision start event if collision is new
  769. if (newCollision)
  770. {
  771. SendEvent(E_PHYSICSCOLLISIONSTART, physicsCollisionData_);
  772. // Skip rest of processing if either of the nodes or bodies is removed as a response to the event
  773. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  774. continue;
  775. }
  776. // Then send the ongoing collision event
  777. SendEvent(E_PHYSICSCOLLISION, physicsCollisionData_);
  778. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  779. continue;
  780. nodeCollisionData_[NodeCollision::P_BODY] = bodyA;
  781. nodeCollisionData_[NodeCollision::P_OTHERNODE] = nodeB;
  782. nodeCollisionData_[NodeCollision::P_OTHERBODY] = bodyB;
  783. nodeCollisionData_[NodeCollision::P_TRIGGER] = trigger;
  784. nodeCollisionData_[NodeCollision::P_CONTACTS] = contacts_.GetBuffer();
  785. if (newCollision)
  786. {
  787. nodeA->SendEvent(E_NODECOLLISIONSTART, nodeCollisionData_);
  788. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  789. continue;
  790. }
  791. nodeA->SendEvent(E_NODECOLLISION, nodeCollisionData_);
  792. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  793. continue;
  794. // Flip perspective to body B
  795. contacts_.Clear();
  796. contactManifold = i->second_.manifold_;
  797. if (contactManifold)
  798. {
  799. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  800. {
  801. btManifoldPoint& point = contactManifold->getContactPoint(j);
  802. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  803. contacts_.WriteVector3(-ToVector3(point.m_normalWorldOnB));
  804. contacts_.WriteFloat(point.m_distance1);
  805. contacts_.WriteFloat(point.m_appliedImpulse);
  806. }
  807. }
  808. contactManifold = i->second_.flippedManifold_;
  809. if (contactManifold)
  810. {
  811. for (int j = 0; j < contactManifold->getNumContacts(); ++j)
  812. {
  813. btManifoldPoint& point = contactManifold->getContactPoint(j);
  814. contacts_.WriteVector3(ToVector3(point.m_positionWorldOnB));
  815. contacts_.WriteVector3(ToVector3(point.m_normalWorldOnB));
  816. contacts_.WriteFloat(point.m_distance1);
  817. contacts_.WriteFloat(point.m_appliedImpulse);
  818. }
  819. }
  820. nodeCollisionData_[NodeCollision::P_BODY] = bodyB;
  821. nodeCollisionData_[NodeCollision::P_OTHERNODE] = nodeA;
  822. nodeCollisionData_[NodeCollision::P_OTHERBODY] = bodyA;
  823. nodeCollisionData_[NodeCollision::P_CONTACTS] = contacts_.GetBuffer();
  824. if (newCollision)
  825. {
  826. nodeB->SendEvent(E_NODECOLLISIONSTART, nodeCollisionData_);
  827. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  828. continue;
  829. }
  830. nodeB->SendEvent(E_NODECOLLISION, nodeCollisionData_);
  831. }
  832. }
  833. // Send collision end events as applicable
  834. {
  835. physicsCollisionData_[PhysicsCollisionEnd::P_WORLD] = this;
  836. for (HashMap<Pair<WeakPtr<RigidBody>, WeakPtr<RigidBody>>, ManifoldPair>::Iterator
  837. i = previousCollisions_.Begin(); i != previousCollisions_.End(); ++i)
  838. {
  839. if (!currentCollisions_.Contains(i->first_))
  840. {
  841. RigidBody* bodyA = i->first_.first_;
  842. RigidBody* bodyB = i->first_.second_;
  843. if (!bodyA || !bodyB)
  844. continue;
  845. bool trigger = bodyA->IsTrigger() || bodyB->IsTrigger();
  846. // Skip collision event signaling if both objects are static, or if collision event mode does not match
  847. if (bodyA->GetMass() == 0.0f && bodyB->GetMass() == 0.0f)
  848. continue;
  849. if (bodyA->GetCollisionEventMode() == COLLISION_NEVER || bodyB->GetCollisionEventMode() == COLLISION_NEVER)
  850. continue;
  851. if (bodyA->GetCollisionEventMode() == COLLISION_ACTIVE && bodyB->GetCollisionEventMode() == COLLISION_ACTIVE &&
  852. !bodyA->IsActive() && !bodyB->IsActive())
  853. continue;
  854. Node* nodeA = bodyA->GetNode();
  855. Node* nodeB = bodyB->GetNode();
  856. WeakPtr<Node> nodeWeakA(nodeA);
  857. WeakPtr<Node> nodeWeakB(nodeB);
  858. physicsCollisionData_[PhysicsCollisionEnd::P_BODYA] = bodyA;
  859. physicsCollisionData_[PhysicsCollisionEnd::P_BODYB] = bodyB;
  860. physicsCollisionData_[PhysicsCollisionEnd::P_NODEA] = nodeA;
  861. physicsCollisionData_[PhysicsCollisionEnd::P_NODEB] = nodeB;
  862. physicsCollisionData_[PhysicsCollisionEnd::P_TRIGGER] = trigger;
  863. SendEvent(E_PHYSICSCOLLISIONEND, physicsCollisionData_);
  864. // Skip rest of processing if either of the nodes or bodies is removed as a response to the event
  865. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  866. continue;
  867. nodeCollisionData_[NodeCollisionEnd::P_BODY] = bodyA;
  868. nodeCollisionData_[NodeCollisionEnd::P_OTHERNODE] = nodeB;
  869. nodeCollisionData_[NodeCollisionEnd::P_OTHERBODY] = bodyB;
  870. nodeCollisionData_[NodeCollisionEnd::P_TRIGGER] = trigger;
  871. nodeA->SendEvent(E_NODECOLLISIONEND, nodeCollisionData_);
  872. if (!nodeWeakA || !nodeWeakB || !i->first_.first_ || !i->first_.second_)
  873. continue;
  874. nodeCollisionData_[NodeCollisionEnd::P_BODY] = bodyB;
  875. nodeCollisionData_[NodeCollisionEnd::P_OTHERNODE] = nodeA;
  876. nodeCollisionData_[NodeCollisionEnd::P_OTHERBODY] = bodyA;
  877. nodeB->SendEvent(E_NODECOLLISIONEND, nodeCollisionData_);
  878. }
  879. }
  880. }
  881. previousCollisions_ = currentCollisions_;
  882. }
  883. void RegisterPhysicsLibrary(Context* context)
  884. {
  885. CollisionShape::RegisterObject(context);
  886. RigidBody::RegisterObject(context);
  887. Constraint::RegisterObject(context);
  888. PhysicsWorld::RegisterObject(context);
  889. RaycastVehicle::RegisterObject(context);
  890. }
  891. }