const Bezier * AiCarStandard::GetCurrentPatch(const CarDynamics * c) { const Bezier *curr_patch = c->GetWheelContact(WheelPosition(0)).GetPatch(); if (!curr_patch) { // let's try the other wheel curr_patch = c->GetWheelContact(WheelPosition(1)).GetPatch(); if (!curr_patch) return NULL; } return curr_patch; }
void AiCarStandard::CalcMu() { const float tire_load = 0.25 * GRAVITY / car->GetInvMass(); float long_friction = 0.0; float lat_friction = 0.0; for (int i = 0; i < 4; i++) { long_friction += car->GetTire(WheelPosition(i)).getMaxFx(tire_load); lat_friction += car->GetTire(WheelPosition(i)).getMaxFy(tire_load, 0.0); } float long_mu = FRICTION_FACTOR_LONG * long_friction * car->GetInvMass() / GRAVITY; float lat_mu = FRICTION_FACTOR_LAT * lat_friction * car->GetInvMass() / GRAVITY; if (!std::isnan(long_mu)) longitude_mu = long_mu; if (!std::isnan(lat_mu)) lateral_mu = lat_mu; }
void CarSound::Update(const CarDynamics & dynamics, float dt) { if (!psound) return; Vec3 pos_car = ToMathVector<float>(dynamics.GetPosition()); Vec3 pos_eng = ToMathVector<float>(dynamics.GetEnginePosition()); psound->SetSourcePosition(roadnoise, pos_car[0], pos_car[1], pos_car[2]); psound->SetSourcePosition(crashsound, pos_car[0], pos_car[1], pos_car[2]); psound->SetSourcePosition(gearsound, pos_car[0], pos_car[1], pos_car[2]); psound->SetSourcePosition(brakesound, pos_car[0], pos_car[1], pos_car[2]); psound->SetSourcePosition(handbrakesound, pos_car[0], pos_car[1], pos_car[2]); // update engine sounds const float rpm = dynamics.GetTachoRPM(); const float throttle = dynamics.GetEngine().GetThrottle(); float total_gain = 0.0; std::vector<std::pair<size_t, float> > gainlist; gainlist.reserve(enginesounds.size()); for (auto & info : enginesounds) { float gain = 1.0; if (rpm < info.minrpm) { gain = 0; } else if (rpm < info.fullgainrpmstart && info.fullgainrpmstart > info.minrpm) { gain *= (rpm - info.minrpm) / (info.fullgainrpmstart - info.minrpm); } if (rpm > info.maxrpm) { gain = 0; } else if (rpm > info.fullgainrpmend && info.fullgainrpmend < info.maxrpm) { gain *= 1.0 - (rpm - info.fullgainrpmend) / (info.maxrpm - info.fullgainrpmend); } if (info.power == EngineSoundInfo::BOTH) { gain *= throttle * 0.5 + 0.5; } else if (info.power == EngineSoundInfo::POWERON) { gain *= throttle; } else if (info.power == EngineSoundInfo::POWEROFF) { gain *= (1.0-throttle); } total_gain += gain; gainlist.push_back(std::make_pair(info.sound_source, gain)); float pitch = rpm / info.naturalrpm; psound->SetSourcePosition(info.sound_source, pos_eng[0], pos_eng[1], pos_eng[2]); psound->SetSourcePitch(info.sound_source, pitch); } // normalize gains assert(total_gain >= 0.0); for (const auto & sound_gain : gainlist) { float gain; if (total_gain == 0.0) { gain = 0.0; } else if (enginesounds.size() == 1 && enginesounds.back().power == EngineSoundInfo::BOTH) { gain = sound_gain.second; } else { gain = sound_gain.second / total_gain; } psound->SetSourceGain(sound_gain.first, gain); } // update tire squeal sounds for (int i = 0; i < 4; i++) { // make sure we don't get overlap psound->SetSourceGain(gravelsound[i], 0.0); psound->SetSourceGain(grasssound[i], 0.0); psound->SetSourceGain(tiresqueal[i], 0.0); float squeal = dynamics.GetTireSquealAmount(WheelPosition(i)); float maxgain = 0.3; float pitchvariation = 0.4; unsigned sound_active = 0; const TrackSurface & surface = dynamics.GetWheelContact(WheelPosition(i)).GetSurface(); if (surface.type == TrackSurface::ASPHALT) { sound_active = tiresqueal[i]; } else if (surface.type == TrackSurface::GRASS) { sound_active = grasssound[i]; maxgain = 0.4; // up the grass sound volume a little } else if (surface.type == TrackSurface::GRAVEL) { sound_active = gravelsound[i]; maxgain = 0.4; } else if (surface.type == TrackSurface::CONCRETE) { sound_active = tiresqueal[i]; maxgain = 0.3; pitchvariation = 0.25; } else if (surface.type == TrackSurface::SAND) { sound_active = grasssound[i]; maxgain = 0.25; // quieter for sand pitchvariation = 0.25; } else { sound_active = tiresqueal[i]; maxgain = 0.0; } btVector3 pos_wheel = dynamics.GetWheelPosition(WheelPosition(i)); btVector3 vel_wheel = dynamics.GetWheelVelocity(WheelPosition(i)); float pitch = (vel_wheel.length() - 5.0) * 0.1; pitch = clamp(pitch, 0.0f, 1.0f); pitch = 1.0 - pitch; pitch *= pitchvariation; pitch = pitch + (1.0 - pitchvariation); pitch = clamp(pitch, 0.1f, 4.0f); psound->SetSourcePosition(sound_active, pos_wheel[0], pos_wheel[1], pos_wheel[2]); psound->SetSourcePitch(sound_active, pitch); psound->SetSourceGain(sound_active, squeal * maxgain); } // update road noise sound { float gain = dynamics.GetVelocity().length(); gain *= 0.02; gain *= gain; if (gain > 1) gain = 1; psound->SetSourceGain(roadnoise, gain); } /* fixme // update bump noise sound { for (int i = 0; i < 4; i++) { suspensionbumpdetection[i].Update( dynamics.GetSuspension(WHEEL_POSITION(i)).GetVelocity(), dynamics.GetSuspension(WHEEL_POSITION(i)).GetDisplacementFraction(), dt); if (suspensionbumpdetection[i].JustSettled()) { float bumpsize = suspensionbumpdetection[i].GetTotalBumpSize(); const float breakevenms = 5.0; float gain = bumpsize * GetSpeed() / breakevenms; if (gain > 1) gain = 1; if (gain < 0) gain = 0; if (gain > 0 && !tirebump[i].Audible()) { tirebump[i].SetGain(gain); tirebump[i].Stop(); tirebump[i].Play(); } } } } */ // update crash sound crashdetection.Update(dynamics.GetSpeed(), dt); float crashdecel = crashdetection.GetMaxDecel(); if (crashdecel > 0) { const float mingainat = 200; const float maxgainat = 2000; float gain = (crashdecel - mingainat) / (maxgainat - mingainat); gain = clamp(gain, 0.1f, 1.0f); if (!psound->GetSourcePlaying(crashsound)) { psound->ResetSource(crashsound); psound->SetSourceGain(crashsound, gain); } } // update interior sounds if (!interior) return; // update gear sound if (gearsound_check != dynamics.GetTransmission().GetGear()) { float gain = 0.0; if (rpm > 0.0) gain = dynamics.GetEngine().GetRPMLimit() / rpm; gain = clamp(gain, 0.25f, 0.50f); if (!psound->GetSourcePlaying(gearsound)) { psound->ResetSource(gearsound); psound->SetSourceGain(gearsound, gain); } gearsound_check = dynamics.GetTransmission().GetGear(); } /* fixme // brake sound if (inputs[CarInput::BRAKE] > 0 && !brakesound_check) { // disable brake sound, sounds wierd if (false)//!psound->GetSourcePlaying(brakesound)) { psound->ResetSource(brakesound); psound->SetSourceGain(brakesound, 0.5); } brakesound_check = true; } if (inputs[CarInput::BRAKE] <= 0) brakesound_check = false; // handbrake sound if (inputs[CarInput::HANDBRAKE] > 0 && !handbrakesound_check) { if (!psound->GetSourcePlaying(handbrakesound)) { psound->ResetSource(handbrakesound); psound->SetSourceGain(handbrakesound, 0.5); } handbrakesound_check = true; } if (inputs[CarInput::HANDBRAKE] <= 0) handbrakesound_check = false; */ }
void PerformanceTesting::TestStoppingDistance(bool abs, std::ostream & info_output, std::ostream & error_output) { info_output << "Testing stopping distance" << std::endl; float maxtime = 300.0; float t = 0.; float dt = 1/90.0; int i = 0; float stopthreshold = 0.1; //if the speed (in m/s) is less than this value, discontinue the testing btVector3 stopstart; //where the stopping starts float brakestartspeed = 26.82; //speed at which to start braking, in m/s (26.82 m/s is 60 mph) bool accelerating = true; //switches to false once 60 mph is reached ResetCar(); car.SetABS(abs); while (t < maxtime) { if (accelerating) { carinput[CarInput::THROTTLE] = 1.0f; carinput[CarInput::BRAKE] = 0.0f; } else { carinput[CarInput::THROTTLE] = 0.0f; carinput[CarInput::BRAKE] = 1.0f; } car.Update(carinput); world.update(dt); float car_speed = car.GetSpeed(); if (car_speed >= brakestartspeed && accelerating) //stop accelerating and hit the brakes { accelerating = false; stopstart = car.GetWheelPosition(WheelPosition(0)); //std::cout << "hitting the brakes at " << t << ", " << car_speed << std::endl; } if (!accelerating && car_speed < stopthreshold) { break; } if (!car.GetEngine().GetCombustion()) { error_output << "Car stalled during launch, t=" << t << std::endl; break; } if (i % (int)(1.0/dt) == 0) //every second { //std::cout << t << ", " << car.dynamics.GetSpeed() << ", " << car.GetGear() << ", " << car.GetEngineRPM() << std::endl; } t += dt; i++; } btVector3 stopend = car.GetWheelPosition(WheelPosition(0)); info_output << "60-0 stopping distance "; if (abs) info_output << "(ABS)"; else info_output << "(no ABS)"; info_output << ": " << ConvertToFeet((stopend-stopstart).length()) << " ft" << std::endl; }
void PerformanceTesting::TestStoppingDistance(bool abs, std::ostream & info_output, std::ostream & error_output) { info_output << "Testing stopping distance" << std::endl; float maxtime = 300; float t = 0.; float dt = 1/90.0; int i = 0; float stopthreshold = 0.1; //if the speed (in m/s) is less than this value, discontinue the testing btVector3 stopstart; //where the stopping starts float brakestartspeed = 26.82; //speed at which to start braking, in m/s (26.82 m/s is 60 mph) // wheel lockup speeds during braking float front_lockup_speed = 0.0f; float rear_lockup_speed = 0.0f; bool accelerating = true; //switches to false once 60 mph is reached ResetCar(); car.SetABS(abs); while (t < maxtime) { if (accelerating && car.GetTransmission().GetGear() == 1 && car.GetEngine().GetRPM() > 0.8f * car.GetEngine().GetRedline()) { carinput[CarInput::BRAKE] = 0; carinput[CarInput::CLUTCH] = 0; } car.Update(carinput); world.update(dt); float car_speed = car.GetSpeed(); if (car_speed >= brakestartspeed && accelerating) //stop accelerating and hit the brakes { stopstart = car.GetWheelPosition(WheelPosition(0)); carinput[CarInput::THROTTLE] = 0; carinput[CarInput::BRAKE] = 1; accelerating = false; //info_output << "hitting the brakes at " << t << ", " << car_speed << std::endl; } if (!accelerating && car_speed < stopthreshold) { break; } if (!accelerating) { if (!(front_lockup_speed > 0) && car.GetWheel(WheelPosition(0)).GetRPM() < 0.001f) { front_lockup_speed = car_speed; } if (!(rear_lockup_speed > 0) && car.GetWheel(WheelPosition(3)).GetRPM() < 0.001f) { rear_lockup_speed = car_speed; } } if (t > 0 && !car.GetEngine().GetCombustion()) { error_output << "Car stalled during launch, t=" << t << std::endl; } if (i % (int)(1/dt) == 0) //every second { //info_output << t // << ", " << car_speed // << ", " << car.GetWheel(WheelPosition(0)).GetAngularVelocity() // << ", " << car.GetBrake(WheelPosition(0)).GetBrakeFactor() // << std::endl; } t += dt; i++; } btVector3 stopend = car.GetWheelPosition(WheelPosition(0)); info_output << "60-0 stopping distance "; if (abs) info_output << "(ABS)"; else info_output << "(no ABS)"; info_output << ": " << ConvertToFeet((stopend-stopstart).length()) << " ft\n" << "Wheel lockup speed " << ConvertToMPH(front_lockup_speed) << ", " << ConvertToMPH(rear_lockup_speed) << std::endl; }