Proper brake force using friction

This commit is contained in:
sergeypdev 2025-03-16 15:49:10 +04:00
parent bf7b7e6ae3
commit 8caf47003e
4 changed files with 118 additions and 52 deletions

View File

@ -390,24 +390,41 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
drive_wheels := []physics.Suspension_Constraint_Handle{wheel_rl, wheel_rr} drive_wheels := []physics.Suspension_Constraint_Handle{wheel_rl, wheel_rr}
turn_wheels := []physics.Suspension_Constraint_Handle{wheel_fl, wheel_fr} turn_wheels := []physics.Suspension_Constraint_Handle{wheel_fl, wheel_fr}
front_wheels := turn_wheels
back_wheels := drive_wheels
DRIVE_IMPULSE :: 10000 DRIVE_IMPULSE :: 2000
BRAKE_IMPULSE :: 10000 BRAKE_IMPULSE :: 500
TURN_ANGLE :: -f32(20) * math.RAD_PER_DEG TURN_ANGLE :: -f32(20) * math.RAD_PER_DEG
// 68% front, 32% rear
BRAKE_BIAS :: f32(0.68)
for wheel_handle in front_wheels {
wheel := physics.get_suspension_constraint(sim_state, wheel_handle)
wheel.brake_impulse = 0
if (rl.IsKeyDown(.S)) {
wheel.brake_impulse = BRAKE_BIAS * BRAKE_IMPULSE
}
}
for wheel_handle in back_wheels {
wheel := physics.get_suspension_constraint(sim_state, wheel_handle)
wheel.brake_impulse = 0
if (rl.IsKeyDown(.S)) {
wheel.brake_impulse = (1.0 - BRAKE_BIAS) * BRAKE_IMPULSE
}
}
for wheel_handle in drive_wheels { for wheel_handle in drive_wheels {
wheel := physics.get_suspension_constraint(sim_state, wheel_handle) wheel := physics.get_suspension_constraint(sim_state, wheel_handle)
wheel.drive_impulse = 0 wheel.drive_impulse = 0
wheel.brake_impulse = 0
if rl.IsKeyDown(.W) && !g_mem.free_cam { if rl.IsKeyDown(.W) && !g_mem.free_cam {
wheel.drive_impulse = DRIVE_IMPULSE wheel.drive_impulse = DRIVE_IMPULSE
} }
if rl.IsKeyDown(.S) && !g_mem.free_cam {
wheel.brake_impulse = BRAKE_IMPULSE
}
} }
car_body := physics.get_body(sim_state, runtime_world.car_handle) car_body := physics.get_body(sim_state, runtime_world.car_handle)

View File

@ -75,6 +75,17 @@ wheel_get_right_vec :: #force_inline proc(
return body_local_to_world_vec(body, local_right) return body_local_to_world_vec(body, local_right)
} }
wheel_get_forward_vec :: #force_inline proc(
body: Body_Ptr,
wheel: Suspension_Constraint_Ptr,
) -> Vec3 {
local_right := lg.quaternion_mul_vector3(
lg.quaternion_angle_axis(wheel.turn_angle, Vec3{0, 1, 0}),
Vec3{0, 0, 1},
)
return body_local_to_world_vec(body, local_right)
}
body_get_shape_offset_local :: proc(body: Body_Ptr) -> (offset: Vec3) { body_get_shape_offset_local :: proc(body: Body_Ptr) -> (offset: Vec3) {
#partial switch s in body.shape { #partial switch s in body.shape {
case Internal_Shape_Convex: case Internal_Shape_Convex:

View File

@ -120,49 +120,51 @@ Collision_Shape :: union {
} }
Suspension_Constraint :: struct { Suspension_Constraint :: struct {
alive: bool, alive: bool,
// Pos relative to the body // Pos relative to the body
rel_pos: Vec3, rel_pos: Vec3,
// Dir relative to the body // Dir relative to the body
rel_dir: Vec3, rel_dir: Vec3,
// Handle of the rigid body // Handle of the rigid body
body: Body_Handle, body: Body_Handle,
// Wheel radius // Wheel radius
radius: f32, radius: f32,
// Wheel mass // Wheel mass
mass: f32, mass: f32,
// Rest distance // Rest distance
rest: f32, rest: f32,
// Frequency of the spring, affects stiffness // Frequency of the spring, affects stiffness
natural_frequency: f32, natural_frequency: f32,
// How much to damp velocity of the spring // How much to damp velocity of the spring
damping: f32, damping: f32,
// Runtime state // Runtime state
// Accumulated impulse // Accumulated impulse
spring_impulse: f32, spring_impulse: f32,
lateral_impulse: f32, lateral_impulse: f32,
longitudinal_impulse: f32, longitudinal_impulse: f32,
brake_friction_impulse: f32,
// Inverse inertia along wheel rotation axis // Inverse inertia along wheel rotation axis
inv_inertia: f32, inv_inertia: f32,
// Rotation // Rotation
q: f32, q: f32,
// Angular velocity // Angular velocity
w: f32, w: f32,
hit: bool, hit: bool,
hit_point: Vec3, hit_point: Vec3,
// rel_hit_point = rel_pos + rel_dir * hit_t // rel_hit_point = rel_pos + rel_dir * hit_t
hit_t: f32, hit_t: f32,
turn_angle: f32, turn_angle: f32,
drive_impulse: f32, drive_impulse: f32,
brake_impulse: f32, // Impulse of brake pad on brake disc, set outsie
applied_impulse: Vec3, brake_impulse: f32,
applied_impulse: Vec3,
// Free list // Free list
next_plus_one: i32, next_plus_one: i32,
} }
// Index plus one, so handle 0 maps to invalid body // Index plus one, so handle 0 maps to invalid body

View File

@ -488,14 +488,48 @@ pgs_solve_suspension :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f
{wheel_world_pos, pos2}, {wheel_world_pos, pos2},
collision.plane_from_point_normal({}, collision.Vec3{0, 1, 0}), collision.plane_from_point_normal({}, collision.Vec3{0, 1, 0}),
) )
forward := body_local_to_world_vec(body, Vec3{0, 0, 1}) forward := wheel_get_forward_vec(body, v)
contact_patch_linear_vel := body_vel_at_contact_patch := body_velocity_at_point(body, v.hit_point)
body_velocity_at_point(body, v.hit_point) + (v.radius * v.w * forward)
w_normal := get_body_angular_inverse_mass(body, dir)
inv_w_normal := 1.0 / w_normal
// Drive force
if true {
total_impulse := -v.drive_impulse
v.w += v.inv_inertia * total_impulse * dt
}
// Brake force
if true {
// How strong is brake pad pushing against brake disc
brake_pad_impulse := v.brake_impulse
if brake_pad_impulse != 0 {
// TODO: figure out what's the realistic value
brake_friction := f32(1.0)
friction_clamp := brake_pad_impulse * brake_friction
incremental_impulse := (1.0 / v.inv_inertia) * -v.w
new_total_impulse := clamp(
v.brake_friction_impulse + incremental_impulse,
-friction_clamp,
friction_clamp,
)
applied_impulse := new_total_impulse - v.brake_friction_impulse
v.brake_friction_impulse = new_total_impulse
v.w += v.inv_inertia * applied_impulse
} else {
v.brake_friction_impulse = 0
}
}
w := get_body_angular_inverse_mass(body, dir)
inv_w := 1.0 / w
if v.hit { if v.hit {
// Spring force
{ {
bias_coef, mass_coef, impulse_coef := calculate_soft_constraint_params( bias_coef, mass_coef, impulse_coef := calculate_soft_constraint_params(
v.natural_frequency, v.natural_frequency,
@ -508,7 +542,7 @@ pgs_solve_suspension :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f
separation := v.rest - x separation := v.rest - x
incremental_impulse := incremental_impulse :=
-inv_w * mass_coef * (vel + separation * bias_coef) - -inv_w_normal * mass_coef * (vel + separation * bias_coef) -
impulse_coef * v.spring_impulse impulse_coef * v.spring_impulse
v.spring_impulse += incremental_impulse v.spring_impulse += incremental_impulse
@ -517,6 +551,9 @@ pgs_solve_suspension :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f
right := wheel_get_right_vec(body, v) right := wheel_get_right_vec(body, v)
contact_patch_linear_vel :=
body_vel_at_contact_patch + (v.radius * v.w * forward)
// Longitudinal friction // Longitudinal friction
if true { if true {
vel_long := lg.dot(contact_patch_linear_vel, forward) vel_long := lg.dot(contact_patch_linear_vel, forward)
@ -524,7 +561,12 @@ pgs_solve_suspension :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f
friction := f32(1) friction := f32(1)
friction_clamp := abs(v.spring_impulse) * friction friction_clamp := abs(v.spring_impulse) * friction
incremental_impulse := -v.inv_inertia * vel_long w_body := get_body_inverse_mass(body, forward, v.hit_point)
w_long := w_body + v.inv_inertia
inv_w_long := 1.0 / w_long
incremental_impulse := -inv_w_long * vel_long
new_total_impulse := clamp( new_total_impulse := clamp(
v.longitudinal_impulse + incremental_impulse, v.longitudinal_impulse + incremental_impulse,
-friction_clamp, -friction_clamp,
@ -533,30 +575,19 @@ pgs_solve_suspension :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f
applied_impulse := new_total_impulse - v.longitudinal_impulse applied_impulse := new_total_impulse - v.longitudinal_impulse
v.longitudinal_impulse = new_total_impulse v.longitudinal_impulse = new_total_impulse
apply_velocity_correction(body, applied_impulse * forward, v.hit_point)
v.w += v.inv_inertia * applied_impulse v.w += v.inv_inertia * applied_impulse
} }
// Drive forces
if true {
total_impulse := v.drive_impulse - v.brake_impulse
apply_velocity_correction(
body,
total_impulse * forward * dt,
wheel_world_pos,
)
}
// Lateral friction // Lateral friction
if true { if true {
vel_contact := body_velocity_at_point(body, wheel_world_pos) vel_contact := body_vel_at_contact_patch
lateral_vel := lg.dot(right, vel_contact) lateral_vel := lg.dot(right, vel_contact)
friction := f32(1) friction := f32(1)
friction_clamp := -v.spring_impulse * friction friction_clamp := -v.spring_impulse * friction
incremental_impulse := -inv_w * lateral_vel incremental_impulse := -inv_w_normal * lateral_vel
new_total_impulse := clamp( new_total_impulse := clamp(
v.lateral_impulse + incremental_impulse, v.lateral_impulse + incremental_impulse,
-friction_clamp, -friction_clamp,
@ -565,7 +596,7 @@ pgs_solve_suspension :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f
applied_impulse := new_total_impulse - v.lateral_impulse applied_impulse := new_total_impulse - v.lateral_impulse
v.lateral_impulse = new_total_impulse v.lateral_impulse = new_total_impulse
apply_velocity_correction(body, applied_impulse * right, wheel_world_pos) apply_velocity_correction(body, applied_impulse * right, v.hit_point)
} }
} else { } else {
v.lateral_impulse = 0 v.lateral_impulse = 0
@ -618,6 +649,8 @@ pgs_substep :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f32, inv_d
if s.hit { if s.hit {
body := get_body(sim_state, s.body) body := get_body(sim_state, s.body)
p := body_local_to_world(body, s.rel_pos) p := body_local_to_world(body, s.rel_pos)
hit_p := body_local_to_world(body, s.rel_pos + s.rel_dir * s.hit_t)
forward := wheel_get_forward_vec(body, s)
right := wheel_get_right_vec(body, s) right := wheel_get_right_vec(body, s)
apply_velocity_correction( apply_velocity_correction(
@ -627,8 +660,11 @@ pgs_substep :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f32, inv_d
) )
apply_velocity_correction(body, s.lateral_impulse * right, p) apply_velocity_correction(body, s.lateral_impulse * right, p)
apply_velocity_correction(body, s.longitudinal_impulse * forward, hit_p)
s.w += s.inv_inertia * s.longitudinal_impulse s.w += s.inv_inertia * s.longitudinal_impulse
} }
s.w += s.inv_inertia * s.brake_friction_impulse
} }
} }