PhysicsWorld.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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 = mCollisions;
  222. mCollisions.clear();
  223. }
  224. // Interpolate transforms of physics objects
  225. float t = clamp(mTimeAcc / internalTimeStep, 0.0f, 1.0f);
  226. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  227. (*i)->postStep(t);
  228. // Send post-step event
  229. sendEvent(EVENT_PHYSICSPOSTSTEP, eventData);
  230. }
  231. }
  232. }
  233. void PhysicsWorld::setPlayback(bool enable)
  234. {
  235. // During scene rewind/replay all non-predicted dynamic & kinematic bodies are temporarily disabled
  236. if (enable)
  237. {
  238. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  239. {
  240. RigidBody* body = *i;
  241. if ((body->getMode() != PHYS_STATIC) && (!body->checkPrediction()))
  242. body->setTempDisabled(true);
  243. }
  244. }
  245. else
  246. {
  247. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  248. {
  249. RigidBody* body = *i;
  250. body->setTempDisabled(false);
  251. }
  252. }
  253. }
  254. void PhysicsWorld::setGravity(const Vector3& gravity)
  255. {
  256. dWorldSetGravity(mWorld, gravity.mX, gravity.mY, gravity.mZ);;
  257. }
  258. void PhysicsWorld::setFps(int fps)
  259. {
  260. mFps = max(fps, 1);
  261. }
  262. void PhysicsWorld::setMaxContacts(unsigned contacts)
  263. {
  264. mMaxContacts = max(contacts, 1);
  265. }
  266. void PhysicsWorld::setLinearRestThreshold(float threshold)
  267. {
  268. dWorldSetAutoDisableLinearThreshold(mWorld, max(threshold, 0.0f));
  269. }
  270. void PhysicsWorld::setLinearDamping(float threshold, float scale)
  271. {
  272. dWorldSetLinearDampingThreshold(mWorld, max(threshold, 0.0f));
  273. dWorldSetLinearDamping(mWorld, clamp(scale, 0.0f, 1.0f));
  274. }
  275. void PhysicsWorld::setAngularRestThreshold(float threshold)
  276. {
  277. dWorldSetAutoDisableAngularThreshold(mWorld, threshold);
  278. }
  279. void PhysicsWorld::setAngularDamping(float threshold, float scale)
  280. {
  281. dWorldSetAngularDampingThreshold(mWorld, max(threshold, 0.0f));
  282. dWorldSetAngularDamping(mWorld, clamp(scale, 0.0f, 1.0f));
  283. }
  284. void PhysicsWorld::setAngularMaxNetVelocity(float velocity)
  285. {
  286. mAngularMaxNetVelocity = max(velocity, 0.0f);
  287. }
  288. void PhysicsWorld::setBounceThreshold(float threshold)
  289. {
  290. mBounceThreshold = max(threshold, 0.0f);
  291. }
  292. void PhysicsWorld::setERP(float erp)
  293. {
  294. dWorldSetERP(mWorld, erp);
  295. }
  296. void PhysicsWorld::setCFM(float cfm)
  297. {
  298. dWorldSetCFM(mWorld, cfm);
  299. }
  300. void PhysicsWorld::setContactSurfaceLayer(float depth)
  301. {
  302. dWorldSetContactSurfaceLayer(mWorld, depth);
  303. }
  304. void PhysicsWorld::setTimeAccumulator(float time)
  305. {
  306. mTimeAcc = time;
  307. }
  308. void PhysicsWorld::setRandomSeed(unsigned seed)
  309. {
  310. dRandSetSeed(seed);
  311. }
  312. void PhysicsWorld::raycast(const Ray& ray, std::vector<PhysicsRaycastResult>& result, float maxDistance, unsigned collisionMask)
  313. {
  314. PROFILE(Physics_Raycast);
  315. result.clear();
  316. dGeomRaySetLength(mRayGeometry, maxDistance);
  317. dGeomRaySet(mRayGeometry, ray.mOrigin.mX, ray.mOrigin.mY, ray.mOrigin.mZ, ray.mDirection.mX, ray.mDirection.mY, ray.mDirection.mZ);
  318. dGeomSetCollideBits(mRayGeometry, collisionMask);
  319. dSpaceCollide2(mRayGeometry, (dGeomID)mSpace, &result, raycastCallback);
  320. std::sort(result.begin(), result.end(), compareRaycastResults);
  321. }
  322. unsigned PhysicsWorld::getRandomSeed() const
  323. {
  324. return dRandGetSeed();
  325. }
  326. Vector3 PhysicsWorld::getGravity() const
  327. {
  328. dVector3 g;
  329. dWorldGetGravity(mWorld, g);
  330. return Vector3(g[0], g[1], g[2]);
  331. }
  332. float PhysicsWorld::getLinearRestThreshold() const
  333. {
  334. return dWorldGetAutoDisableLinearThreshold(mWorld);
  335. }
  336. float PhysicsWorld::getLinearDampingThreshold() const
  337. {
  338. return dWorldGetLinearDampingThreshold(mWorld);
  339. }
  340. float PhysicsWorld::getLinearDampingScale() const
  341. {
  342. return dWorldGetLinearDamping(mWorld);
  343. }
  344. float PhysicsWorld::getAngularRestThreshold() const
  345. {
  346. return dWorldGetAutoDisableAngularThreshold(mWorld);
  347. }
  348. float PhysicsWorld::getAngularDampingThreshold() const
  349. {
  350. return dWorldGetAngularDampingThreshold(mWorld);
  351. }
  352. float PhysicsWorld::getAngularDampingScale() const
  353. {
  354. return dWorldGetAngularDamping(mWorld);
  355. }
  356. float PhysicsWorld::getERP() const
  357. {
  358. return dWorldGetERP(mWorld);
  359. }
  360. float PhysicsWorld::getCFM() const
  361. {
  362. return dWorldGetCFM(mWorld);
  363. }
  364. float PhysicsWorld::getContactSurfaceLayer() const
  365. {
  366. return dWorldGetContactSurfaceLayer(mWorld);
  367. }
  368. void PhysicsWorld::drawDebugGeometry(DebugRenderer* debug)
  369. {
  370. PROFILE(Physics_DrawDebugGeometry);
  371. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  372. (*i)->drawDebugGeometry(debug);
  373. }
  374. void PhysicsWorld::addRigidBody(RigidBody* body)
  375. {
  376. mRigidBodies.push_back(body);
  377. }
  378. void PhysicsWorld::removeRigidBody(RigidBody* body)
  379. {
  380. for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
  381. {
  382. if ((*i) == body)
  383. {
  384. mRigidBodies.erase(i);
  385. return;
  386. }
  387. }
  388. }
  389. void PhysicsWorld::nearCallback(void *userData, dGeomID geomA, dGeomID geomB)
  390. {
  391. dBodyID bodyA = dGeomGetBody(geomA);
  392. dBodyID bodyB = dGeomGetBody(geomB);
  393. // If both geometries are static, no collision
  394. if ((!bodyA) && (!bodyB))
  395. return;
  396. // If the geometries belong to the same body, no collision
  397. if (bodyA == bodyB)
  398. return;
  399. // If the bodies are already connected via other joints, no collision
  400. if ((bodyA) && (bodyB) && (dAreConnectedExcluding(bodyA, bodyB, dJointTypeContact)))
  401. return;
  402. RigidBody* rigidBodyA = static_cast<RigidBody*>(dGeomGetData(geomA));
  403. RigidBody* rigidBodyB = static_cast<RigidBody*>(dGeomGetData(geomB));
  404. if ((!rigidBodyA) || (!rigidBodyB))
  405. return;
  406. Entity* entityA = rigidBodyA->getEntity();
  407. Entity* entityB = rigidBodyB->getEntity();
  408. // If both bodies are inactive, no collision (note also that no events will be generated)
  409. if ((!rigidBodyA->isActive()) && (!rigidBodyB->isActive()))
  410. return;
  411. PhysicsWorld* world = static_cast<PhysicsWorld*>(userData);
  412. // Calculate average friction & bounce (physically incorrect)
  413. float friction = (rigidBodyA->getFriction() + rigidBodyB->getFriction()) * 0.5f;
  414. float bounce = (rigidBodyA->getBounce() + rigidBodyB->getBounce()) * 0.5f;
  415. static std::vector<dContact> contacts;
  416. if (contacts.size() < world->mMaxContacts)
  417. contacts.resize(world->mMaxContacts);
  418. for (unsigned i = 0; i < world->mMaxContacts; ++i)
  419. {
  420. contacts[i].surface.mode = dContactApprox1;
  421. contacts[i].surface.mu = friction;
  422. if (bounce > 0.0f)
  423. {
  424. contacts[i].surface.mode |= dContactBounce;
  425. contacts[i].surface.bounce = bounce;
  426. contacts[i].surface.bounce_vel = world->mBounceThreshold;
  427. }
  428. }
  429. unsigned numContacts = dCollide(geomA, geomB, world->mMaxContacts, &contacts[0].geom, sizeof(dContact));
  430. if (!numContacts)
  431. return;
  432. std::pair<RigidBody*, RigidBody*> bodyPair;
  433. if (rigidBodyA < rigidBodyB)
  434. bodyPair = std::make_pair(rigidBodyA, rigidBodyB);
  435. else
  436. bodyPair = std::make_pair(rigidBodyB, rigidBodyA);
  437. static VariantMap collisionData;
  438. static VariantMap entityCollisionData;
  439. static VectorBuffer contactsA;
  440. static VectorBuffer contactsB;
  441. collisionData[PhysicsCollision::P_WORLD] = (void*)world;
  442. collisionData[PhysicsCollision::P_SCENE] = (void*)world->mScene;
  443. collisionData[PhysicsCollision::P_BODYA] = (void*)rigidBodyA;
  444. collisionData[PhysicsCollision::P_BODYB] = (void*)rigidBodyB;
  445. // Check if the same pair already collided on the last step
  446. entityCollisionData[EntityCollision::P_NEWCOLLISION] = collisionData[PhysicsCollision::P_NEWCOLLISION] =
  447. world->mPreviousCollisions.find(bodyPair) == world->mPreviousCollisions.end();
  448. world->mCollisions.insert(bodyPair);
  449. contactsA.clear();
  450. contactsB.clear();
  451. for (unsigned i = 0; i < numContacts; ++i)
  452. {
  453. // Calculate isotropic friction direction from relative tangent velocity between bodies
  454. // Adapted from http://www.ode.org/old_list_archives/2005-May/015836.html
  455. dVector3 velA;
  456. if (bodyA)
  457. dBodyGetPointVel(bodyA, contacts[i].geom.pos[0], contacts[i].geom.pos[1], contacts[i].geom.pos[2], velA);
  458. else
  459. velA[0] = velA[1] = velA[2] = 0.0f;
  460. if (bodyB)
  461. {
  462. dVector3 velB;
  463. dBodyGetPointVel(bodyB, contacts[i].geom.pos[0], contacts[i].geom.pos[1], contacts[i].geom.pos[2], velB);
  464. velA[0] -= velB[0];
  465. velA[1] -= velB[1];
  466. velA[2] -= velB[2];
  467. }
  468. // Normalize & only use our calculated friction if it has enough precision
  469. float length = sqrtf(velA[0] * velA[0] + velA[1] * velA[1] + velA[2] * velA[2]);
  470. if (length > M_EPSILON)
  471. {
  472. float invLen = 1.0f / length;
  473. velA[0] *= invLen;
  474. velA[1] *= invLen;
  475. velA[2] *= invLen;
  476. // Make sure friction is also perpendicular to normal
  477. dCROSS(contacts[i].fdir1, =, velA, contacts[i].geom.normal);
  478. contacts[i].surface.mode |= dContactFDir1;
  479. }
  480. // Create contact joint
  481. dJointID contact = dJointCreateContact(world->mWorld, world->mContactJoints, &contacts[i]);
  482. dJointAttach(contact, bodyA, bodyB);
  483. // Write contact data to the contact buffers: position, normal, depth, velocity
  484. Vector3 position(contacts[i].geom.pos[0], contacts[i].geom.pos[1], contacts[i].geom.pos[2]);
  485. Vector3 normal(contacts[i].geom.normal[0], contacts[i].geom.normal[1], contacts[i].geom.normal[2]);
  486. contactsA.writeVector3(position);
  487. contactsA.writeVector3(normal);
  488. contactsA.writeFloat(contacts[i].geom.depth);
  489. contactsA.writeFloat(length);
  490. if (entityB)
  491. {
  492. contactsB.writeVector3(position);
  493. contactsB.writeVector3(-normal);
  494. contactsB.writeFloat(contacts[i].geom.depth);
  495. contactsB.writeFloat(length);
  496. }
  497. }
  498. // Send collision events
  499. collisionData[PhysicsCollision::P_CONTACTS] = contactsA.getBuffer();
  500. world->sendEvent(EVENT_PHYSICSCOLLISION, collisionData);
  501. if (entityA)
  502. {
  503. entityCollisionData[EntityCollision::P_BODY] = (void*)rigidBodyA;
  504. entityCollisionData[EntityCollision::P_OTHERBODY] = (void*)rigidBodyB;
  505. entityCollisionData[EntityCollision::P_OTHERENTITY] = (void*)entityB;
  506. entityCollisionData[EntityCollision::P_CONTACTS] = contactsA.getBuffer();
  507. world->sendEvent(entityA, EVENT_ENTITYCOLLISION, entityCollisionData);
  508. }
  509. if (entityB)
  510. {
  511. entityCollisionData[EntityCollision::P_BODY] = (void*)rigidBodyB;
  512. entityCollisionData[EntityCollision::P_OTHERBODY] = (void*)rigidBodyA;
  513. entityCollisionData[EntityCollision::P_OTHERENTITY] = (void*)entityA;
  514. entityCollisionData[EntityCollision::P_CONTACTS] = contactsB.getBuffer();
  515. world->sendEvent(entityB, EVENT_ENTITYCOLLISION, entityCollisionData);
  516. }
  517. // Propagate transient prediction based on physics interactions
  518. // Note: during the actual rewind/replay phase this works poorly, because most bodies are disabled and
  519. // no new collisions can be detected. However, the transient prediction timers are also not decremented
  520. // during replay. An alternative would be to use simple bounding box/sphere checks for propagation
  521. if ((entityA) && (entityB) && (entityA->isProxy()) && (entityB->isProxy()))
  522. {
  523. entityA->setPredictionFrom(entityB);
  524. entityB->setPredictionFrom(entityA);
  525. }
  526. }
  527. void PhysicsWorld::raycastCallback(void *userData, dGeomID geomA, dGeomID geomB)
  528. {
  529. RigidBody* rigidBodyA = static_cast<RigidBody*>(dGeomGetData(geomA));
  530. RigidBody* rigidBodyB = static_cast<RigidBody*>(dGeomGetData(geomB));
  531. if ((!rigidBodyA) && (!rigidBodyB))
  532. return;
  533. dContact contact;
  534. unsigned numContacts = dCollide(geomA, geomB, 1, &contact.geom, sizeof(dContact));
  535. if (numContacts > 0)
  536. {
  537. std::vector<PhysicsRaycastResult>* result = static_cast<std::vector<PhysicsRaycastResult>*>(userData);
  538. PhysicsRaycastResult newResult;
  539. if (rigidBodyA)
  540. newResult.mBody = rigidBodyA;
  541. else
  542. newResult.mBody = rigidBodyB;
  543. newResult.mDistance = contact.geom.depth;
  544. newResult.mPosition = Vector3(contact.geom.pos[0], contact.geom.pos[1], contact.geom.pos[2]);
  545. newResult.mNormal = Vector3(contact.geom.normal[0], contact.geom.normal[1], contact.geom.normal[2]);
  546. result->push_back(newResult);
  547. }
  548. }