PhysicsWorld.cpp 23 KB

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