btRaycastVehicle.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*
  2. * Copyright (c) 2005 Erwin Coumans https://bulletphysics.org
  3. *
  4. * Permission to use, copy, modify, distribute and sell this software
  5. * and its documentation for any purpose is hereby granted without fee,
  6. * provided that the above copyright notice appear in all copies.
  7. * Erwin Coumans makes no representations about the suitability
  8. * of this software for any purpose.
  9. * It is provided "as is" without express or implied warranty.
  10. */
  11. #include "LinearMath/btVector3.h"
  12. #include "btRaycastVehicle.h"
  13. #include "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h"
  14. #include "BulletDynamics/ConstraintSolver/btJacobianEntry.h"
  15. #include "LinearMath/btQuaternion.h"
  16. #include "BulletDynamics/Dynamics/btDynamicsWorld.h"
  17. #include "btVehicleRaycaster.h"
  18. #include "btWheelInfo.h"
  19. #include "LinearMath/btMinMax.h"
  20. #include "LinearMath/btIDebugDraw.h"
  21. #include "BulletDynamics/ConstraintSolver/btContactConstraint.h"
  22. #define ROLLING_INFLUENCE_FIX
  23. btRigidBody& btActionInterface::getFixedBody()
  24. {
  25. static btRigidBody s_fixed(0, 0, 0);
  26. s_fixed.setMassProps(btScalar(0.), btVector3(btScalar(0.), btScalar(0.), btScalar(0.)));
  27. return s_fixed;
  28. }
  29. btRaycastVehicle::btRaycastVehicle(const btVehicleTuning& tuning, btRigidBody* chassis, btVehicleRaycaster* raycaster)
  30. : m_vehicleRaycaster(raycaster),
  31. m_pitchControl(btScalar(0.))
  32. {
  33. m_chassisBody = chassis;
  34. m_indexRightAxis = 0;
  35. m_indexUpAxis = 2;
  36. m_indexForwardAxis = 1;
  37. defaultInit(tuning);
  38. }
  39. void btRaycastVehicle::defaultInit(const btVehicleTuning& tuning)
  40. {
  41. (void)tuning;
  42. m_currentVehicleSpeedKmHour = btScalar(0.);
  43. m_steeringValue = btScalar(0.);
  44. }
  45. btRaycastVehicle::~btRaycastVehicle()
  46. {
  47. }
  48. //
  49. // basically most of the code is general for 2 or 4 wheel vehicles, but some of it needs to be reviewed
  50. //
  51. btWheelInfo& btRaycastVehicle::addWheel(const btVector3& connectionPointCS, const btVector3& wheelDirectionCS0, const btVector3& wheelAxleCS, btScalar suspensionRestLength, btScalar wheelRadius, const btVehicleTuning& tuning, bool isFrontWheel)
  52. {
  53. btWheelInfoConstructionInfo ci;
  54. ci.m_chassisConnectionCS = connectionPointCS;
  55. ci.m_wheelDirectionCS = wheelDirectionCS0;
  56. ci.m_wheelAxleCS = wheelAxleCS;
  57. ci.m_suspensionRestLength = suspensionRestLength;
  58. ci.m_wheelRadius = wheelRadius;
  59. ci.m_suspensionStiffness = tuning.m_suspensionStiffness;
  60. ci.m_wheelsDampingCompression = tuning.m_suspensionCompression;
  61. ci.m_wheelsDampingRelaxation = tuning.m_suspensionDamping;
  62. ci.m_frictionSlip = tuning.m_frictionSlip;
  63. ci.m_bIsFrontWheel = isFrontWheel;
  64. ci.m_maxSuspensionTravelCm = tuning.m_maxSuspensionTravelCm;
  65. ci.m_maxSuspensionForce = tuning.m_maxSuspensionForce;
  66. m_wheelInfo.push_back(btWheelInfo(ci));
  67. btWheelInfo& wheel = m_wheelInfo[getNumWheels() - 1];
  68. updateWheelTransformsWS(wheel, false);
  69. updateWheelTransform(getNumWheels() - 1, false);
  70. return wheel;
  71. }
  72. const btTransform& btRaycastVehicle::getWheelTransformWS(int wheelIndex) const
  73. {
  74. btAssert(wheelIndex < getNumWheels());
  75. const btWheelInfo& wheel = m_wheelInfo[wheelIndex];
  76. return wheel.m_worldTransform;
  77. }
  78. void btRaycastVehicle::updateWheelTransform(int wheelIndex, bool interpolatedTransform)
  79. {
  80. btWheelInfo& wheel = m_wheelInfo[wheelIndex];
  81. updateWheelTransformsWS(wheel, interpolatedTransform);
  82. btVector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
  83. const btVector3& right = wheel.m_raycastInfo.m_wheelAxleWS;
  84. btVector3 fwd = up.cross(right);
  85. fwd = fwd.normalize();
  86. // up = right.cross(fwd);
  87. // up.normalize();
  88. //rotate around steering over de wheelAxleWS
  89. btScalar steering = wheel.m_steering;
  90. btQuaternion steeringOrn(up, steering); //wheel.m_steering);
  91. btMatrix3x3 steeringMat(steeringOrn);
  92. btQuaternion rotatingOrn(right, -wheel.m_rotation);
  93. btMatrix3x3 rotatingMat(rotatingOrn);
  94. btMatrix3x3 basis2;
  95. basis2[0][m_indexRightAxis] = -right[0];
  96. basis2[1][m_indexRightAxis] = -right[1];
  97. basis2[2][m_indexRightAxis] = -right[2];
  98. basis2[0][m_indexUpAxis] = up[0];
  99. basis2[1][m_indexUpAxis] = up[1];
  100. basis2[2][m_indexUpAxis] = up[2];
  101. basis2[0][m_indexForwardAxis] = fwd[0];
  102. basis2[1][m_indexForwardAxis] = fwd[1];
  103. basis2[2][m_indexForwardAxis] = fwd[2];
  104. wheel.m_worldTransform.setBasis(steeringMat * rotatingMat * basis2);
  105. wheel.m_worldTransform.setOrigin(
  106. wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength);
  107. }
  108. void btRaycastVehicle::resetSuspension()
  109. {
  110. int i;
  111. for (i = 0; i < m_wheelInfo.size(); i++)
  112. {
  113. btWheelInfo& wheel = m_wheelInfo[i];
  114. wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength();
  115. wheel.m_suspensionRelativeVelocity = btScalar(0.0);
  116. wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
  117. //wheel_info.setContactFriction(btScalar(0.0));
  118. wheel.m_clippedInvContactDotSuspension = btScalar(1.0);
  119. }
  120. }
  121. void btRaycastVehicle::updateWheelTransformsWS(btWheelInfo& wheel, bool interpolatedTransform)
  122. {
  123. wheel.m_raycastInfo.m_isInContact = false;
  124. btTransform chassisTrans = getChassisWorldTransform();
  125. if (interpolatedTransform && (getRigidBody()->getMotionState()))
  126. {
  127. getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
  128. }
  129. wheel.m_raycastInfo.m_hardPointWS = chassisTrans(wheel.m_chassisConnectionPointCS);
  130. wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.getBasis() * wheel.m_wheelDirectionCS;
  131. wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.getBasis() * wheel.m_wheelAxleCS;
  132. }
  133. btScalar btRaycastVehicle::rayCast(btWheelInfo& wheel)
  134. {
  135. updateWheelTransformsWS(wheel, false);
  136. btScalar depth = -1;
  137. btScalar raylen = wheel.getSuspensionRestLength() + wheel.m_wheelsRadius;
  138. btVector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
  139. const btVector3& source = wheel.m_raycastInfo.m_hardPointWS;
  140. wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
  141. const btVector3& target = wheel.m_raycastInfo.m_contactPointWS;
  142. btScalar param = btScalar(0.);
  143. btVehicleRaycaster::btVehicleRaycasterResult rayResults;
  144. btAssert(m_vehicleRaycaster);
  145. void* object = m_vehicleRaycaster->castRay(source, target, rayResults);
  146. wheel.m_raycastInfo.m_groundObject = 0;
  147. if (object)
  148. {
  149. param = rayResults.m_distFraction;
  150. depth = raylen * rayResults.m_distFraction;
  151. wheel.m_raycastInfo.m_contactNormalWS = rayResults.m_hitNormalInWorld;
  152. wheel.m_raycastInfo.m_isInContact = true;
  153. wheel.m_raycastInfo.m_groundObject = &getFixedBody(); ///@todo for driving on dynamic/movable objects!;
  154. //wheel.m_raycastInfo.m_groundObject = object;
  155. btScalar hitDistance = param * raylen;
  156. wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelsRadius;
  157. //clamp on max suspension travel
  158. btScalar minSuspensionLength = wheel.getSuspensionRestLength() - wheel.m_maxSuspensionTravelCm * btScalar(0.01);
  159. btScalar maxSuspensionLength = wheel.getSuspensionRestLength() + wheel.m_maxSuspensionTravelCm * btScalar(0.01);
  160. if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength)
  161. {
  162. wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
  163. }
  164. if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength)
  165. {
  166. wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
  167. }
  168. wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld;
  169. btScalar denominator = wheel.m_raycastInfo.m_contactNormalWS.dot(wheel.m_raycastInfo.m_wheelDirectionWS);
  170. btVector3 chassis_velocity_at_contactPoint;
  171. btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition();
  172. chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
  173. btScalar projVel = wheel.m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
  174. if (denominator >= btScalar(-0.1))
  175. {
  176. wheel.m_suspensionRelativeVelocity = btScalar(0.0);
  177. wheel.m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1);
  178. }
  179. else
  180. {
  181. btScalar inv = btScalar(-1.) / denominator;
  182. wheel.m_suspensionRelativeVelocity = projVel * inv;
  183. wheel.m_clippedInvContactDotSuspension = inv;
  184. }
  185. }
  186. else
  187. {
  188. //put wheel info as in rest position
  189. wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength();
  190. wheel.m_suspensionRelativeVelocity = btScalar(0.0);
  191. wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
  192. wheel.m_clippedInvContactDotSuspension = btScalar(1.0);
  193. }
  194. return depth;
  195. }
  196. const btTransform& btRaycastVehicle::getChassisWorldTransform() const
  197. {
  198. /*if (getRigidBody()->getMotionState())
  199. {
  200. btTransform chassisWorldTrans;
  201. getRigidBody()->getMotionState()->getWorldTransform(chassisWorldTrans);
  202. return chassisWorldTrans;
  203. }
  204. */
  205. return getRigidBody()->getCenterOfMassTransform();
  206. }
  207. void btRaycastVehicle::updateVehicle(btScalar step)
  208. {
  209. {
  210. for (int i = 0; i < getNumWheels(); i++)
  211. {
  212. updateWheelTransform(i, false);
  213. }
  214. }
  215. m_currentVehicleSpeedKmHour = btScalar(3.6) * getRigidBody()->getLinearVelocity().length();
  216. const btTransform& chassisTrans = getChassisWorldTransform();
  217. btVector3 forwardW(
  218. chassisTrans.getBasis()[0][m_indexForwardAxis],
  219. chassisTrans.getBasis()[1][m_indexForwardAxis],
  220. chassisTrans.getBasis()[2][m_indexForwardAxis]);
  221. if (forwardW.dot(getRigidBody()->getLinearVelocity()) < btScalar(0.))
  222. {
  223. m_currentVehicleSpeedKmHour *= btScalar(-1.);
  224. }
  225. //
  226. // simulate suspension
  227. //
  228. int i = 0;
  229. for (i = 0; i < m_wheelInfo.size(); i++)
  230. {
  231. //btScalar depth;
  232. //depth =
  233. rayCast(m_wheelInfo[i]);
  234. }
  235. updateSuspension(step);
  236. for (i = 0; i < m_wheelInfo.size(); i++)
  237. {
  238. //apply suspension force
  239. btWheelInfo& wheel = m_wheelInfo[i];
  240. btScalar suspensionForce = wheel.m_wheelsSuspensionForce;
  241. if (suspensionForce > wheel.m_maxSuspensionForce)
  242. {
  243. suspensionForce = wheel.m_maxSuspensionForce;
  244. }
  245. btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
  246. btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition();
  247. getRigidBody()->applyImpulse(impulse, relpos);
  248. }
  249. updateFriction(step);
  250. for (i = 0; i < m_wheelInfo.size(); i++)
  251. {
  252. btWheelInfo& wheel = m_wheelInfo[i];
  253. btVector3 relpos = wheel.m_raycastInfo.m_hardPointWS - getRigidBody()->getCenterOfMassPosition();
  254. btVector3 vel = getRigidBody()->getVelocityInLocalPoint(relpos);
  255. if (wheel.m_raycastInfo.m_isInContact)
  256. {
  257. const btTransform& chassisWorldTransform = getChassisWorldTransform();
  258. btVector3 fwd(
  259. chassisWorldTransform.getBasis()[0][m_indexForwardAxis],
  260. chassisWorldTransform.getBasis()[1][m_indexForwardAxis],
  261. chassisWorldTransform.getBasis()[2][m_indexForwardAxis]);
  262. btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
  263. fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
  264. btScalar proj2 = fwd.dot(vel);
  265. wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius);
  266. wheel.m_rotation += wheel.m_deltaRotation;
  267. }
  268. else
  269. {
  270. wheel.m_rotation += wheel.m_deltaRotation;
  271. }
  272. wheel.m_deltaRotation *= btScalar(0.99); //damping of rotation when not in contact
  273. }
  274. }
  275. void btRaycastVehicle::setSteeringValue(btScalar steering, int wheel)
  276. {
  277. btAssert(wheel >= 0 && wheel < getNumWheels());
  278. btWheelInfo& wheelInfo = getWheelInfo(wheel);
  279. wheelInfo.m_steering = steering;
  280. }
  281. btScalar btRaycastVehicle::getSteeringValue(int wheel) const
  282. {
  283. return getWheelInfo(wheel).m_steering;
  284. }
  285. void btRaycastVehicle::applyEngineForce(btScalar force, int wheel)
  286. {
  287. btAssert(wheel >= 0 && wheel < getNumWheels());
  288. btWheelInfo& wheelInfo = getWheelInfo(wheel);
  289. wheelInfo.m_engineForce = force;
  290. }
  291. const btWheelInfo& btRaycastVehicle::getWheelInfo(int index) const
  292. {
  293. btAssert((index >= 0) && (index < getNumWheels()));
  294. return m_wheelInfo[index];
  295. }
  296. btWheelInfo& btRaycastVehicle::getWheelInfo(int index)
  297. {
  298. btAssert((index >= 0) && (index < getNumWheels()));
  299. return m_wheelInfo[index];
  300. }
  301. void btRaycastVehicle::setBrake(btScalar brake, int wheelIndex)
  302. {
  303. btAssert((wheelIndex >= 0) && (wheelIndex < getNumWheels()));
  304. getWheelInfo(wheelIndex).m_brake = brake;
  305. }
  306. void btRaycastVehicle::updateSuspension(btScalar deltaTime)
  307. {
  308. (void)deltaTime;
  309. btScalar chassisMass = btScalar(1.) / m_chassisBody->getInvMass();
  310. for (int w_it = 0; w_it < getNumWheels(); w_it++)
  311. {
  312. btWheelInfo& wheel_info = m_wheelInfo[w_it];
  313. if (wheel_info.m_raycastInfo.m_isInContact)
  314. {
  315. btScalar force;
  316. // Spring
  317. {
  318. btScalar susp_length = wheel_info.getSuspensionRestLength();
  319. btScalar current_length = wheel_info.m_raycastInfo.m_suspensionLength;
  320. btScalar length_diff = (susp_length - current_length);
  321. force = wheel_info.m_suspensionStiffness * length_diff * wheel_info.m_clippedInvContactDotSuspension;
  322. }
  323. // Damper
  324. {
  325. btScalar projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
  326. {
  327. btScalar susp_damping;
  328. if (projected_rel_vel < btScalar(0.0))
  329. {
  330. susp_damping = wheel_info.m_wheelsDampingCompression;
  331. }
  332. else
  333. {
  334. susp_damping = wheel_info.m_wheelsDampingRelaxation;
  335. }
  336. force -= susp_damping * projected_rel_vel;
  337. }
  338. }
  339. // RESULT
  340. wheel_info.m_wheelsSuspensionForce = force * chassisMass;
  341. if (wheel_info.m_wheelsSuspensionForce < btScalar(0.))
  342. {
  343. wheel_info.m_wheelsSuspensionForce = btScalar(0.);
  344. }
  345. }
  346. else
  347. {
  348. wheel_info.m_wheelsSuspensionForce = btScalar(0.0);
  349. }
  350. }
  351. }
  352. struct btWheelContactPoint
  353. {
  354. btRigidBody* m_body0;
  355. btRigidBody* m_body1;
  356. btVector3 m_frictionPositionWorld;
  357. btVector3 m_frictionDirectionWorld;
  358. btScalar m_jacDiagABInv;
  359. btScalar m_maxImpulse;
  360. btWheelContactPoint(btRigidBody* body0, btRigidBody* body1, const btVector3& frictionPosWorld, const btVector3& frictionDirectionWorld, btScalar maxImpulse)
  361. : m_body0(body0),
  362. m_body1(body1),
  363. m_frictionPositionWorld(frictionPosWorld),
  364. m_frictionDirectionWorld(frictionDirectionWorld),
  365. m_maxImpulse(maxImpulse)
  366. {
  367. btScalar denom0 = body0->computeImpulseDenominator(frictionPosWorld, frictionDirectionWorld);
  368. btScalar denom1 = body1->computeImpulseDenominator(frictionPosWorld, frictionDirectionWorld);
  369. btScalar relaxation = 1.f;
  370. m_jacDiagABInv = relaxation / (denom0 + denom1);
  371. }
  372. };
  373. btScalar calcRollingFriction(btWheelContactPoint& contactPoint, int numWheelsOnGround);
  374. btScalar calcRollingFriction(btWheelContactPoint& contactPoint, int numWheelsOnGround)
  375. {
  376. btScalar j1 = 0.f;
  377. const btVector3& contactPosWorld = contactPoint.m_frictionPositionWorld;
  378. btVector3 rel_pos1 = contactPosWorld - contactPoint.m_body0->getCenterOfMassPosition();
  379. btVector3 rel_pos2 = contactPosWorld - contactPoint.m_body1->getCenterOfMassPosition();
  380. btScalar maxImpulse = contactPoint.m_maxImpulse;
  381. btVector3 vel1 = contactPoint.m_body0->getVelocityInLocalPoint(rel_pos1);
  382. btVector3 vel2 = contactPoint.m_body1->getVelocityInLocalPoint(rel_pos2);
  383. btVector3 vel = vel1 - vel2;
  384. btScalar vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
  385. // calculate j that moves us to zero relative velocity
  386. j1 = -vrel * contactPoint.m_jacDiagABInv / btScalar(numWheelsOnGround);
  387. btSetMin(j1, maxImpulse);
  388. btSetMax(j1, -maxImpulse);
  389. return j1;
  390. }
  391. btScalar sideFrictionStiffness2 = btScalar(1.0);
  392. void btRaycastVehicle::updateFriction(btScalar timeStep)
  393. {
  394. //calculate the impulse, so that the wheels don't move sidewards
  395. int numWheel = getNumWheels();
  396. if (!numWheel)
  397. return;
  398. m_forwardWS.resize(numWheel);
  399. m_axle.resize(numWheel);
  400. m_forwardImpulse.resize(numWheel);
  401. m_sideImpulse.resize(numWheel);
  402. int numWheelsOnGround = 0;
  403. //collapse all those loops into one!
  404. for (int i = 0; i < getNumWheels(); i++)
  405. {
  406. btWheelInfo& wheelInfo = m_wheelInfo[i];
  407. class btRigidBody* groundObject = (class btRigidBody*)wheelInfo.m_raycastInfo.m_groundObject;
  408. if (groundObject)
  409. numWheelsOnGround++;
  410. m_sideImpulse[i] = btScalar(0.);
  411. m_forwardImpulse[i] = btScalar(0.);
  412. }
  413. {
  414. for (int i = 0; i < getNumWheels(); i++)
  415. {
  416. btWheelInfo& wheelInfo = m_wheelInfo[i];
  417. class btRigidBody* groundObject = (class btRigidBody*)wheelInfo.m_raycastInfo.m_groundObject;
  418. if (groundObject)
  419. {
  420. const btTransform& wheelTrans = getWheelTransformWS(i);
  421. btMatrix3x3 wheelBasis0 = wheelTrans.getBasis();
  422. m_axle[i] = -btVector3(
  423. wheelBasis0[0][m_indexRightAxis],
  424. wheelBasis0[1][m_indexRightAxis],
  425. wheelBasis0[2][m_indexRightAxis]);
  426. const btVector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
  427. btScalar proj = m_axle[i].dot(surfNormalWS);
  428. m_axle[i] -= surfNormalWS * proj;
  429. m_axle[i] = m_axle[i].normalize();
  430. m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
  431. m_forwardWS[i].normalize();
  432. resolveSingleBilateral(*m_chassisBody, wheelInfo.m_raycastInfo.m_contactPointWS,
  433. *groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
  434. btScalar(0.), m_axle[i], m_sideImpulse[i], timeStep);
  435. m_sideImpulse[i] *= sideFrictionStiffness2;
  436. }
  437. }
  438. }
  439. btScalar sideFactor = btScalar(1.);
  440. btScalar fwdFactor = 0.5;
  441. bool sliding = false;
  442. {
  443. for (int wheel = 0; wheel < getNumWheels(); wheel++)
  444. {
  445. btWheelInfo& wheelInfo = m_wheelInfo[wheel];
  446. class btRigidBody* groundObject = (class btRigidBody*)wheelInfo.m_raycastInfo.m_groundObject;
  447. btScalar rollingFriction = 0.f;
  448. if (groundObject)
  449. {
  450. if (wheelInfo.m_engineForce != 0.f)
  451. {
  452. rollingFriction = wheelInfo.m_engineForce * timeStep;
  453. }
  454. else
  455. {
  456. btScalar defaultRollingFrictionImpulse = 0.f;
  457. btScalar maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
  458. btWheelContactPoint contactPt(m_chassisBody, groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel], maxImpulse);
  459. btAssert(numWheelsOnGround > 0);
  460. rollingFriction = calcRollingFriction(contactPt, numWheelsOnGround);
  461. }
  462. }
  463. //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
  464. m_forwardImpulse[wheel] = btScalar(0.);
  465. m_wheelInfo[wheel].m_skidInfo = btScalar(1.);
  466. if (groundObject)
  467. {
  468. m_wheelInfo[wheel].m_skidInfo = btScalar(1.);
  469. btScalar maximp = wheelInfo.m_wheelsSuspensionForce * timeStep * wheelInfo.m_frictionSlip;
  470. btScalar maximpSide = maximp;
  471. btScalar maximpSquared = maximp * maximpSide;
  472. m_forwardImpulse[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
  473. btScalar x = (m_forwardImpulse[wheel]) * fwdFactor;
  474. btScalar y = (m_sideImpulse[wheel]) * sideFactor;
  475. btScalar impulseSquared = (x * x + y * y);
  476. if (impulseSquared > maximpSquared)
  477. {
  478. sliding = true;
  479. btScalar factor = maximp / btSqrt(impulseSquared);
  480. m_wheelInfo[wheel].m_skidInfo *= factor;
  481. }
  482. }
  483. }
  484. }
  485. if (sliding)
  486. {
  487. for (int wheel = 0; wheel < getNumWheels(); wheel++)
  488. {
  489. if (m_sideImpulse[wheel] != btScalar(0.))
  490. {
  491. if (m_wheelInfo[wheel].m_skidInfo < btScalar(1.))
  492. {
  493. m_forwardImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo;
  494. m_sideImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo;
  495. }
  496. }
  497. }
  498. }
  499. // apply the impulses
  500. {
  501. for (int wheel = 0; wheel < getNumWheels(); wheel++)
  502. {
  503. btWheelInfo& wheelInfo = m_wheelInfo[wheel];
  504. btVector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
  505. m_chassisBody->getCenterOfMassPosition();
  506. if (m_forwardImpulse[wheel] != btScalar(0.))
  507. {
  508. m_chassisBody->applyImpulse(m_forwardWS[wheel] * (m_forwardImpulse[wheel]), rel_pos);
  509. }
  510. if (m_sideImpulse[wheel] != btScalar(0.))
  511. {
  512. class btRigidBody* groundObject = (class btRigidBody*)m_wheelInfo[wheel].m_raycastInfo.m_groundObject;
  513. btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS -
  514. groundObject->getCenterOfMassPosition();
  515. btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
  516. #if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
  517. btVector3 vChassisWorldUp = getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
  518. rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
  519. #else
  520. rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence;
  521. #endif
  522. m_chassisBody->applyImpulse(sideImp, rel_pos);
  523. //apply friction impulse on the ground
  524. groundObject->applyImpulse(-sideImp, rel_pos2);
  525. }
  526. }
  527. }
  528. }
  529. void btRaycastVehicle::debugDraw(btIDebugDraw* debugDrawer)
  530. {
  531. for (int v = 0; v < this->getNumWheels(); v++)
  532. {
  533. btVector3 wheelColor(0, 1, 1);
  534. if (getWheelInfo(v).m_raycastInfo.m_isInContact)
  535. {
  536. wheelColor.setValue(0, 0, 1);
  537. }
  538. else
  539. {
  540. wheelColor.setValue(1, 0, 1);
  541. }
  542. btVector3 wheelPosWS = getWheelInfo(v).m_worldTransform.getOrigin();
  543. btVector3 axle = btVector3(
  544. getWheelInfo(v).m_worldTransform.getBasis()[0][getRightAxis()],
  545. getWheelInfo(v).m_worldTransform.getBasis()[1][getRightAxis()],
  546. getWheelInfo(v).m_worldTransform.getBasis()[2][getRightAxis()]);
  547. //debug wheels (cylinders)
  548. debugDrawer->drawLine(wheelPosWS, wheelPosWS + axle, wheelColor);
  549. debugDrawer->drawLine(wheelPosWS, getWheelInfo(v).m_raycastInfo.m_contactPointWS, wheelColor);
  550. }
  551. }
  552. void* btDefaultVehicleRaycaster::castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result)
  553. {
  554. // RayResultCallback& resultCallback;
  555. btCollisionWorld::ClosestRayResultCallback rayCallback(from, to);
  556. m_dynamicsWorld->rayTest(from, to, rayCallback);
  557. if (rayCallback.hasHit())
  558. {
  559. const btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject);
  560. if (body && body->hasContactResponse())
  561. {
  562. result.m_hitPointInWorld = rayCallback.m_hitPointWorld;
  563. result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld;
  564. result.m_hitNormalInWorld.normalize();
  565. result.m_distFraction = rayCallback.m_closestHitFraction;
  566. return (void*)body;
  567. }
  568. }
  569. return 0;
  570. }