2 * Copyright (c) 2005 Erwin Coumans https://bulletphysics.org
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.
12 #include "LinearMath/btVector3.h"
13 #include "btRaycastVehicle.h"
15 #include "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h"
16 #include "BulletDynamics/ConstraintSolver/btJacobianEntry.h"
17 #include "LinearMath/btQuaternion.h"
18 #include "BulletDynamics/Dynamics/btDynamicsWorld.h"
19 #include "btVehicleRaycaster.h"
20 #include "btWheelInfo.h"
21 #include "LinearMath/btMinMax.h"
22 #include "LinearMath/btIDebugDraw.h"
23 #include "BulletDynamics/ConstraintSolver/btContactConstraint.h"
25 #define ROLLING_INFLUENCE_FIX
27 btRigidBody& btActionInterface::getFixedBody()
29 static btRigidBody s_fixed(0, 0, 0);
30 s_fixed.setMassProps(btScalar(0.), btVector3(btScalar(0.), btScalar(0.), btScalar(0.)));
34 btRaycastVehicle::btRaycastVehicle(const btVehicleTuning& tuning, btRigidBody* chassis, btVehicleRaycaster* raycaster)
35 : m_vehicleRaycaster(raycaster),
36 m_pitchControl(btScalar(0.))
38 m_chassisBody = chassis;
41 m_indexForwardAxis = 1;
45 void btRaycastVehicle::defaultInit(const btVehicleTuning& tuning)
48 m_currentVehicleSpeedKmHour = btScalar(0.);
49 m_steeringValue = btScalar(0.);
52 btRaycastVehicle::~btRaycastVehicle()
57 // basically most of the code is general for 2 or 4 wheel vehicles, but some of it needs to be reviewed
59 btWheelInfo& btRaycastVehicle::addWheel(const btVector3& connectionPointCS, const btVector3& wheelDirectionCS0, const btVector3& wheelAxleCS, btScalar suspensionRestLength, btScalar wheelRadius, const btVehicleTuning& tuning, bool isFrontWheel)
61 btWheelInfoConstructionInfo ci;
63 ci.m_chassisConnectionCS = connectionPointCS;
64 ci.m_wheelDirectionCS = wheelDirectionCS0;
65 ci.m_wheelAxleCS = wheelAxleCS;
66 ci.m_suspensionRestLength = suspensionRestLength;
67 ci.m_wheelRadius = wheelRadius;
68 ci.m_suspensionStiffness = tuning.m_suspensionStiffness;
69 ci.m_wheelsDampingCompression = tuning.m_suspensionCompression;
70 ci.m_wheelsDampingRelaxation = tuning.m_suspensionDamping;
71 ci.m_frictionSlip = tuning.m_frictionSlip;
72 ci.m_bIsFrontWheel = isFrontWheel;
73 ci.m_maxSuspensionTravelCm = tuning.m_maxSuspensionTravelCm;
74 ci.m_maxSuspensionForce = tuning.m_maxSuspensionForce;
76 m_wheelInfo.push_back(btWheelInfo(ci));
78 btWheelInfo& wheel = m_wheelInfo[getNumWheels() - 1];
80 updateWheelTransformsWS(wheel, false);
81 updateWheelTransform(getNumWheels() - 1, false);
85 const btTransform& btRaycastVehicle::getWheelTransformWS(int wheelIndex) const
87 btAssert(wheelIndex < getNumWheels());
88 const btWheelInfo& wheel = m_wheelInfo[wheelIndex];
89 return wheel.m_worldTransform;
92 void btRaycastVehicle::updateWheelTransform(int wheelIndex, bool interpolatedTransform)
94 btWheelInfo& wheel = m_wheelInfo[wheelIndex];
95 updateWheelTransformsWS(wheel, interpolatedTransform);
96 btVector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
97 const btVector3& right = wheel.m_raycastInfo.m_wheelAxleWS;
98 btVector3 fwd = up.cross(right);
99 fwd = fwd.normalize();
100 // up = right.cross(fwd);
103 //rotate around steering over de wheelAxleWS
104 btScalar steering = wheel.m_steering;
106 btQuaternion steeringOrn(up, steering); //wheel.m_steering);
107 btMatrix3x3 steeringMat(steeringOrn);
109 btQuaternion rotatingOrn(right, -wheel.m_rotation);
110 btMatrix3x3 rotatingMat(rotatingOrn);
113 basis2[0][m_indexRightAxis] = -right[0];
114 basis2[1][m_indexRightAxis] = -right[1];
115 basis2[2][m_indexRightAxis] = -right[2];
117 basis2[0][m_indexUpAxis] = up[0];
118 basis2[1][m_indexUpAxis] = up[1];
119 basis2[2][m_indexUpAxis] = up[2];
121 basis2[0][m_indexForwardAxis] = fwd[0];
122 basis2[1][m_indexForwardAxis] = fwd[1];
123 basis2[2][m_indexForwardAxis] = fwd[2];
125 wheel.m_worldTransform.setBasis(steeringMat * rotatingMat * basis2);
126 wheel.m_worldTransform.setOrigin(
127 wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength);
130 void btRaycastVehicle::resetSuspension()
133 for (i = 0; i < m_wheelInfo.size(); i++)
135 btWheelInfo& wheel = m_wheelInfo[i];
136 wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength();
137 wheel.m_suspensionRelativeVelocity = btScalar(0.0);
139 wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
140 //wheel_info.setContactFriction(btScalar(0.0));
141 wheel.m_clippedInvContactDotSuspension = btScalar(1.0);
145 void btRaycastVehicle::updateWheelTransformsWS(btWheelInfo& wheel, bool interpolatedTransform)
147 wheel.m_raycastInfo.m_isInContact = false;
149 btTransform chassisTrans = getChassisWorldTransform();
150 if (interpolatedTransform && (getRigidBody()->getMotionState()))
152 getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
155 wheel.m_raycastInfo.m_hardPointWS = chassisTrans(wheel.m_chassisConnectionPointCS);
156 wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.getBasis() * wheel.m_wheelDirectionCS;
157 wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.getBasis() * wheel.m_wheelAxleCS;
160 btScalar btRaycastVehicle::rayCast(btWheelInfo& wheel)
162 updateWheelTransformsWS(wheel, false);
166 btScalar raylen = wheel.getSuspensionRestLength() + wheel.m_wheelsRadius;
168 btVector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
169 const btVector3& source = wheel.m_raycastInfo.m_hardPointWS;
170 wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
171 const btVector3& target = wheel.m_raycastInfo.m_contactPointWS;
173 btScalar param = btScalar(0.);
175 btVehicleRaycaster::btVehicleRaycasterResult rayResults;
177 btAssert(m_vehicleRaycaster);
179 void* object = m_vehicleRaycaster->castRay(source, target, rayResults);
181 wheel.m_raycastInfo.m_groundObject = 0;
185 param = rayResults.m_distFraction;
186 depth = raylen * rayResults.m_distFraction;
187 wheel.m_raycastInfo.m_contactNormalWS = rayResults.m_hitNormalInWorld;
188 wheel.m_raycastInfo.m_isInContact = true;
190 wheel.m_raycastInfo.m_groundObject = &getFixedBody(); ///@todo for driving on dynamic/movable objects!;
191 //wheel.m_raycastInfo.m_groundObject = object;
193 btScalar hitDistance = param * raylen;
194 wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelsRadius;
195 //clamp on max suspension travel
197 btScalar minSuspensionLength = wheel.getSuspensionRestLength() - wheel.m_maxSuspensionTravelCm * btScalar(0.01);
198 btScalar maxSuspensionLength = wheel.getSuspensionRestLength() + wheel.m_maxSuspensionTravelCm * btScalar(0.01);
199 if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength)
201 wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
203 if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength)
205 wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
208 wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld;
210 btScalar denominator = wheel.m_raycastInfo.m_contactNormalWS.dot(wheel.m_raycastInfo.m_wheelDirectionWS);
212 btVector3 chassis_velocity_at_contactPoint;
213 btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition();
215 chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
217 btScalar projVel = wheel.m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
219 if (denominator >= btScalar(-0.1))
221 wheel.m_suspensionRelativeVelocity = btScalar(0.0);
222 wheel.m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1);
226 btScalar inv = btScalar(-1.) / denominator;
227 wheel.m_suspensionRelativeVelocity = projVel * inv;
228 wheel.m_clippedInvContactDotSuspension = inv;
233 //put wheel info as in rest position
234 wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength();
235 wheel.m_suspensionRelativeVelocity = btScalar(0.0);
236 wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
237 wheel.m_clippedInvContactDotSuspension = btScalar(1.0);
243 const btTransform& btRaycastVehicle::getChassisWorldTransform() const
245 /*if (getRigidBody()->getMotionState())
247 btTransform chassisWorldTrans;
248 getRigidBody()->getMotionState()->getWorldTransform(chassisWorldTrans);
249 return chassisWorldTrans;
253 return getRigidBody()->getCenterOfMassTransform();
256 void btRaycastVehicle::updateVehicle(btScalar step)
259 for (int i = 0; i < getNumWheels(); i++)
261 updateWheelTransform(i, false);
265 m_currentVehicleSpeedKmHour = btScalar(3.6) * getRigidBody()->getLinearVelocity().length();
267 const btTransform& chassisTrans = getChassisWorldTransform();
270 chassisTrans.getBasis()[0][m_indexForwardAxis],
271 chassisTrans.getBasis()[1][m_indexForwardAxis],
272 chassisTrans.getBasis()[2][m_indexForwardAxis]);
274 if (forwardW.dot(getRigidBody()->getLinearVelocity()) < btScalar(0.))
276 m_currentVehicleSpeedKmHour *= btScalar(-1.);
280 // simulate suspension
284 for (i = 0; i < m_wheelInfo.size(); i++)
288 rayCast(m_wheelInfo[i]);
291 updateSuspension(step);
293 for (i = 0; i < m_wheelInfo.size(); i++)
295 //apply suspension force
296 btWheelInfo& wheel = m_wheelInfo[i];
298 btScalar suspensionForce = wheel.m_wheelsSuspensionForce;
300 if (suspensionForce > wheel.m_maxSuspensionForce)
302 suspensionForce = wheel.m_maxSuspensionForce;
304 btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
305 btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition();
307 getRigidBody()->applyImpulse(impulse, relpos);
310 updateFriction(step);
312 for (i = 0; i < m_wheelInfo.size(); i++)
314 btWheelInfo& wheel = m_wheelInfo[i];
315 btVector3 relpos = wheel.m_raycastInfo.m_hardPointWS - getRigidBody()->getCenterOfMassPosition();
316 btVector3 vel = getRigidBody()->getVelocityInLocalPoint(relpos);
318 if (wheel.m_raycastInfo.m_isInContact)
320 const btTransform& chassisWorldTransform = getChassisWorldTransform();
323 chassisWorldTransform.getBasis()[0][m_indexForwardAxis],
324 chassisWorldTransform.getBasis()[1][m_indexForwardAxis],
325 chassisWorldTransform.getBasis()[2][m_indexForwardAxis]);
327 btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
328 fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
330 btScalar proj2 = fwd.dot(vel);
332 wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius);
333 wheel.m_rotation += wheel.m_deltaRotation;
337 wheel.m_rotation += wheel.m_deltaRotation;
340 wheel.m_deltaRotation *= btScalar(0.99); //damping of rotation when not in contact
344 void btRaycastVehicle::setSteeringValue(btScalar steering, int wheel)
346 btAssert(wheel >= 0 && wheel < getNumWheels());
348 btWheelInfo& wheelInfo = getWheelInfo(wheel);
349 wheelInfo.m_steering = steering;
352 btScalar btRaycastVehicle::getSteeringValue(int wheel) const
354 return getWheelInfo(wheel).m_steering;
357 void btRaycastVehicle::applyEngineForce(btScalar force, int wheel)
359 btAssert(wheel >= 0 && wheel < getNumWheels());
360 btWheelInfo& wheelInfo = getWheelInfo(wheel);
361 wheelInfo.m_engineForce = force;
364 const btWheelInfo& btRaycastVehicle::getWheelInfo(int index) const
366 btAssert((index >= 0) && (index < getNumWheels()));
368 return m_wheelInfo[index];
371 btWheelInfo& btRaycastVehicle::getWheelInfo(int index)
373 btAssert((index >= 0) && (index < getNumWheels()));
375 return m_wheelInfo[index];
378 void btRaycastVehicle::setBrake(btScalar brake, int wheelIndex)
380 btAssert((wheelIndex >= 0) && (wheelIndex < getNumWheels()));
381 getWheelInfo(wheelIndex).m_brake = brake;
384 void btRaycastVehicle::updateSuspension(btScalar deltaTime)
388 btScalar chassisMass = btScalar(1.) / m_chassisBody->getInvMass();
390 for (int w_it = 0; w_it < getNumWheels(); w_it++)
392 btWheelInfo& wheel_info = m_wheelInfo[w_it];
394 if (wheel_info.m_raycastInfo.m_isInContact)
399 btScalar susp_length = wheel_info.getSuspensionRestLength();
400 btScalar current_length = wheel_info.m_raycastInfo.m_suspensionLength;
402 btScalar length_diff = (susp_length - current_length);
404 force = wheel_info.m_suspensionStiffness * length_diff * wheel_info.m_clippedInvContactDotSuspension;
409 btScalar projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
411 btScalar susp_damping;
412 if (projected_rel_vel < btScalar(0.0))
414 susp_damping = wheel_info.m_wheelsDampingCompression;
418 susp_damping = wheel_info.m_wheelsDampingRelaxation;
420 force -= susp_damping * projected_rel_vel;
425 wheel_info.m_wheelsSuspensionForce = force * chassisMass;
426 if (wheel_info.m_wheelsSuspensionForce < btScalar(0.))
428 wheel_info.m_wheelsSuspensionForce = btScalar(0.);
433 wheel_info.m_wheelsSuspensionForce = btScalar(0.0);
438 struct btWheelContactPoint
440 btRigidBody* m_body0;
441 btRigidBody* m_body1;
442 btVector3 m_frictionPositionWorld;
443 btVector3 m_frictionDirectionWorld;
444 btScalar m_jacDiagABInv;
445 btScalar m_maxImpulse;
447 btWheelContactPoint(btRigidBody* body0, btRigidBody* body1, const btVector3& frictionPosWorld, const btVector3& frictionDirectionWorld, btScalar maxImpulse)
450 m_frictionPositionWorld(frictionPosWorld),
451 m_frictionDirectionWorld(frictionDirectionWorld),
452 m_maxImpulse(maxImpulse)
454 btScalar denom0 = body0->computeImpulseDenominator(frictionPosWorld, frictionDirectionWorld);
455 btScalar denom1 = body1->computeImpulseDenominator(frictionPosWorld, frictionDirectionWorld);
456 btScalar relaxation = 1.f;
457 m_jacDiagABInv = relaxation / (denom0 + denom1);
461 btScalar calcRollingFriction(btWheelContactPoint& contactPoint, int numWheelsOnGround);
462 btScalar calcRollingFriction(btWheelContactPoint& contactPoint, int numWheelsOnGround)
466 const btVector3& contactPosWorld = contactPoint.m_frictionPositionWorld;
468 btVector3 rel_pos1 = contactPosWorld - contactPoint.m_body0->getCenterOfMassPosition();
469 btVector3 rel_pos2 = contactPosWorld - contactPoint.m_body1->getCenterOfMassPosition();
471 btScalar maxImpulse = contactPoint.m_maxImpulse;
473 btVector3 vel1 = contactPoint.m_body0->getVelocityInLocalPoint(rel_pos1);
474 btVector3 vel2 = contactPoint.m_body1->getVelocityInLocalPoint(rel_pos2);
475 btVector3 vel = vel1 - vel2;
477 btScalar vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
479 // calculate j that moves us to zero relative velocity
480 j1 = -vrel * contactPoint.m_jacDiagABInv / btScalar(numWheelsOnGround);
481 btSetMin(j1, maxImpulse);
482 btSetMax(j1, -maxImpulse);
487 btScalar sideFrictionStiffness2 = btScalar(1.0);
488 void btRaycastVehicle::updateFriction(btScalar timeStep)
490 //calculate the impulse, so that the wheels don't move sidewards
491 int numWheel = getNumWheels();
495 m_forwardWS.resize(numWheel);
496 m_axle.resize(numWheel);
497 m_forwardImpulse.resize(numWheel);
498 m_sideImpulse.resize(numWheel);
500 int numWheelsOnGround = 0;
502 //collapse all those loops into one!
503 for (int i = 0; i < getNumWheels(); i++)
505 btWheelInfo& wheelInfo = m_wheelInfo[i];
506 class btRigidBody* groundObject = (class btRigidBody*)wheelInfo.m_raycastInfo.m_groundObject;
509 m_sideImpulse[i] = btScalar(0.);
510 m_forwardImpulse[i] = btScalar(0.);
514 for (int i = 0; i < getNumWheels(); i++)
516 btWheelInfo& wheelInfo = m_wheelInfo[i];
518 class btRigidBody* groundObject = (class btRigidBody*)wheelInfo.m_raycastInfo.m_groundObject;
522 const btTransform& wheelTrans = getWheelTransformWS(i);
524 btMatrix3x3 wheelBasis0 = wheelTrans.getBasis();
525 m_axle[i] = -btVector3(
526 wheelBasis0[0][m_indexRightAxis],
527 wheelBasis0[1][m_indexRightAxis],
528 wheelBasis0[2][m_indexRightAxis]);
530 const btVector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
531 btScalar proj = m_axle[i].dot(surfNormalWS);
532 m_axle[i] -= surfNormalWS * proj;
533 m_axle[i] = m_axle[i].normalize();
535 m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
536 m_forwardWS[i].normalize();
538 resolveSingleBilateral(*m_chassisBody, wheelInfo.m_raycastInfo.m_contactPointWS,
539 *groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
540 btScalar(0.), m_axle[i], m_sideImpulse[i], timeStep);
542 m_sideImpulse[i] *= sideFrictionStiffness2;
547 btScalar sideFactor = btScalar(1.);
548 btScalar fwdFactor = 0.5;
550 bool sliding = false;
552 for (int wheel = 0; wheel < getNumWheels(); wheel++)
554 btWheelInfo& wheelInfo = m_wheelInfo[wheel];
555 class btRigidBody* groundObject = (class btRigidBody*)wheelInfo.m_raycastInfo.m_groundObject;
557 btScalar rollingFriction = 0.f;
561 if (wheelInfo.m_engineForce != 0.f)
563 rollingFriction = wheelInfo.m_engineForce * timeStep;
567 btScalar defaultRollingFrictionImpulse = 0.f;
568 btScalar maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
569 btWheelContactPoint contactPt(m_chassisBody, groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel], maxImpulse);
570 btAssert(numWheelsOnGround > 0);
571 rollingFriction = calcRollingFriction(contactPt, numWheelsOnGround);
575 //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
577 m_forwardImpulse[wheel] = btScalar(0.);
578 m_wheelInfo[wheel].m_skidInfo = btScalar(1.);
582 m_wheelInfo[wheel].m_skidInfo = btScalar(1.);
584 btScalar maximp = wheelInfo.m_wheelsSuspensionForce * timeStep * wheelInfo.m_frictionSlip;
585 btScalar maximpSide = maximp;
587 btScalar maximpSquared = maximp * maximpSide;
589 m_forwardImpulse[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
591 btScalar x = (m_forwardImpulse[wheel]) * fwdFactor;
592 btScalar y = (m_sideImpulse[wheel]) * sideFactor;
594 btScalar impulseSquared = (x * x + y * y);
596 if (impulseSquared > maximpSquared)
600 btScalar factor = maximp / btSqrt(impulseSquared);
602 m_wheelInfo[wheel].m_skidInfo *= factor;
610 for (int wheel = 0; wheel < getNumWheels(); wheel++)
612 if (m_sideImpulse[wheel] != btScalar(0.))
614 if (m_wheelInfo[wheel].m_skidInfo < btScalar(1.))
616 m_forwardImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo;
617 m_sideImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo;
623 // apply the impulses
625 for (int wheel = 0; wheel < getNumWheels(); wheel++)
627 btWheelInfo& wheelInfo = m_wheelInfo[wheel];
629 btVector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
630 m_chassisBody->getCenterOfMassPosition();
632 if (m_forwardImpulse[wheel] != btScalar(0.))
634 m_chassisBody->applyImpulse(m_forwardWS[wheel] * (m_forwardImpulse[wheel]), rel_pos);
636 if (m_sideImpulse[wheel] != btScalar(0.))
638 class btRigidBody* groundObject = (class btRigidBody*)m_wheelInfo[wheel].m_raycastInfo.m_groundObject;
640 btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS -
641 groundObject->getCenterOfMassPosition();
643 btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
645 #if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
646 btVector3 vChassisWorldUp = getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
647 rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
649 rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence;
651 m_chassisBody->applyImpulse(sideImp, rel_pos);
653 //apply friction impulse on the ground
654 groundObject->applyImpulse(-sideImp, rel_pos2);
660 void btRaycastVehicle::debugDraw(btIDebugDraw* debugDrawer)
662 for (int v = 0; v < this->getNumWheels(); v++)
664 btVector3 wheelColor(0, 1, 1);
665 if (getWheelInfo(v).m_raycastInfo.m_isInContact)
667 wheelColor.setValue(0, 0, 1);
671 wheelColor.setValue(1, 0, 1);
674 btVector3 wheelPosWS = getWheelInfo(v).m_worldTransform.getOrigin();
676 btVector3 axle = btVector3(
677 getWheelInfo(v).m_worldTransform.getBasis()[0][getRightAxis()],
678 getWheelInfo(v).m_worldTransform.getBasis()[1][getRightAxis()],
679 getWheelInfo(v).m_worldTransform.getBasis()[2][getRightAxis()]);
681 //debug wheels (cylinders)
682 debugDrawer->drawLine(wheelPosWS, wheelPosWS + axle, wheelColor);
683 debugDrawer->drawLine(wheelPosWS, getWheelInfo(v).m_raycastInfo.m_contactPointWS, wheelColor);
687 void* btDefaultVehicleRaycaster::castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result)
689 // RayResultCallback& resultCallback;
691 btCollisionWorld::ClosestRayResultCallback rayCallback(from, to);
693 m_dynamicsWorld->rayTest(from, to, rayCallback);
695 if (rayCallback.hasHit())
697 const btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject);
698 if (body && body->hasContactResponse())
700 result.m_hitPointInWorld = rayCallback.m_hitPointWorld;
701 result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld;
702 result.m_hitNormalInWorld.normalize();
703 result.m_distFraction = rayCallback.m_closestHitFraction;