float speed = glm::length(velocity_local);
// Calculate weight distribution.
float weight = description.mass * G;
float wheelbase = description.cg_to_front_axle + description.cg_to_back_axle;
float front_weight = (description.cg_to_back_axle / wheelbase) * weight - (description.cg_height / wheelbase) * description.mass * acceleration_local.x;
float rear_weight = (description.cg_to_front_axle / wheelbase) * weight + (description.cg_height / wheelbase) * description.mass * acceleration_local.x;
// Assume the wheels are rolling and calculate the engine torque.
float wheel_angular_velocity = velocity_local.x / description.wheel_radius;
float transmission = description.gear_ratios[gear] * description.differential_ratio * description.transmission_efficiency;
float engine_rpm = ANGULAR_VELOCITY_TO_RPM * wheel_angular_velocity * transmission;
float engine_torque = throttle ? lerp_curve(description.torque_curve, engine_rpm) : 0.0f;
// Simplified traction model - use the torque on the wheels.
float drive_torque = engine_torque * transmission;
float traction_force = drive_torque / description.wheel_radius;
// Calculate the braking torque on the wheels.
float braking_torque = reverse ? 3500 : 0;
float braking_force = -braking_torque / description.wheel_radius * glm::sign(velocity_local.x);
// Calculate the lateral slip angles and determine the lateral cornering force.
float front_angular_velocity = car_angular_velocity * description.cg_to_front_axle;
float rear_angular_velocity = -car_angular_velocity * description.cg_to_back_axle;
float slip_angle_front = std::atan2(velocity_local.y + front_angular_velocity, std::abs(velocity_local.x)) - glm::sign(velocity_local.x) * steer_angle;
float slip_angle_rear = std::atan2(velocity_local.y + rear_angular_velocity, std::abs(velocity_local.x));
float cornering_force_front = front_weight * -description.cornering_stiffness * slip_angle_front;
float cornering_force_rear = rear_weight * -description.cornering_stiffness * slip_angle_rear;
// The wheels have a limited maximal traction before they start to slide.
float traction_circle_radius = 0.8;
glm::vec2 front_total_traction = glm::vec2(0, cornering_force_front * std::cos(steer_angle));
glm::vec2 rear_total_traction = glm::vec2(traction_force + braking_force, cornering_force_rear);
bool front_slipping = false;
float front_total_traction_length = glm::length(front_total_traction);
if (front_total_traction_length / front_weight >= traction_circle_radius)
{
front_total_traction /= front_total_traction_length;
front_total_traction *= traction_circle_radius * front_weight;
front_slipping = true;
}
bool rear_slipping = false;
float rear_total_traction_length = glm::length(rear_total_traction);
if (rear_total_traction_length / rear_weight >= traction_circle_radius)
{
rear_total_traction /= rear_total_traction_length;
rear_total_traction *= traction_circle_radius * rear_weight;
rear_slipping = true;
}
// Calculate the torque on the car body and integrate car yaw rate and orientation.
float cornering_torque_front = front_total_traction.y * description.cg_to_front_axle;
float cornering_torque_rear = rear_total_traction.y * description.cg_to_back_axle;
float car_torque = std::cos(steer_angle) * cornering_torque_front - cornering_torque_rear;
float car_angular_acceleration = car_torque / description.inertia;
car_angular_velocity += car_angular_acceleration * dt;
orientation += car_angular_velocity * dt;
// Calculate the wind drag force on the car. Simplification that the area facing the velocity direction is the front.
float area = description.height * 2.0f * description.halfwidth;
float drag_multiplier = 0.5f * description.air_density * area * description.drag_coefficient;
glm::vec2 drag_resistance = -drag_multiplier * speed * velocity_local;
// Calculate the rolling friction force on the car.
glm::vec2 rolling_resistance = glm::vec2(-description.wheel_rolling_friction * velocity_local.x, 0);
// Sum the forces on the car's CG and integrate the velocity.
glm::vec2 force = rear_total_traction + front_total_traction + drag_resistance + rolling_resistance;
acceleration_local = force / description.mass;
velocity_local += acceleration_local * dt;
// Calculate the acceleration and velocity in world coordinates and integrate world position.
float sn = std::sin(orientation);
float cs = std::cos(orientation);
acceleration.x = cs * acceleration_local.x - sn * acceleration_local.y;
acceleration.y = sn * acceleration_local.x + cs * acceleration_local.y;
velocity.x = cs * velocity_local.x - sn * velocity_local.y;
velocity.y = sn * velocity_local.x + cs * velocity_local.y;
position += velocity * dt;