void Replay::CarState::RecordFrame(const std::vector <float> & inputs, CarDynamics & car) { assert(inputbuffer.size() == CarInput::INVALID); // record inputs, delta encoding InputFrame newinputframe(frame); for (unsigned i = 0; i < CarInput::INVALID; i++) { if (inputs[i] != inputbuffer[i]) { inputbuffer[i] = inputs[i]; newinputframe.AddInput(i, inputs[i]); } } if (newinputframe.GetNumInputs() > 0) inputframes.push_back(newinputframe); // record every 30th state, input frame if (frame % 30 == 0) { std::ostringstream statestream; joeserialize::BinaryOutputSerializer serialize_output(statestream); car.Serialize(serialize_output); stateframes.push_back(StateFrame(frame)); stateframes.back().SetBinaryStateData(statestream.str()); stateframes.back().SetInputSnapshot(inputs); } frame++; }
void CarGraphics::Update(const CarDynamics & dynamics) { if (!bodynode.valid()) return; assert(dynamics.GetNumBodies() == topnode.GetNodeList().size()); unsigned i = 0; SceneNode::List & childlist = topnode.GetNodeList(); for (SceneNode::List::iterator ni = childlist.begin(); ni != childlist.end(); ++ni, ++i) { Vec3 pos = ToMathVector<float>(dynamics.GetPosition(i)); Quat rot = ToQuaternion<float>(dynamics.GetOrientation(i)); ni->GetTransform().SetTranslation(pos); ni->GetTransform().SetRotation(rot); } // brake/reverse lights SceneNode & bodynoderef = topnode.GetNode(bodynode); for (std::list<Light>::iterator i = lights.begin(); i != lights.end(); i++) { SceneNode & node = bodynoderef.GetNode(i->node); Drawable & draw = node.GetDrawList().lights_omni.get(i->draw); draw.SetDrawEnable(applied_brakes > 0); } if (brakelights.valid()) { Drawable & draw = bodynoderef.GetDrawList().lights_emissive.get(brakelights); draw.SetDrawEnable(applied_brakes > 0); } if (reverselights.valid()) { Drawable & draw = bodynoderef.GetDrawList().lights_emissive.get(reverselights); draw.SetDrawEnable(dynamics.GetTransmission().GetGear() < 0); } // steering if (steernode.valid()) { SceneNode & steernoderef = bodynoderef.GetNode(steernode); steernoderef.GetTransform().SetRotation(steer_rotation); } }
void Replay::CarState::ProcessPlayStateFrame(const StateFrame & frame, CarDynamics & car) { // process input snapshot for (unsigned i = 0; i < inputbuffer.size() && i < frame.GetInputSnapshot().size(); i++) { inputbuffer[i] = frame.GetInputSnapshot()[i]; } // process binary car state std::istringstream statestream(frame.GetBinaryStateData()); joeserialize::BinaryInputSerializer serialize_input(statestream); car.Serialize(serialize_input); }
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; */ }