A bunch of tweaks
- Add max steering lock and limit drift assist to never exceed it - Bring back tyre curve debug - Show relevant wheel debug values - Calculate camber for pacejka
This commit is contained in:
parent
6e600e9e6d
commit
0226e83010
@ -1,13 +1,13 @@
|
||||
a
|
||||
1.1
|
||||
-200
|
||||
1.5
|
||||
-20
|
||||
1700
|
||||
2000
|
||||
10
|
||||
0.5
|
||||
0
|
||||
0
|
||||
-0.5
|
||||
0
|
||||
0
|
||||
-1
|
||||
0
|
||||
0
|
||||
0
|
||||
|
|
@ -1,13 +1,13 @@
|
||||
b
|
||||
1.2
|
||||
1.5
|
||||
-200
|
||||
1400
|
||||
20
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
-2
|
||||
-10
|
||||
300
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
|
|
@ -8,3 +8,7 @@ _ :: math
|
||||
exp_smooth :: proc "contextless" (target: $T, pos: T, speed: f32, dt: f32) -> T {
|
||||
return pos + ((target - pos) * (1.0 - math.exp_f32(-speed * dt)))
|
||||
}
|
||||
|
||||
exp_smooth_angle :: proc "contextless" (target: $T, pos: T, speed: f32, dt: f32) -> T {
|
||||
return pos + (math.angle_diff(pos, target) * (1.0 - math.exp_f32(-speed * dt)))
|
||||
}
|
||||
|
@ -543,7 +543,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
},
|
||||
},
|
||||
mass = 1000,
|
||||
com_shift = physics.Vec3{0, 0.8, -0.5},
|
||||
com_shift = physics.Vec3{0, 1, -0.5},
|
||||
},
|
||||
)
|
||||
|
||||
@ -611,11 +611,16 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
assets.get_curve_1d(&g_mem.assetman, "assets/tyre_lateral.csv"),
|
||||
)
|
||||
|
||||
TURN_ANGLE_AT_HIGH_SPEED :: f32(10) * math.RAD_PER_DEG
|
||||
TURN_ANGLE_AT_LOW_SPEED :: f32(30) * math.RAD_PER_DEG
|
||||
|
||||
wheel_fl := physics.immediate_suspension_constraint(
|
||||
&world.physics_scene,
|
||||
#hash("FL", "fnv32a"),
|
||||
{
|
||||
name = name.from_string("FL"),
|
||||
turn_wheel = true,
|
||||
steer_lock = TURN_ANGLE_AT_LOW_SPEED,
|
||||
rel_pos = {-wheel_extent_x_front, wheel_y, wheel_front_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
@ -632,7 +637,9 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
&world.physics_scene,
|
||||
#hash("FR", "fnv32a"),
|
||||
{
|
||||
name = name.from_string("FR"),
|
||||
turn_wheel = true,
|
||||
steer_lock = TURN_ANGLE_AT_LOW_SPEED,
|
||||
rel_pos = {wheel_extent_x_front, wheel_y, wheel_front_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
@ -649,6 +656,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
&world.physics_scene,
|
||||
#hash("RL", "fnv32a"),
|
||||
{
|
||||
name = name.from_string("RL"),
|
||||
rel_pos = {-wheel_extent_x_back, wheel_y, wheel_back_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
@ -665,6 +673,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
&world.physics_scene,
|
||||
#hash("RR", "fnv32a"),
|
||||
{
|
||||
name = name.from_string("RR"),
|
||||
rel_pos = {wheel_extent_x_back, wheel_y, wheel_back_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
@ -706,10 +715,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
front_wheels := turn_wheels
|
||||
back_wheels := drive_wheels
|
||||
|
||||
DRIVE_IMPULSE :: 3000
|
||||
BRAKE_IMPULSE :: 10
|
||||
TURN_ANGLE_AT_HIGH_SPEED :: f32(10) * math.RAD_PER_DEG
|
||||
TURN_ANGLE_AT_LOW_SPEED :: f32(30) * math.RAD_PER_DEG
|
||||
// 68% front, 32% rear
|
||||
BRAKE_BIAS :: f32(0.68)
|
||||
|
||||
@ -745,7 +751,10 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||
}
|
||||
|
||||
car_body := physics.get_body(sim_state, world.car_handle)
|
||||
turn_vel_correction := math.smoothstep(f32(90), f32(10), linalg.length(car_body.v) * 3.6)
|
||||
car_vel_kmh := linalg.length(car_body.v) * 3.6
|
||||
LOW_SPEED :: f32(10)
|
||||
HIGH_SPEED :: f32(90)
|
||||
turn_vel_correction := 1.0 - math.saturate((car_vel_kmh - 10) / (HIGH_SPEED - LOW_SPEED))
|
||||
|
||||
turn_input := rl.GetGamepadAxisMovement(0, .LEFT_X)
|
||||
if abs(turn_input) < GAMEPAD_DEADZONE {
|
||||
@ -980,9 +989,14 @@ yaw_pitch_to_rotation :: proc "contextless" (yaw, pitch: f32) -> linalg.Matrix3f
|
||||
|
||||
follow_camera_update :: proc(world: ^World, camera: ^Car_Follow_Camera, dt: f32) {
|
||||
body := physics.get_interpolated_body(&world.physics_scene, SOLVER_CONFIG, camera.body)
|
||||
body_up := physics.body_local_to_world_vec(body, {0, 1, 0})
|
||||
|
||||
camera.follow_target = body.x + physics.Vec3{0, 4, 0}
|
||||
camera.target = body.x + physics.Vec3{0, 2.5, 0}
|
||||
// COM can be a lot lower than the center of visual mesh, offset by that first
|
||||
car_center := body.x + body_up * 1
|
||||
|
||||
// When car flips it's noticeable that camera is offset from COM, remove the offset when it sways
|
||||
camera.follow_target = car_center + physics.Vec3{0, 3, 0}
|
||||
camera.target = car_center + physics.Vec3{0, 1.5, 0}
|
||||
|
||||
delta, sense, _ := collect_camera_input()
|
||||
|
||||
@ -995,31 +1009,28 @@ follow_camera_update :: proc(world: ^World, camera: ^Car_Follow_Camera, dt: f32)
|
||||
if camera.manual_rotation_time > 0 {
|
||||
camera.manual_rotation_time -= dt
|
||||
|
||||
if !camera.has_yaw_pitch {
|
||||
camera.has_yaw_pitch = true
|
||||
camera.yaw, camera.pitch = dir_to_yaw_pitch(
|
||||
linalg.normalize0(camera.follow_target - camera.pos),
|
||||
)
|
||||
}
|
||||
|
||||
camera.yaw += delta.x * sense
|
||||
camera.pitch += delta.y * sense
|
||||
camera.pitch = math.clamp(camera.pitch, -math.PI / 2.0 + 0.0001, math.PI / 2.0 - 0.0001)
|
||||
|
||||
} else {
|
||||
v_len := linalg.length(body.v)
|
||||
if v_len >= 0.0001 {
|
||||
dir := body.v / v_len
|
||||
|
||||
speed := math.smoothstep(f32(0.2), f32(20), v_len) * 6
|
||||
// speed *= math.smoothstep(f32(6), f32(20), v_len) * 3
|
||||
|
||||
target_yaw, target_pitch := dir_to_yaw_pitch(dir)
|
||||
|
||||
camera.yaw = emath.exp_smooth_angle(target_yaw, camera.yaw, speed, dt)
|
||||
camera.pitch = emath.exp_smooth_angle(target_pitch, camera.pitch, speed, dt)
|
||||
}
|
||||
}
|
||||
|
||||
camera.pos =
|
||||
camera.follow_target +
|
||||
yaw_pitch_to_rotation(camera.yaw, camera.pitch) * rl.Vector3{0, 0, 1} * distance
|
||||
} else {
|
||||
dir := linalg.normalize0(camera.pos - camera.follow_target)
|
||||
if dir == 0 {
|
||||
dir = {0, 0, -1}
|
||||
}
|
||||
|
||||
camera.has_yaw_pitch = false
|
||||
|
||||
pos_target := camera.follow_target + dir * distance
|
||||
camera.pos = pos_target
|
||||
}
|
||||
}
|
||||
|
||||
follow_camera_to_rl :: proc(camera: Car_Follow_Camera) -> rl.Camera3D {
|
||||
|
@ -366,133 +366,121 @@ draw_debug_ui :: proc(
|
||||
}
|
||||
}
|
||||
|
||||
// active_wheels := []int{0, 1}
|
||||
|
||||
// w, h: i32 = 500, 500
|
||||
if .ACTIVE in ui.treenode(ctx, "Wheels") {
|
||||
for i in 0 ..< len(sim_state.suspension_constraints_slice) {
|
||||
s := get_interpolated_wheel(scene, config, Suspension_Constraint_Handle(i + 1))
|
||||
if s.alive {
|
||||
|
||||
// window_x: i32 = 0
|
||||
if .ACTIVE in ui.treenode(ctx, fmt.tprintf("Wheel {}", name.to_string(s.name))) {
|
||||
ui.keyval(ctx, "Spring Impulse", s.spring_impulse)
|
||||
ui.keyval(ctx, "Turn Angle", s.turn_angle * math.DEG_PER_RAD)
|
||||
ui.keyval(ctx, "Turn Assist", s.turn_assist * math.DEG_PER_RAD)
|
||||
ui.keyval(ctx, "Total Turn", (s.turn_angle + s.turn_assist) * math.DEG_PER_RAD)
|
||||
ui.keyval(ctx, "Long Slip", s.slip_ratio)
|
||||
ui.keyval(ctx, "Lat Slip", s.slip_angle)
|
||||
ui.keyval(ctx, "Camber", s.camber)
|
||||
|
||||
// for i in 0 ..< len(sim_state.suspension_constraints_slice) {
|
||||
// s := &sim_state.suspension_constraints_slice[i]
|
||||
NUM_SAMPLES :: 100
|
||||
|
||||
// if s.alive {
|
||||
// for idx in active_wheels {
|
||||
// if i == idx {
|
||||
// if ui.window(
|
||||
// ctx,
|
||||
// fmt.tprintf("Wheel %v", i),
|
||||
// ui.Rect{x = window_x, y = 0, w = w, h = h},
|
||||
// ui.Options{},
|
||||
// ) {
|
||||
// NUM_SAMPLES :: 100
|
||||
dt := f32(config.timestep) / f32(config.substreps_minus_one + 1)
|
||||
inv_dt := 1.0 / dt
|
||||
|
||||
// dt := f32(config.timestep) / f32(config.substreps_minus_one + 1)
|
||||
// inv_dt := 1.0 / dt
|
||||
if .ACTIVE in ui.treenode(ctx, "Longitudinal") {
|
||||
ui.layout_row(ctx, {-1}, 200)
|
||||
{
|
||||
ui.begin_line(ctx, ui.Color{255, 0, 0, 255})
|
||||
defer ui.end_line(ctx)
|
||||
|
||||
// {
|
||||
// ui.layout_row(ctx, {-1}, 300)
|
||||
// {
|
||||
// ui.begin_line(ctx, ui.Color{255, 0, 0, 255})
|
||||
// defer ui.end_line(ctx)
|
||||
for j in 0 ..< NUM_SAMPLES {
|
||||
alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
||||
x := alpha * 200.0 - 100.0
|
||||
|
||||
// for j in 0 ..< NUM_SAMPLES {
|
||||
// alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
||||
// x := alpha * 200.0 - 100.0
|
||||
long_friction := abs(
|
||||
pacejka_94_longitudinal(
|
||||
s.pacejka_long,
|
||||
x,
|
||||
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
),
|
||||
)
|
||||
|
||||
// long_friction := abs(
|
||||
// pacejka_94_longitudinal(
|
||||
// s.pacejka_long,
|
||||
// x,
|
||||
// max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
// ),
|
||||
// )
|
||||
ui.push_line_point(ctx, ui.Vec2f{alpha, long_friction * -0.5 + 1})
|
||||
}
|
||||
|
||||
// ui.push_line_point(
|
||||
// ctx,
|
||||
// ui.Vec2f{alpha, long_friction * -0.5 + 1},
|
||||
// )
|
||||
// }
|
||||
long_friction := abs(
|
||||
pacejka_94_longitudinal(
|
||||
s.pacejka_long,
|
||||
s.slip_ratio,
|
||||
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
),
|
||||
)
|
||||
|
||||
// long_friction := abs(
|
||||
// pacejka_94_longitudinal(
|
||||
// s.pacejka_long,
|
||||
// s.slip_ratio,
|
||||
// max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
// ),
|
||||
// )
|
||||
rect := ui.get_line(ctx).rect
|
||||
|
||||
// rect := ui.get_line(ctx).rect
|
||||
cur_point :=
|
||||
Vec2{(s.slip_ratio + 100.0) / 200.0, long_friction * -0.5 + 1} *
|
||||
Vec2{f32(rect.w), f32(rect.h)} +
|
||||
Vec2{f32(rect.x), f32(rect.y)}
|
||||
ui.draw_rect(
|
||||
ctx,
|
||||
ui.rect_from_point_extent(
|
||||
ui.Vec2{i32(cur_point.x), i32(cur_point.y)},
|
||||
2,
|
||||
),
|
||||
ui.Color{255, 255, 0, 255},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// cur_point :=
|
||||
// Vec2 {
|
||||
// (s.slip_ratio + 100.0) / 200.0,
|
||||
// long_friction * -0.5 + 1,
|
||||
// } *
|
||||
// Vec2{f32(rect.w), f32(rect.h)} +
|
||||
// Vec2{f32(rect.x), f32(rect.y)}
|
||||
// ui.draw_rect(
|
||||
// ctx,
|
||||
// ui.rect_from_point_extent(
|
||||
// ui.Vec2{i32(cur_point.x), i32(cur_point.y)},
|
||||
// 2,
|
||||
// ),
|
||||
// ui.Color{255, 255, 0, 255},
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
if .ACTIVE in ui.treenode(ctx, "Lateral") {
|
||||
ui.layout_row(ctx, {-1}, 200)
|
||||
ui.begin_line(ctx, ui.Color{0, 255, 0, 255})
|
||||
defer ui.end_line(ctx)
|
||||
|
||||
// {
|
||||
// ui.layout_row(ctx, {-1}, 300)
|
||||
// ui.begin_line(ctx, ui.Color{0, 255, 0, 255})
|
||||
// defer ui.end_line(ctx)
|
||||
for j in 0 ..< NUM_SAMPLES {
|
||||
alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
||||
x := alpha * 180.0 - 90.0
|
||||
|
||||
// for j in 0 ..< NUM_SAMPLES {
|
||||
// alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
||||
// x := alpha * 180.0 - 90.0
|
||||
lat_friction := abs(
|
||||
pacejka_94_lateral(
|
||||
s.pacejka_lat,
|
||||
x,
|
||||
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
0.0,
|
||||
),
|
||||
)
|
||||
|
||||
// lat_friction := abs(
|
||||
// pacejka_94_lateral(
|
||||
// s.pacejka_lat,
|
||||
// x,
|
||||
// max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
// 0.0,
|
||||
// ),
|
||||
// )
|
||||
ui.push_line_point(ctx, ui.Vec2f{alpha, lat_friction * -0.5 + 1})
|
||||
}
|
||||
|
||||
// ui.push_line_point(ctx, ui.Vec2f{alpha, lat_friction * -0.5 + 1})
|
||||
// }
|
||||
lat_friction := abs(
|
||||
pacejka_94_lateral(
|
||||
s.pacejka_lat,
|
||||
s.slip_angle,
|
||||
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
0.0,
|
||||
),
|
||||
)
|
||||
|
||||
// lat_friction := abs(
|
||||
// pacejka_94_lateral(
|
||||
// s.pacejka_lat,
|
||||
// s.slip_angle,
|
||||
// max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
// 0.0,
|
||||
// ),
|
||||
// )
|
||||
rect := ui.get_line(ctx).rect
|
||||
|
||||
// rect := ui.get_line(ctx).rect
|
||||
|
||||
// cur_point :=
|
||||
// Vec2{(s.slip_angle + 100.0) / 200.0, lat_friction * -0.5 + 1} *
|
||||
// Vec2{f32(rect.w), f32(rect.h)} +
|
||||
// Vec2{f32(rect.x), f32(rect.y)}
|
||||
// ui.draw_rect(
|
||||
// ctx,
|
||||
// ui.rect_from_point_extent(
|
||||
// ui.Vec2{i32(cur_point.x), i32(cur_point.y)},
|
||||
// 2,
|
||||
// ),
|
||||
// ui.Color{255, 255, 0, 255},
|
||||
// )
|
||||
// }
|
||||
|
||||
// window_x += w
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
cur_point :=
|
||||
Vec2{(s.slip_angle + 100.0) / 200.0, lat_friction * -0.5 + 1} *
|
||||
Vec2{f32(rect.w), f32(rect.h)} +
|
||||
Vec2{f32(rect.x), f32(rect.y)}
|
||||
ui.draw_rect(
|
||||
ctx,
|
||||
ui.rect_from_point_extent(
|
||||
ui.Vec2{i32(cur_point.x), i32(cur_point.y)},
|
||||
2,
|
||||
),
|
||||
ui.Color{255, 255, 0, 255},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []Vec3) {
|
||||
|
@ -55,6 +55,9 @@ pacejka_94_longitudinal :: proc(
|
||||
f_z: f32,
|
||||
s_v: f32 = 0,
|
||||
) -> f32 {
|
||||
if f_z < 0.001 {
|
||||
return 0
|
||||
}
|
||||
f_z_sq := f_z * f_z
|
||||
|
||||
C := b[0]
|
||||
@ -77,6 +80,9 @@ pacejka_94_lateral :: proc(
|
||||
f_z: f32,
|
||||
camber_angle: f32,
|
||||
) -> f32 {
|
||||
if f_z < 0.001 {
|
||||
return 0
|
||||
}
|
||||
camber_angle_sq := camber_angle * camber_angle
|
||||
|
||||
C := a[0]
|
||||
|
@ -297,7 +297,9 @@ Collision_Shape :: struct {
|
||||
|
||||
Suspension_Constraint :: struct {
|
||||
alive: bool,
|
||||
name: name.Name,
|
||||
turn_wheel: bool,
|
||||
steer_lock: f32,
|
||||
// Pos relative to the body
|
||||
rel_pos: Vec3,
|
||||
// Dir relative to the body
|
||||
@ -366,6 +368,7 @@ Suspension_Constraint :: struct {
|
||||
// Convenience for debug visualization to avoid recomputing
|
||||
slip_angle: f32,
|
||||
slip_ratio: f32,
|
||||
camber: f32,
|
||||
// Multipliers for combined friction
|
||||
slip_vec: Vec2,
|
||||
|
||||
@ -746,7 +749,10 @@ Body_Config :: struct {
|
||||
|
||||
// TODO: rename to wheel
|
||||
Suspension_Constraint_Config :: struct {
|
||||
name: name.Name,
|
||||
turn_wheel: bool,
|
||||
// Max turn angle either left or right
|
||||
steer_lock: f32,
|
||||
rel_pos: Vec3,
|
||||
rel_dir: Vec3,
|
||||
body: Body_Handle,
|
||||
@ -917,7 +923,9 @@ update_suspension_constraint_from_config :: proc(
|
||||
constraint: Suspension_Constraint_Ptr,
|
||||
config: Suspension_Constraint_Config,
|
||||
) {
|
||||
constraint.name = config.name
|
||||
constraint.turn_wheel = config.turn_wheel
|
||||
constraint.steer_lock = config.steer_lock
|
||||
constraint.rel_pos = config.rel_pos
|
||||
constraint.rel_dir = config.rel_dir
|
||||
constraint.body = config.body
|
||||
|
@ -975,7 +975,7 @@ pgs_solve_contacts :: proc(
|
||||
inv_dt: f32,
|
||||
apply_bias: bool,
|
||||
) {
|
||||
bias_rate, mass_coef, impulse_coef := calculate_soft_constraint_params(240 / 8, 1, f64(dt))
|
||||
bias_rate, mass_coef, impulse_coef := calculate_soft_constraint_params(30, 8, f64(dt))
|
||||
if !apply_bias {
|
||||
mass_coef = 1
|
||||
bias_rate = 0
|
||||
@ -1032,8 +1032,7 @@ pgs_solve_contacts :: proc(
|
||||
|
||||
bias := f32(0.0)
|
||||
|
||||
MAX_BAUMGARTE_VELOCITY :: 4.0
|
||||
|
||||
MAX_BAUMGARTE_VELOCITY :: 1000
|
||||
if separation > 0 {
|
||||
bias = separation * inv_dt
|
||||
} else if apply_bias {
|
||||
@ -1332,6 +1331,8 @@ pgs_solve_suspension :: proc(
|
||||
|
||||
if body.alive {
|
||||
if v.turn_wheel {
|
||||
v.turn_angle = math.clamp(v.turn_angle, -v.steer_lock, v.steer_lock)
|
||||
|
||||
body_forward_vec := body_local_to_world_vec(body, {0, 0, 1})
|
||||
body_right_vec := body_local_to_world_vec(body, {1, 0, 0})
|
||||
lateral_to_longitudinal_relation :=
|
||||
@ -1349,6 +1350,11 @@ pgs_solve_suspension :: proc(
|
||||
drift_amount *
|
||||
math.PI *
|
||||
0.15
|
||||
|
||||
// Clamp the assist to not go outside steer lock
|
||||
v.turn_assist =
|
||||
math.clamp(v.turn_angle + v.turn_assist, -v.steer_lock, v.steer_lock) -
|
||||
v.turn_angle
|
||||
}
|
||||
|
||||
|
||||
@ -1499,12 +1505,16 @@ pgs_solve_suspension :: proc(
|
||||
|
||||
// log.debugf("slip_vec: %v", slip_vec)
|
||||
|
||||
camber_cos := -lg.dot(wheel_get_right_vec(body, v), v.right)
|
||||
camber_angle_rad := camber_cos < 0.999999 ? math.acos(camber_cos) : 0
|
||||
v.camber = camber_angle_rad * math.DEG_PER_RAD * math.sign(v.rel_pos.x)
|
||||
|
||||
long_friction :=
|
||||
abs(
|
||||
pacejka_94_longitudinal(
|
||||
v.pacejka_long,
|
||||
slip_ratio,
|
||||
max(abs(v.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
v.spring_impulse * inv_dt * 0.001,
|
||||
),
|
||||
) *
|
||||
abs(slip_vec.y)
|
||||
@ -1513,8 +1523,8 @@ pgs_solve_suspension :: proc(
|
||||
pacejka_94_lateral(
|
||||
v.pacejka_lat,
|
||||
slip_angle,
|
||||
max(abs(v.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||
0.0,
|
||||
v.spring_impulse * inv_dt * 0.001,
|
||||
v.camber,
|
||||
),
|
||||
) *
|
||||
abs(slip_vec.x)
|
||||
|
Loading…
x
Reference in New Issue
Block a user