PhysicsWorld.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "DebugRenderer.h"
  25. #include "Log.h"
  26. #include "PhysicsEvents.h"
  27. #include "PhysicsWorld.h"
  28. #include "Profiler.h"
  29. #include "Ray.h"
  30. #include "RigidBody.h"
  31. #include "Scene.h"
  32. #include "SceneEvents.h"
  33. #include "StringUtils.h"
  34. #include <ode/ode.h>
  35. #include <algorithm>
  36. #include "DebugNew.h"
  37. unsigned numWorlds = 0;
  38. static bool compareRaycastResults(const PhysicsRaycastResult& lhs, const PhysicsRaycastResult& rhs)
  39. {
  40. return lhs.mDistance < rhs.mDistance;
  41. }
  42. PhysicsWorld::PhysicsWorld() :
  43. mWorld(0),
  44. mSpace(0),
  45. mRayGeometry(0),
  46. mContactJoints(0),
  47. mFps(60),
  48. mMaxContacts(20),
  49. mBounceThreshold(0.1f),
  50. mAngularMaxNetVelocity(256.0f),
  51. mTimeAcc(0.0f),
  52. mDrawDebugGeometry(false)
  53. {
  54. if (!numWorlds)
  55. dInitODE();
  56. mWorld = dWorldCreate();
  57. mSpace = dHashSpaceCreate(0);
  58. mContactJoints = dJointGroupCreate(0);
  59. ++numWorlds;
  60. // Create ray geometry for physics world raycasts
  61. mRayGeometry = dCreateRay(mSpace, 0.0f);
  62. // Enable automatic resting of rigid bodies
  63. dWorldSetAutoDisableFlag(mWorld, 1);
  64. subscribeToEvent(EVENT_POSTRENDERUPDATE, EVENT_HANDLER(PhysicsWorld, handlePostRenderUpdate));
  65. }
  66. PhysicsWorld::~PhysicsWorld()
  67. {
  68. if (mContactJoints)
  69. {
  70. dJointGroupDestroy(mContactJoints);
  71. mContactJoints = 0;
  72. }
  73. if (mRayGeometry)
  74. {
  75. dGeomDestroy(mRayGeometry);
  76. mRayGeometry = 0;
  77. }
  78. if (mSpace)
  79. {
  80. dSpaceDestroy(mSpace);
  81. mSpace = 0;
  82. }
  83. if (mWorld)
  84. {
  85. dWorldDestroy(mWorld);
  86. mWorld = 0;
  87. --numWorlds;
  88. if (!numWorlds)
  89. dCloseODE();
  90. }
  91. }
  92. void PhysicsWorld::save(Serializer& dest)
  93. {
  94. writeExtensionType(dest);
  95. dest.writeVector3(getGravity());
  96. dest.writeUInt(getFps());
  97. dest.writeUInt(getMaxContacts());
  98. dest.writeFloat(getBounceThreshold());
  99. dest.writeFloat(getLinearRestThreshold());
  100. dest.writeFloat(getLinearDampingThreshold());
  101. dest.writeFloat(getLinearDampingScale());
  102. dest.writeFloat(getAngularRestThreshold());
  103. dest.writeFloat(getAngularDampingThreshold());
  104. dest.writeFloat(getAngularDampingScale());
  105. dest.writeFloat(getAngularMaxNetVelocity());
  106. dest.writeFloat(getERP());
  107. dest.writeFloat(getCFM());
  108. dest.writeFloat(getContactSurfaceLayer());
  109. dest.writeFloat(getTimeAccumulator());
  110. dest.writeUInt(getRandomSeed());
  111. }
  112. void PhysicsWorld::load(Deserializer& source)
  113. {
  114. checkExtensionType(source);
  115. setGravity(source.readVector3());
  116. setFps(source.readUInt());
  117. setMaxContacts(source.readUInt());
  118. setBounceThreshold(source.readFloat());
  119. setLinearRestThreshold(source.readFloat());
  120. float threshold = source.readFloat();
  121. float scale = source.readFloat();
  122. setLinearDamping(threshold, scale);
  123. setAngularRestThreshold(source.readFloat());
  124. threshold = source.readFloat();
  125. scale = source.readFloat();
  126. setAngularDamping(threshold, scale);
  127. setAngularMaxNetVelocity(source.readFloat());
  128. setERP(source.readFloat());
  129. setCFM(source.readFloat());
  130. setContactSurfaceLayer(source.readFloat());
  131. setTimeAccumulator(source.readFloat());
  132. setRandomSeed(source.readUInt());
  133. }
  134. void PhysicsWorld::saveXML(XMLElement& dest)
  135. {
  136. XMLElement physicsElem = dest.createChildElement("physics");
  137. physicsElem.setVector3("gravity", getGravity());
  138. physicsElem.setInt("fps", getFps());
  139. physicsElem.setFloat("timeacc", getTimeAccumulator());
  140. physicsElem.setInt("randomseed", getRandomSeed());
  141. XMLElement contactsElem = physicsElem.createChildElement("contacts");
  142. contactsElem.setInt("max", getMaxContacts());
  143. contactsElem.setFloat("bouncethreshold", getBounceThreshold());
  144. contactsElem.setFloat("erp", getERP());
  145. contactsElem.setFloat("cfm", getCFM());
  146. contactsElem.setFloat("surfacelayer", getContactSurfaceLayer());
  147. XMLElement linearElem = physicsElem.createChildElement("linear");
  148. XMLElement angularElem = physicsElem.createChildElement("angular");
  149. linearElem.setFloat("restthreshold", getLinearRestThreshold());
  150. linearElem.setFloat("dampingthreshold", getLinearDampingThreshold());
  151. linearElem.setFloat("dampingscale", getLinearDampingScale());
  152. angularElem.setFloat("restthreshold", getAngularRestThreshold());
  153. angularElem.setFloat("dampingthreshold", getAngularDampingThreshold());
  154. angularElem.setFloat("dampingscale", getAngularDampingScale());
  155. angularElem.setFloat("maxnetvelocity", getAngularMaxNetVelocity());
  156. }
  157. void PhysicsWorld::loadXML(const XMLElement& source)
  158. {
  159. XMLElement physicsElem = source.getChildElement("physics");
  160. setGravity(physicsElem.getVector3("gravity"));
  161. setFps(physicsElem.getInt("fps"));
  162. if (physicsElem.hasAttribute("timeacc"))
  163. setTimeAccumulator(physicsElem.getFloat("timeacc"));
  164. if (physicsElem.hasAttribute("randomseed"))
  165. setRandomSeed(physicsElem.getInt("randomseed"));
  166. if (physicsElem.hasChildElement("contacts"))
  167. {
  168. XMLElement contactsElem = physicsElem.getChildElement("contacts");
  169. setMaxContacts(contactsElem.getInt("max"));
  170. setBounceThreshold(contactsElem.getFloat("bouncethreshold"));
  171. setERP(contactsElem.getFloat("erp"));
  172. setCFM(contactsElem.getFloat("cfm"));
  173. setContactSurfaceLayer(contactsElem.getFloat("surfacelayer"));
  174. }
  175. if (physicsElem.hasChildElement("linear"))
  176. {
  177. XMLElement linearElem = physicsElem.getChildElement("linear");
  178. setLinearRestThreshold(linearElem.getFloat("restthreshold"));
  179. setLinearDamping(linearElem.getFloat("dampingthreshold"), linearElem.getFloat("dampingscale"));
  180. }
  181. if (physicsElem.hasChildElement("angular"))
  182. {
  183. XMLElement angularElem = physicsElem.getChildElement("angular");
  184. setAngularRestThreshold(angularElem.getFloat("restthreshold"));
  185. setAngularDamping(angularElem.getFloat("dampingthreshold"), angularElem.getFloat("dampingscale"));
  186. setAngularMaxNetVelocity(angularElem.getFloat("maxnetvelocity"));
  187. }
  188. }
  189. void PhysicsWorld::update(float timeStep)
  190. {
  191. PROFILE(Physics_Update);
  192. float internalTimeStep = 1.0f / mFps;
  193. while (timeStep > 0.0f)
  194. {
  195. float currentStep = min(timeStep, internalTimeStep);
  196. mTimeAcc += currentStep;
  197. timeStep -= currentStep;
  198. if (mTimeAcc >= internalTimeStep)
  199. {
  200. mTimeAcc -= internalTimeStep;
  201. // Send pre-step event
  202. using namespace PhysicsPreStep;
  203. VariantMap eventData;
  204. eventData[P_WORLD] = (void*)this;
  205. eventData[P_SCENE] = (void*)mScene;
  206. eventData[P_TIMESTEP] = internalTimeStep;
  207. sendEvent(EVENT_PHYSICSPRESTEP, eventData);
  208. // Store the previous transforms of the physics objects
  209. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  210. (*i)->preStep();
  211. // Collide, step the world, and clear contact joints
  212. {
  213. PROFILE(Physics_Collide);
  214. dSpaceCollide(mSpace, this, nearCallback);
  215. }
  216. {
  217. PROFILE(Physics_Step);
  218. dWorldQuickStep(mWorld, internalTimeStep);
  219. dJointGroupEmpty(mContactJoints);
  220. mPreviousCollisions = mCurrentCollisions;
  221. mCurrentCollisions.clear();
  222. }
  223. // Send accumulated collision events
  224. sendCollisionEvents();
  225. // Interpolate transforms of physics objects
  226. float t = clamp(mTimeAcc / internalTimeStep, 0.0f, 1.0f);
  227. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  228. (*i)->postStep(t);
  229. // Send post-step event
  230. sendEvent(EVENT_PHYSICSPOSTSTEP, eventData);
  231. }
  232. }
  233. }
  234. void PhysicsWorld::setPlayback(bool enable)
  235. {
  236. // During scene rewind/replay all non-predicted dynamic & kinematic bodies are temporarily disabled
  237. if (enable)
  238. {
  239. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  240. {
  241. RigidBody* body = *i;
  242. if ((body->getMode() != PHYS_STATIC) && (!body->checkPrediction()))
  243. body->setTempDisabled(true);
  244. }
  245. }
  246. else
  247. {
  248. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  249. {
  250. RigidBody* body = *i;
  251. body->setTempDisabled(false);
  252. }
  253. }
  254. }
  255. void PhysicsWorld::setGravity(const Vector3& gravity)
  256. {
  257. dWorldSetGravity(mWorld, gravity.mX, gravity.mY, gravity.mZ);;
  258. }
  259. void PhysicsWorld::setFps(int fps)
  260. {
  261. mFps = max(fps, 1);
  262. }
  263. void PhysicsWorld::setMaxContacts(unsigned contacts)
  264. {
  265. mMaxContacts = max(contacts, 1);
  266. }
  267. void PhysicsWorld::setLinearRestThreshold(float threshold)
  268. {
  269. dWorldSetAutoDisableLinearThreshold(mWorld, max(threshold, 0.0f));
  270. }
  271. void PhysicsWorld::setLinearDamping(float threshold, float scale)
  272. {
  273. dWorldSetLinearDampingThreshold(mWorld, max(threshold, 0.0f));
  274. dWorldSetLinearDamping(mWorld, clamp(scale, 0.0f, 1.0f));
  275. }
  276. void PhysicsWorld::setAngularRestThreshold(float threshold)
  277. {
  278. dWorldSetAutoDisableAngularThreshold(mWorld, threshold);
  279. }
  280. void PhysicsWorld::setAngularDamping(float threshold, float scale)
  281. {
  282. dWorldSetAngularDampingThreshold(mWorld, max(threshold, 0.0f));
  283. dWorldSetAngularDamping(mWorld, clamp(scale, 0.0f, 1.0f));
  284. }
  285. void PhysicsWorld::setAngularMaxNetVelocity(float velocity)
  286. {
  287. mAngularMaxNetVelocity = max(velocity, 0.0f);
  288. }
  289. void PhysicsWorld::setBounceThreshold(float threshold)
  290. {
  291. mBounceThreshold = max(threshold, 0.0f);
  292. }
  293. void PhysicsWorld::setERP(float erp)
  294. {
  295. dWorldSetERP(mWorld, erp);
  296. }
  297. void PhysicsWorld::setCFM(float cfm)
  298. {
  299. dWorldSetCFM(mWorld, cfm);
  300. }
  301. void PhysicsWorld::setContactSurfaceLayer(float depth)
  302. {
  303. dWorldSetContactSurfaceLayer(mWorld, depth);
  304. }
  305. void PhysicsWorld::setTimeAccumulator(float time)
  306. {
  307. mTimeAcc = time;
  308. }
  309. void PhysicsWorld::setRandomSeed(unsigned seed)
  310. {
  311. dRandSetSeed(seed);
  312. }
  313. void PhysicsWorld::setDrawDebugGeometry(bool enable)
  314. {
  315. mDrawDebugGeometry = enable;
  316. }
  317. void PhysicsWorld::raycast(std::vector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask)
  318. {
  319. PROFILE(Physics_Raycast);
  320. result.clear();
  321. dGeomRaySetLength(mRayGeometry, maxDistance);
  322. dGeomRaySet(mRayGeometry, ray.mOrigin.mX, ray.mOrigin.mY, ray.mOrigin.mZ, ray.mDirection.mX, ray.mDirection.mY, ray.mDirection.mZ);
  323. dGeomSetCollideBits(mRayGeometry, collisionMask);
  324. dSpaceCollide2(mRayGeometry, (dGeomID)mSpace, &result, raycastCallback);
  325. std::sort(result.begin(), result.end(), compareRaycastResults);
  326. }
  327. unsigned PhysicsWorld::getRandomSeed() const
  328. {
  329. return dRandGetSeed();
  330. }
  331. Vector3 PhysicsWorld::getGravity() const
  332. {
  333. dVector3 g;
  334. dWorldGetGravity(mWorld, g);
  335. return Vector3(g[0], g[1], g[2]);
  336. }
  337. float PhysicsWorld::getLinearRestThreshold() const
  338. {
  339. return dWorldGetAutoDisableLinearThreshold(mWorld);
  340. }
  341. float PhysicsWorld::getLinearDampingThreshold() const
  342. {
  343. return dWorldGetLinearDampingThreshold(mWorld);
  344. }
  345. float PhysicsWorld::getLinearDampingScale() const
  346. {
  347. return dWorldGetLinearDamping(mWorld);
  348. }
  349. float PhysicsWorld::getAngularRestThreshold() const
  350. {
  351. return dWorldGetAutoDisableAngularThreshold(mWorld);
  352. }
  353. float PhysicsWorld::getAngularDampingThreshold() const
  354. {
  355. return dWorldGetAngularDampingThreshold(mWorld);
  356. }
  357. float PhysicsWorld::getAngularDampingScale() const
  358. {
  359. return dWorldGetAngularDamping(mWorld);
  360. }
  361. float PhysicsWorld::getERP() const
  362. {
  363. return dWorldGetERP(mWorld);
  364. }
  365. float PhysicsWorld::getCFM() const
  366. {
  367. return dWorldGetCFM(mWorld);
  368. }
  369. float PhysicsWorld::getContactSurfaceLayer() const
  370. {
  371. return dWorldGetContactSurfaceLayer(mWorld);
  372. }
  373. void PhysicsWorld::addRigidBody(RigidBody* body)
  374. {
  375. mRigidBodies.push_back(body);
  376. }
  377. void PhysicsWorld::removeRigidBody(RigidBody* body)
  378. {
  379. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  380. {
  381. if ((*i) == body)
  382. {
  383. mRigidBodies.erase(i);
  384. return;
  385. }
  386. }
  387. }
  388. void PhysicsWorld::sendCollisionEvents()
  389. {
  390. PROFILE(Physics_SendCollisionEvents);
  391. static VariantMap physicsCollisionData;
  392. static VariantMap entityCollisionData;
  393. static VectorBuffer contacts;
  394. physicsCollisionData[PhysicsCollision::P_WORLD] = (void*)this;
  395. physicsCollisionData[PhysicsCollision::P_SCENE] = (void*)mScene;
  396. for (std::vector<PhysicsCollisionInfo>::const_iterator i = mCollisionInfos.begin(); i != mCollisionInfos.end(); ++i)
  397. {
  398. // Skip event if either of the bodies has been removed
  399. if ((!i->mRigidBodyA) || (!i->mRigidBodyB))
  400. continue;
  401. physicsCollisionData[PhysicsCollision::P_BODYA] = (void*)i->mRigidBodyA;
  402. physicsCollisionData[PhysicsCollision::P_BODYB] = (void*)i->mRigidBodyB;
  403. physicsCollisionData[PhysicsCollision::P_NEWCOLLISION] = i->mNewCollision;
  404. contacts.clear();
  405. for (unsigned j = 0; j < i->mContacts.size(); ++j)
  406. {
  407. contacts.writeVector3(i->mContacts[j].mPosition);
  408. contacts.writeVector3(i->mContacts[j].mNormal);
  409. contacts.writeFloat(i->mContacts[j].mDepth);
  410. contacts.writeFloat(i->mContacts[j].mVelocity);
  411. }
  412. physicsCollisionData[PhysicsCollision::P_CONTACTS] = contacts.getBuffer();
  413. sendEvent(EVENT_PHYSICSCOLLISION, physicsCollisionData);
  414. // Skip if either of the bodies or entities has been removed as a response to the just sent event
  415. if ((!i->mRigidBodyA) || (!i->mRigidBodyB) || (!i->mEntityA) || (!i->mEntityB))
  416. continue;
  417. entityCollisionData[EntityCollision::P_BODY] = (void*)i->mRigidBodyA;
  418. entityCollisionData[EntityCollision::P_OTHERBODY] = (void*)i->mRigidBodyB;
  419. entityCollisionData[EntityCollision::P_OTHERENTITY] = (void*)i->mEntityB;
  420. entityCollisionData[EntityCollision::P_NEWCOLLISION] = i->mNewCollision;
  421. entityCollisionData[EntityCollision::P_CONTACTS] = contacts.getBuffer();
  422. sendEvent(i->mEntityA, EVENT_ENTITYCOLLISION, entityCollisionData);
  423. // Skip if either of the bodies or entities has been removed as a response to the just sent event
  424. if ((!i->mRigidBodyA) || (!i->mRigidBodyB) || (!i->mEntityA) || (!i->mEntityB))
  425. continue;
  426. contacts.clear();
  427. for (unsigned j = 0; j < i->mContacts.size(); ++j)
  428. {
  429. contacts.writeVector3(i->mContacts[j].mPosition);
  430. contacts.writeVector3(-i->mContacts[j].mNormal);
  431. contacts.writeFloat(i->mContacts[j].mDepth);
  432. contacts.writeFloat(i->mContacts[j].mVelocity);
  433. }
  434. entityCollisionData[EntityCollision::P_BODY] = (void*)i->mRigidBodyB;
  435. entityCollisionData[EntityCollision::P_OTHERBODY] = (void*)i->mRigidBodyA;
  436. entityCollisionData[EntityCollision::P_OTHERENTITY] = (void*)i->mEntityA;
  437. entityCollisionData[EntityCollision::P_CONTACTS] = contacts.getBuffer();
  438. sendEvent(i->mEntityB, EVENT_ENTITYCOLLISION, entityCollisionData);
  439. }
  440. mCollisionInfos.clear();
  441. }
  442. void PhysicsWorld::drawDebugGeometry()
  443. {
  444. DebugRenderer* debug = mScene->getExtension<DebugRenderer>();
  445. if (!debug)
  446. return;
  447. PROFILE(Physics_DrawDebugGeometry);
  448. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  449. (*i)->drawDebugGeometry(debug);
  450. }
  451. void PhysicsWorld::nearCallback(void *userData, dGeomID geomA, dGeomID geomB)
  452. {
  453. dBodyID bodyA = dGeomGetBody(geomA);
  454. dBodyID bodyB = dGeomGetBody(geomB);
  455. // If both geometries are static, no collision
  456. if ((!bodyA) && (!bodyB))
  457. return;
  458. // If the geometries belong to the same body, no collision
  459. if (bodyA == bodyB)
  460. return;
  461. // If the bodies are already connected via other joints, no collision
  462. if ((bodyA) && (bodyB) && (dAreConnectedExcluding(bodyA, bodyB, dJointTypeContact)))
  463. return;
  464. RigidBody* rigidBodyA = static_cast<RigidBody*>(dGeomGetData(geomA));
  465. RigidBody* rigidBodyB = static_cast<RigidBody*>(dGeomGetData(geomB));
  466. if ((!rigidBodyA) || (!rigidBodyB))
  467. return;
  468. Entity* entityA = rigidBodyA->getEntity();
  469. Entity* entityB = rigidBodyB->getEntity();
  470. // If both bodies are inactive, no collision (note also that no events will be generated)
  471. if ((!rigidBodyA->isActive()) && (!rigidBodyB->isActive()))
  472. return;
  473. PhysicsWorld* world = static_cast<PhysicsWorld*>(userData);
  474. // Calculate average friction & bounce (physically incorrect)
  475. float friction = (rigidBodyA->getFriction() + rigidBodyB->getFriction()) * 0.5f;
  476. float bounce = (rigidBodyA->getBounce() + rigidBodyB->getBounce()) * 0.5f;
  477. static std::vector<dContact> contacts;
  478. if (contacts.size() < world->mMaxContacts)
  479. contacts.resize(world->mMaxContacts);
  480. for (unsigned i = 0; i < world->mMaxContacts; ++i)
  481. {
  482. contacts[i].surface.mode = dContactApprox1;
  483. contacts[i].surface.mu = friction;
  484. if (bounce > 0.0f)
  485. {
  486. contacts[i].surface.mode |= dContactBounce;
  487. contacts[i].surface.bounce = bounce;
  488. contacts[i].surface.bounce_vel = world->mBounceThreshold;
  489. }
  490. }
  491. unsigned numContacts = dCollide(geomA, geomB, world->mMaxContacts, &contacts[0].geom, sizeof(dContact));
  492. if (!numContacts)
  493. return;
  494. std::pair<RigidBody*, RigidBody*> bodyPair;
  495. if (rigidBodyA < rigidBodyB)
  496. bodyPair = std::make_pair(rigidBodyA, rigidBodyB);
  497. else
  498. bodyPair = std::make_pair(rigidBodyB, rigidBodyA);
  499. static PhysicsCollisionInfo collisionInfo;
  500. collisionInfo.mEntityA = entityA;
  501. collisionInfo.mEntityB = entityB;
  502. collisionInfo.mRigidBodyA = rigidBodyA;
  503. collisionInfo.mRigidBodyB = rigidBodyB;
  504. collisionInfo.mNewCollision = world->mPreviousCollisions.find(bodyPair) == world->mPreviousCollisions.end();
  505. collisionInfo.mContacts.clear();
  506. world->mCurrentCollisions.insert(bodyPair);
  507. for (unsigned i = 0; i < numContacts; ++i)
  508. {
  509. // Calculate isotropic friction direction from relative tangent velocity between bodies
  510. // Adapted from http://www.ode.org/old_list_archives/2005-May/015836.html
  511. dVector3 velA;
  512. if (bodyA)
  513. dBodyGetPointVel(bodyA, contacts[i].geom.pos[0], contacts[i].geom.pos[1], contacts[i].geom.pos[2], velA);
  514. else
  515. velA[0] = velA[1] = velA[2] = 0.0f;
  516. if (bodyB)
  517. {
  518. dVector3 velB;
  519. dBodyGetPointVel(bodyB, contacts[i].geom.pos[0], contacts[i].geom.pos[1], contacts[i].geom.pos[2], velB);
  520. velA[0] -= velB[0];
  521. velA[1] -= velB[1];
  522. velA[2] -= velB[2];
  523. }
  524. // Normalize & only use our calculated friction if it has enough precision
  525. float length = sqrtf(velA[0] * velA[0] + velA[1] * velA[1] + velA[2] * velA[2]);
  526. if (length > M_EPSILON)
  527. {
  528. float invLen = 1.0f / length;
  529. velA[0] *= invLen;
  530. velA[1] *= invLen;
  531. velA[2] *= invLen;
  532. // Make sure friction is also perpendicular to normal
  533. dCROSS(contacts[i].fdir1, =, velA, contacts[i].geom.normal);
  534. contacts[i].surface.mode |= dContactFDir1;
  535. }
  536. // Create contact joint
  537. dJointID contact = dJointCreateContact(world->mWorld, world->mContactJoints, &contacts[i]);
  538. dJointAttach(contact, bodyA, bodyB);
  539. // Store contact info
  540. static PhysicsContactInfo contactInfo;
  541. contactInfo.mPosition = Vector3(contacts[i].geom.pos[0], contacts[i].geom.pos[1], contacts[i].geom.pos[2]);
  542. contactInfo.mNormal = Vector3(contacts[i].geom.normal[0], contacts[i].geom.normal[1], contacts[i].geom.normal[2]);
  543. contactInfo.mDepth = contacts[i].geom.depth;
  544. contactInfo.mVelocity = length;
  545. collisionInfo.mContacts.push_back(contactInfo);
  546. }
  547. // Store collision info to be sent later
  548. world->mCollisionInfos.push_back(collisionInfo);
  549. // Propagate transient prediction based on physics interactions
  550. // Note: during the actual rewind/replay phase this works poorly, because most bodies are disabled and
  551. // no new collisions can be detected. However, the transient prediction timers are also not decremented
  552. // during replay. An alternative would be to use simple bounding box/sphere checks for propagation
  553. if ((entityA) && (entityB) && (entityA->isProxy()) && (entityB->isProxy()))
  554. {
  555. entityA->setPredictionFrom(entityB);
  556. entityB->setPredictionFrom(entityA);
  557. }
  558. }
  559. void PhysicsWorld::raycastCallback(void *userData, dGeomID geomA, dGeomID geomB)
  560. {
  561. RigidBody* rigidBodyA = static_cast<RigidBody*>(dGeomGetData(geomA));
  562. RigidBody* rigidBodyB = static_cast<RigidBody*>(dGeomGetData(geomB));
  563. if ((!rigidBodyA) && (!rigidBodyB))
  564. return;
  565. dContact contact;
  566. unsigned numContacts = dCollide(geomA, geomB, 1, &contact.geom, sizeof(dContact));
  567. if (numContacts > 0)
  568. {
  569. std::vector<PhysicsRaycastResult>* result = static_cast<std::vector<PhysicsRaycastResult>*>(userData);
  570. PhysicsRaycastResult newResult;
  571. if (rigidBodyA)
  572. newResult.mBody = rigidBodyA;
  573. else
  574. newResult.mBody = rigidBodyB;
  575. newResult.mDistance = contact.geom.depth;
  576. newResult.mPosition = Vector3(contact.geom.pos[0], contact.geom.pos[1], contact.geom.pos[2]);
  577. newResult.mNormal = Vector3(contact.geom.normal[0], contact.geom.normal[1], contact.geom.normal[2]);
  578. result->push_back(newResult);
  579. }
  580. }
  581. void PhysicsWorld::handlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
  582. {
  583. if (mDrawDebugGeometry)
  584. drawDebugGeometry();
  585. }