void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { //calculate the impulse, so that the wheels don't move sidewards int numWheel = wheels.size(); if (!numWheel) return; m_forwardWS.resize(numWheel); m_axle.resize(numWheel); m_forwardImpulse.resize(numWheel); m_sideImpulse.resize(numWheel); int numWheelsOnGround = 0; //collapse all those loops into one! for (int i=0;i<wheels.size();i++) { VehicleWheel& wheelInfo = *wheels[i]; if (wheelInfo.m_raycastInfo.m_isInContact) numWheelsOnGround++; m_sideImpulse[i] = real_t(0.); m_forwardImpulse[i] = real_t(0.); } { for (int i=0;i<wheels.size();i++) { VehicleWheel& wheelInfo = *wheels[i]; if (wheelInfo.m_raycastInfo.m_isInContact) { //const btTransform& wheelTrans = getWheelTransformWS( i ); Matrix3 wheelBasis0 = wheelInfo.m_worldTransform.basis;//get_global_transform().basis; m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X); //m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS; const Vector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS; real_t proj = m_axle[i].dot(surfNormalWS); m_axle[i] -= surfNormalWS * proj; m_axle[i] = m_axle[i].normalized(); m_forwardWS[i] = surfNormalWS.cross(m_axle[i]); m_forwardWS[i].normalize(); _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_axle[i],m_sideImpulse[i]); m_sideImpulse[i] *= sideFrictionStiffness2; } } } real_t sideFactor = real_t(1.); real_t fwdFactor = 0.5; bool sliding = false; { for (int wheel =0;wheel <wheels.size();wheel++) { VehicleWheel& wheelInfo = *wheels[wheel]; //class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; real_t rollingFriction = 0.f; if (wheelInfo.m_raycastInfo.m_isInContact) { if (engine_force != 0.f) { rollingFriction = -engine_force* s->get_step(); } else { real_t defaultRollingFrictionImpulse = 0.f; float cbrake = MAX(wheelInfo.m_brake,brake); real_t maxImpulse = cbrake ? cbrake : defaultRollingFrictionImpulse; btVehicleWheelContactPoint contactPt(s,wheelInfo.m_raycastInfo.m_groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse); rollingFriction = _calc_rolling_friction(contactPt); } } //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break) m_forwardImpulse[wheel] = real_t(0.); wheelInfo.m_skidInfo= real_t(1.); if (wheelInfo.m_raycastInfo.m_isInContact) { wheelInfo.m_skidInfo= real_t(1.); real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip; real_t maximpSide = maximp; real_t maximpSquared = maximp * maximpSide; m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep; real_t x = (m_forwardImpulse[wheel] ) * fwdFactor; real_t y = (m_sideImpulse[wheel] ) * sideFactor; real_t impulseSquared = (x*x + y*y); if (impulseSquared > maximpSquared) { sliding = true; real_t factor = maximp / Math::sqrt(impulseSquared); wheelInfo.m_skidInfo *= factor; } } } } if (sliding) { for (int wheel = 0;wheel < wheels.size(); wheel++) { if (m_sideImpulse[wheel] != real_t(0.)) { if (wheels[wheel]->m_skidInfo< real_t(1.)) { m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo; m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo; } } } } // apply the impulses { for (int wheel = 0;wheel<wheels.size(); wheel++) { VehicleWheel& wheelInfo = *wheels[wheel]; Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS - s->get_transform().origin; if (m_forwardImpulse[wheel] != real_t(0.)) { s->apply_impulse(rel_pos,m_forwardWS[wheel]*(m_forwardImpulse[wheel])); } if (m_sideImpulse[wheel] != real_t(0.)) { PhysicsBody* groundObject = wheelInfo.m_raycastInfo.m_groundObject; Vector3 rel_pos2; if (groundObject) { rel_pos2=wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin; } Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; #if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT. Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1];//getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis); rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence)); #else rel_pos[1] *= wheelInfo.m_rollInfluence; //? #endif s->apply_impulse(rel_pos,sideImp); //apply friction impulse on the ground //todo //groundObject->applyImpulse(-sideImp,rel_pos2); } } } }
void btRaycastVehicle::updateFriction(btScalar timeStep) { //calculate the impulse, so that the wheels don't move sidewards int numWheel = getNumWheels(); if (!numWheel) return; m_forwardWS.resize(numWheel); m_axle.resize(numWheel); m_forwardImpulse.resize(numWheel); m_sideImpulse.resize(numWheel); int numWheelsOnGround = 0; //collapse all those loops into one! for (int i=0; i<getNumWheels(); i++) { btWheelInfo& wheelInfo = m_wheelInfo[i]; class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; if (groundObject) numWheelsOnGround++; m_sideImpulse[i] = btScalar(0.); m_forwardImpulse[i] = btScalar(0.); } { for (int i=0; i<getNumWheels(); i++) { btWheelInfo& wheelInfo = m_wheelInfo[i]; class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; if (groundObject) { const btTransform& wheelTrans = getWheelTransformWS( i ); btMatrix3x3 wheelBasis0 = wheelTrans.getBasis(); m_axle[i] = btVector3( wheelBasis0[0][m_indexRightAxis], wheelBasis0[1][m_indexRightAxis], wheelBasis0[2][m_indexRightAxis]); const btVector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS; btScalar proj = m_axle[i].dot(surfNormalWS); m_axle[i] -= surfNormalWS * proj; m_axle[i] = m_axle[i].normalize(); m_forwardWS[i] = surfNormalWS.cross(m_axle[i]); m_forwardWS[i].normalize(); resolveSingleBilateral(*m_chassisBody, wheelInfo.m_raycastInfo.m_contactPointWS, *groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, btScalar(0.), m_axle[i],m_sideImpulse[i],timeStep); m_sideImpulse[i] *= sideFrictionStiffness2; } } } btScalar sideFactor = btScalar(1.); btScalar fwdFactor = 0.5; bool sliding = false; { for (int wheel =0; wheel <getNumWheels(); wheel++) { btWheelInfo& wheelInfo = m_wheelInfo[wheel]; class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; btScalar rollingFriction = 0.f; if (groundObject) { if (wheelInfo.m_engineForce != 0.f) { rollingFriction = wheelInfo.m_engineForce* timeStep; } else { btScalar defaultRollingFrictionImpulse = 0.f; btScalar maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse; btWheelContactPoint contactPt(m_chassisBody,groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse); rollingFriction = calcRollingFriction(contactPt); } } //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break) m_forwardImpulse[wheel] = btScalar(0.); m_wheelInfo[wheel].m_skidInfo= btScalar(1.); if (groundObject) { m_wheelInfo[wheel].m_skidInfo= btScalar(1.); btScalar maximp = wheelInfo.m_wheelsSuspensionForce * timeStep * wheelInfo.m_frictionSlip; btScalar maximpSide = maximp; btScalar maximpSquared = maximp * maximpSide; m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep; btScalar x = (m_forwardImpulse[wheel] ) * fwdFactor; btScalar y = (m_sideImpulse[wheel] ) * sideFactor; btScalar impulseSquared = (x*x + y*y); if (impulseSquared > maximpSquared) { sliding = true; btScalar factor = maximp / btSqrt(impulseSquared); m_wheelInfo[wheel].m_skidInfo *= factor; } } } } if (sliding) { for (int wheel = 0; wheel < getNumWheels(); wheel++) { if (m_sideImpulse[wheel] != btScalar(0.)) { if (m_wheelInfo[wheel].m_skidInfo< btScalar(1.)) { m_forwardImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; m_sideImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; } } } } // apply the impulses { for (int wheel = 0; wheel<getNumWheels() ; wheel++) { btWheelInfo& wheelInfo = m_wheelInfo[wheel]; btVector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS - m_chassisBody->getCenterOfMassPosition(); if (m_forwardImpulse[wheel] != btScalar(0.)) { m_chassisBody->applyImpulse(m_forwardWS[wheel]*(m_forwardImpulse[wheel]),rel_pos); } if (m_sideImpulse[wheel] != btScalar(0.)) { class btRigidBody* groundObject = (class btRigidBody*) m_wheelInfo[wheel].m_raycastInfo.m_groundObject; btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->getCenterOfMassPosition(); btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; #if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT. btVector3 vChassisWorldUp = getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis); rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence)); #else rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence; #endif m_chassisBody->applyImpulse(sideImp,rel_pos); //apply friction impulse on the ground groundObject->applyImpulse(-sideImp,rel_pos2); } } } }
void btKart::updateFriction(btScalar timeStep) { //calculate the impulse, so that the wheels don't move sidewards for (int i=0;i<getNumWheels();i++) { m_sideImpulse[i] = btScalar(0.); btWheelInfo& wheelInfo = m_wheelInfo[i]; btRigidBody* groundObject = (btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; if(!groundObject) continue; const btTransform& wheelTrans = getWheelTransformWS( i ); btMatrix3x3 wheelBasis0 = wheelTrans.getBasis(); m_axle[i] = btVector3(wheelBasis0[0][m_indexRightAxis], wheelBasis0[1][m_indexRightAxis], wheelBasis0[2][m_indexRightAxis] ); const btVector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS; btScalar proj = m_axle[i].dot(surfNormalWS); m_axle[i] -= surfNormalWS * proj; m_axle[i] = m_axle[i].normalize(); m_forwardWS[i] = surfNormalWS.cross(m_axle[i]); m_forwardWS[i].normalize(); resolveSingleBilateral(*m_chassisBody, wheelInfo.m_raycastInfo.m_contactPointWS, *groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, btScalar(0.), m_axle[i],m_sideImpulse[i], timeStep); btScalar sideFrictionStiffness2 = btScalar(1.0); m_sideImpulse[i] *= sideFrictionStiffness2; } btScalar sideFactor = btScalar(1.); btScalar fwdFactor = 0.5; bool sliding = false; for (int wheel=0; wheel<getNumWheels(); wheel++) { btWheelInfo& wheelInfo = m_wheelInfo[wheel]; m_wheelInfo[wheel].m_skidInfo = btScalar(1.); m_forwardImpulse[wheel] = btScalar(0.); btRigidBody* groundObject = (btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; if(!groundObject) continue; if(m_zipper_speed > 0) { if (wheel==2 || wheel==3) { // The zipper velocity is the speed that should be // reached. So compute the impulse to accelerate the // kart up to that speed: m_forwardImpulse[wheel] = 0.5f*(m_zipper_speed - getRigidBody()->getLinearVelocity().length()) / m_chassisBody->getInvMass(); } } else { btScalar rollingFriction = 0.f; if (wheelInfo.m_engineForce != 0.f) { rollingFriction = wheelInfo.m_engineForce* timeStep; } else { btScalar defaultRollingFrictionImpulse = 0.f; btScalar maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse; btWheelContactPoint contactPt(m_chassisBody, groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel],maxImpulse); rollingFriction = calcRollingFriction(contactPt); // This is a work around for the problem that a kart shakes // if it is braking: we get a minor impulse forward, which // bullet then tries to offset by applying a backward // impulse - which is a bit too big, causing a impulse // backwards, ... till the kart is shaking backwards and // forwards. By only applying half of the impulse in case // of low friction this goes away. if(wheelInfo.m_brake && fabsf(rollingFriction)<10) rollingFriction*=0.5f; } m_forwardImpulse[wheel] = rollingFriction; } if(m_time_additional_impulse>0) { sliding = true; m_wheelInfo[wheel].m_skidInfo = 0.0f; } else { btScalar maximp = wheelInfo.m_wheelsSuspensionForce * timeStep * wheelInfo.m_frictionSlip; btScalar maximpSide = maximp; btScalar maximpSquared = maximp * maximpSide; btScalar x = (m_forwardImpulse[wheel] ) * fwdFactor; btScalar y = (m_sideImpulse[wheel] ) * sideFactor; btScalar impulseSquared = (x*x + y*y); if (impulseSquared > maximpSquared) { sliding = true; btScalar factor = maximp / btSqrt(impulseSquared); m_wheelInfo[wheel].m_skidInfo *= factor; } // if impulseSquared > maximpSquared } // else (!m_timed_impulse } // for (int wheel=0; wheel<getNumWheels(); wheel++) // Note: don't reset zipper speed, or the kart rewinder will // get incorrect zipper information. // The kart just stopped skidding. Adjust the velocity so that // it points in the right direction. // FIXME: this is not good enough, we need some smooth interpolation here. if(m_is_skidding && m_skid_angular_velocity == 0) { btVector3 v = m_chassisBody->getLinearVelocity(); v.setZ(sqrt(v.getX()*v.getX()+v.getZ()*v.getZ())); v.setX(0); btVector3 v_new = m_chassisBody->getWorldTransform().getBasis()*v; m_chassisBody->setLinearVelocity(v_new); m_is_skidding = false; } if(m_skid_angular_velocity!=0) { m_is_skidding = true; // Skidding is implemented by not having any forward impulse, // but only add a side impulse for(unsigned int i=0; i<4; i++) { m_forwardImpulse[i] = 0; m_sideImpulse[i] = 0; } btVector3 av = m_chassisBody->getAngularVelocity(); av.setY(m_skid_angular_velocity); m_chassisBody->setAngularVelocity(av); } else if (sliding && (m_allow_sliding || m_time_additional_impulse>0) ) { for (int wheel = 0; wheel < getNumWheels(); wheel++) { if (m_sideImpulse[wheel] != btScalar(0.) && m_wheelInfo[wheel].m_skidInfo< btScalar(1.) ) { m_forwardImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; m_sideImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; } } // for wheel <getNumWheels } // if sliding // Apply the impulses // ------------------ for (int wheel = 0;wheel<getNumWheels() ; wheel++) { btWheelInfo& wheelInfo = m_wheelInfo[wheel]; btVector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS - m_chassisBody->getCenterOfMassPosition(); if (m_forwardImpulse[wheel] != btScalar(0.)) { m_chassisBody->applyImpulse( m_forwardWS[wheel]*(m_forwardImpulse[wheel]), #define COMPATIBLE_0_7_3 #ifdef COMPATIBLE_0_7_3 // This was apparently done to help hexley btVector3(0,0,0)); #else rel_pos); #endif } if (m_sideImpulse[wheel] != btScalar(0.)) { btRigidBody* groundObject = (btRigidBody*) m_wheelInfo[wheel].m_raycastInfo.m_groundObject; btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->getCenterOfMassPosition(); //adjust relative position above ground so that force only // acts sideways btVector3 delta_vec = (wheelInfo.m_raycastInfo.m_hardPointWS - wheelInfo.m_raycastInfo.m_contactPointWS); if (delta_vec.length() != btScalar (0)) { delta_vec = delta_vec.normalize(); rel_pos -= delta_vec * rel_pos.dot(delta_vec); } btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; #if defined ROLLING_INFLUENCE_FIX && !defined COMPATIBLE_0_7_3 // fix. It only worked if car's up was along Y - VT. btVector3 vChassisWorldUp = getRigidBody()->getCenterOfMassTransform() .getBasis().getColumn(m_indexUpAxis); rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence) ); #else rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence; #endif m_chassisBody->applyImpulse(sideImp,rel_pos); //apply friction impulse on the ground groundObject->applyImpulse(-sideImp,rel_pos2); } // if (m_sideImpulse[wheel] != btScalar(0.)) } // for wheel<getNumWheels()