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
|
a
|
||||||
1.1
|
1.5
|
||||||
-200
|
-20
|
||||||
1700
|
1700
|
||||||
2000
|
2000
|
||||||
10
|
0.5
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
-0.5
|
0
|
||||||
0
|
-1
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
|
|
@ -1,13 +1,13 @@
|
|||||||
b
|
b
|
||||||
1.2
|
1.5
|
||||||
-200
|
-200
|
||||||
1400
|
1400
|
||||||
20
|
-10
|
||||||
1
|
300
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
-2
|
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 {
|
exp_smooth :: proc "contextless" (target: $T, pos: T, speed: f32, dt: f32) -> T {
|
||||||
return pos + ((target - pos) * (1.0 - math.exp_f32(-speed * dt)))
|
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,
|
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"),
|
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(
|
wheel_fl := physics.immediate_suspension_constraint(
|
||||||
&world.physics_scene,
|
&world.physics_scene,
|
||||||
#hash("FL", "fnv32a"),
|
#hash("FL", "fnv32a"),
|
||||||
{
|
{
|
||||||
|
name = name.from_string("FL"),
|
||||||
turn_wheel = true,
|
turn_wheel = true,
|
||||||
|
steer_lock = TURN_ANGLE_AT_LOW_SPEED,
|
||||||
rel_pos = {-wheel_extent_x_front, wheel_y, wheel_front_z},
|
rel_pos = {-wheel_extent_x_front, wheel_y, wheel_front_z},
|
||||||
rel_dir = {0, -1, 0},
|
rel_dir = {0, -1, 0},
|
||||||
radius = radius,
|
radius = radius,
|
||||||
@ -632,7 +637,9 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
&world.physics_scene,
|
&world.physics_scene,
|
||||||
#hash("FR", "fnv32a"),
|
#hash("FR", "fnv32a"),
|
||||||
{
|
{
|
||||||
|
name = name.from_string("FR"),
|
||||||
turn_wheel = true,
|
turn_wheel = true,
|
||||||
|
steer_lock = TURN_ANGLE_AT_LOW_SPEED,
|
||||||
rel_pos = {wheel_extent_x_front, wheel_y, wheel_front_z},
|
rel_pos = {wheel_extent_x_front, wheel_y, wheel_front_z},
|
||||||
rel_dir = {0, -1, 0},
|
rel_dir = {0, -1, 0},
|
||||||
radius = radius,
|
radius = radius,
|
||||||
@ -649,6 +656,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
&world.physics_scene,
|
&world.physics_scene,
|
||||||
#hash("RL", "fnv32a"),
|
#hash("RL", "fnv32a"),
|
||||||
{
|
{
|
||||||
|
name = name.from_string("RL"),
|
||||||
rel_pos = {-wheel_extent_x_back, wheel_y, wheel_back_z},
|
rel_pos = {-wheel_extent_x_back, wheel_y, wheel_back_z},
|
||||||
rel_dir = {0, -1, 0},
|
rel_dir = {0, -1, 0},
|
||||||
radius = radius,
|
radius = radius,
|
||||||
@ -665,6 +673,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
&world.physics_scene,
|
&world.physics_scene,
|
||||||
#hash("RR", "fnv32a"),
|
#hash("RR", "fnv32a"),
|
||||||
{
|
{
|
||||||
|
name = name.from_string("RR"),
|
||||||
rel_pos = {wheel_extent_x_back, wheel_y, wheel_back_z},
|
rel_pos = {wheel_extent_x_back, wheel_y, wheel_back_z},
|
||||||
rel_dir = {0, -1, 0},
|
rel_dir = {0, -1, 0},
|
||||||
radius = radius,
|
radius = radius,
|
||||||
@ -706,10 +715,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
front_wheels := turn_wheels
|
front_wheels := turn_wheels
|
||||||
back_wheels := drive_wheels
|
back_wheels := drive_wheels
|
||||||
|
|
||||||
DRIVE_IMPULSE :: 3000
|
|
||||||
BRAKE_IMPULSE :: 10
|
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
|
// 68% front, 32% rear
|
||||||
BRAKE_BIAS :: f32(0.68)
|
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)
|
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)
|
turn_input := rl.GetGamepadAxisMovement(0, .LEFT_X)
|
||||||
if abs(turn_input) < GAMEPAD_DEADZONE {
|
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) {
|
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 := 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}
|
// COM can be a lot lower than the center of visual mesh, offset by that first
|
||||||
camera.target = body.x + physics.Vec3{0, 2.5, 0}
|
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()
|
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 {
|
if camera.manual_rotation_time > 0 {
|
||||||
camera.manual_rotation_time -= dt
|
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.yaw += delta.x * sense
|
||||||
camera.pitch += delta.y * sense
|
camera.pitch += delta.y * sense
|
||||||
camera.pitch = math.clamp(camera.pitch, -math.PI / 2.0 + 0.0001, math.PI / 2.0 - 0.0001)
|
camera.pitch = math.clamp(camera.pitch, -math.PI / 2.0 + 0.0001, math.PI / 2.0 - 0.0001)
|
||||||
|
|
||||||
camera.pos =
|
|
||||||
camera.follow_target +
|
|
||||||
yaw_pitch_to_rotation(camera.yaw, camera.pitch) * rl.Vector3{0, 0, 1} * distance
|
|
||||||
} else {
|
} else {
|
||||||
dir := linalg.normalize0(camera.pos - camera.follow_target)
|
v_len := linalg.length(body.v)
|
||||||
if dir == 0 {
|
if v_len >= 0.0001 {
|
||||||
dir = {0, 0, -1}
|
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.has_yaw_pitch = false
|
|
||||||
|
|
||||||
pos_target := camera.follow_target + dir * distance
|
|
||||||
camera.pos = pos_target
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
camera.pos =
|
||||||
|
camera.follow_target +
|
||||||
|
yaw_pitch_to_rotation(camera.yaw, camera.pitch) * rl.Vector3{0, 0, 1} * distance
|
||||||
}
|
}
|
||||||
|
|
||||||
follow_camera_to_rl :: proc(camera: Car_Follow_Camera) -> rl.Camera3D {
|
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) {
|
NUM_SAMPLES :: 100
|
||||||
// s := &sim_state.suspension_constraints_slice[i]
|
|
||||||
|
|
||||||
// if s.alive {
|
dt := f32(config.timestep) / f32(config.substreps_minus_one + 1)
|
||||||
// for idx in active_wheels {
|
inv_dt := 1.0 / dt
|
||||||
// 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)
|
if .ACTIVE in ui.treenode(ctx, "Longitudinal") {
|
||||||
// inv_dt := 1.0 / dt
|
ui.layout_row(ctx, {-1}, 200)
|
||||||
|
{
|
||||||
|
ui.begin_line(ctx, ui.Color{255, 0, 0, 255})
|
||||||
|
defer ui.end_line(ctx)
|
||||||
|
|
||||||
// {
|
for j in 0 ..< NUM_SAMPLES {
|
||||||
// ui.layout_row(ctx, {-1}, 300)
|
alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
||||||
// {
|
x := alpha * 200.0 - 100.0
|
||||||
// ui.begin_line(ctx, ui.Color{255, 0, 0, 255})
|
|
||||||
// defer ui.end_line(ctx)
|
|
||||||
|
|
||||||
// for j in 0 ..< NUM_SAMPLES {
|
long_friction := abs(
|
||||||
// alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
pacejka_94_longitudinal(
|
||||||
// x := alpha * 200.0 - 100.0
|
s.pacejka_long,
|
||||||
|
x,
|
||||||
|
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
// long_friction := abs(
|
ui.push_line_point(ctx, ui.Vec2f{alpha, long_friction * -0.5 + 1})
|
||||||
// pacejka_94_longitudinal(
|
}
|
||||||
// s.pacejka_long,
|
|
||||||
// x,
|
|
||||||
// max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
|
|
||||||
// ui.push_line_point(
|
long_friction := abs(
|
||||||
// ctx,
|
pacejka_94_longitudinal(
|
||||||
// ui.Vec2f{alpha, long_friction * -0.5 + 1},
|
s.pacejka_long,
|
||||||
// )
|
s.slip_ratio,
|
||||||
// }
|
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
// long_friction := abs(
|
rect := ui.get_line(ctx).rect
|
||||||
// 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
|
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 :=
|
if .ACTIVE in ui.treenode(ctx, "Lateral") {
|
||||||
// Vec2 {
|
ui.layout_row(ctx, {-1}, 200)
|
||||||
// (s.slip_ratio + 100.0) / 200.0,
|
ui.begin_line(ctx, ui.Color{0, 255, 0, 255})
|
||||||
// long_friction * -0.5 + 1,
|
defer ui.end_line(ctx)
|
||||||
// } *
|
|
||||||
// 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},
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// {
|
for j in 0 ..< NUM_SAMPLES {
|
||||||
// ui.layout_row(ctx, {-1}, 300)
|
alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
||||||
// ui.begin_line(ctx, ui.Color{0, 255, 0, 255})
|
x := alpha * 180.0 - 90.0
|
||||||
// defer ui.end_line(ctx)
|
|
||||||
|
|
||||||
// for j in 0 ..< NUM_SAMPLES {
|
lat_friction := abs(
|
||||||
// alpha := f32(j) / f32(NUM_SAMPLES - 1)
|
pacejka_94_lateral(
|
||||||
// x := alpha * 180.0 - 90.0
|
s.pacejka_lat,
|
||||||
|
x,
|
||||||
|
max(abs(s.spring_impulse), 0.001) * inv_dt * 0.001,
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
// lat_friction := abs(
|
ui.push_line_point(ctx, ui.Vec2f{alpha, lat_friction * -0.5 + 1})
|
||||||
// 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})
|
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(
|
rect := ui.get_line(ctx).rect
|
||||||
// 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
|
cur_point :=
|
||||||
|
Vec2{(s.slip_angle + 100.0) / 200.0, lat_friction * -0.5 + 1} *
|
||||||
// cur_point :=
|
Vec2{f32(rect.w), f32(rect.h)} +
|
||||||
// Vec2{(s.slip_angle + 100.0) / 200.0, lat_friction * -0.5 + 1} *
|
Vec2{f32(rect.x), f32(rect.y)}
|
||||||
// Vec2{f32(rect.w), f32(rect.h)} +
|
ui.draw_rect(
|
||||||
// Vec2{f32(rect.x), f32(rect.y)}
|
ctx,
|
||||||
// ui.draw_rect(
|
ui.rect_from_point_extent(
|
||||||
// ctx,
|
ui.Vec2{i32(cur_point.x), i32(cur_point.y)},
|
||||||
// ui.rect_from_point_extent(
|
2,
|
||||||
// ui.Vec2{i32(cur_point.x), i32(cur_point.y)},
|
),
|
||||||
// 2,
|
ui.Color{255, 255, 0, 255},
|
||||||
// ),
|
)
|
||||||
// ui.Color{255, 255, 0, 255},
|
}
|
||||||
// )
|
}
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
// window_x += w
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []Vec3) {
|
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []Vec3) {
|
||||||
|
@ -55,6 +55,9 @@ pacejka_94_longitudinal :: proc(
|
|||||||
f_z: f32,
|
f_z: f32,
|
||||||
s_v: f32 = 0,
|
s_v: f32 = 0,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
|
if f_z < 0.001 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
f_z_sq := f_z * f_z
|
f_z_sq := f_z * f_z
|
||||||
|
|
||||||
C := b[0]
|
C := b[0]
|
||||||
@ -77,6 +80,9 @@ pacejka_94_lateral :: proc(
|
|||||||
f_z: f32,
|
f_z: f32,
|
||||||
camber_angle: f32,
|
camber_angle: f32,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
|
if f_z < 0.001 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
camber_angle_sq := camber_angle * camber_angle
|
camber_angle_sq := camber_angle * camber_angle
|
||||||
|
|
||||||
C := a[0]
|
C := a[0]
|
||||||
|
@ -297,7 +297,9 @@ Collision_Shape :: struct {
|
|||||||
|
|
||||||
Suspension_Constraint :: struct {
|
Suspension_Constraint :: struct {
|
||||||
alive: bool,
|
alive: bool,
|
||||||
|
name: name.Name,
|
||||||
turn_wheel: bool,
|
turn_wheel: bool,
|
||||||
|
steer_lock: f32,
|
||||||
// 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
|
||||||
@ -366,6 +368,7 @@ Suspension_Constraint :: struct {
|
|||||||
// Convenience for debug visualization to avoid recomputing
|
// Convenience for debug visualization to avoid recomputing
|
||||||
slip_angle: f32,
|
slip_angle: f32,
|
||||||
slip_ratio: f32,
|
slip_ratio: f32,
|
||||||
|
camber: f32,
|
||||||
// Multipliers for combined friction
|
// Multipliers for combined friction
|
||||||
slip_vec: Vec2,
|
slip_vec: Vec2,
|
||||||
|
|
||||||
@ -746,7 +749,10 @@ Body_Config :: struct {
|
|||||||
|
|
||||||
// TODO: rename to wheel
|
// TODO: rename to wheel
|
||||||
Suspension_Constraint_Config :: struct {
|
Suspension_Constraint_Config :: struct {
|
||||||
|
name: name.Name,
|
||||||
turn_wheel: bool,
|
turn_wheel: bool,
|
||||||
|
// Max turn angle either left or right
|
||||||
|
steer_lock: f32,
|
||||||
rel_pos: Vec3,
|
rel_pos: Vec3,
|
||||||
rel_dir: Vec3,
|
rel_dir: Vec3,
|
||||||
body: Body_Handle,
|
body: Body_Handle,
|
||||||
@ -917,7 +923,9 @@ update_suspension_constraint_from_config :: proc(
|
|||||||
constraint: Suspension_Constraint_Ptr,
|
constraint: Suspension_Constraint_Ptr,
|
||||||
config: Suspension_Constraint_Config,
|
config: Suspension_Constraint_Config,
|
||||||
) {
|
) {
|
||||||
|
constraint.name = config.name
|
||||||
constraint.turn_wheel = config.turn_wheel
|
constraint.turn_wheel = config.turn_wheel
|
||||||
|
constraint.steer_lock = config.steer_lock
|
||||||
constraint.rel_pos = config.rel_pos
|
constraint.rel_pos = config.rel_pos
|
||||||
constraint.rel_dir = config.rel_dir
|
constraint.rel_dir = config.rel_dir
|
||||||
constraint.body = config.body
|
constraint.body = config.body
|
||||||
|
@ -975,7 +975,7 @@ pgs_solve_contacts :: proc(
|
|||||||
inv_dt: f32,
|
inv_dt: f32,
|
||||||
apply_bias: bool,
|
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 {
|
if !apply_bias {
|
||||||
mass_coef = 1
|
mass_coef = 1
|
||||||
bias_rate = 0
|
bias_rate = 0
|
||||||
@ -1032,8 +1032,7 @@ pgs_solve_contacts :: proc(
|
|||||||
|
|
||||||
bias := f32(0.0)
|
bias := f32(0.0)
|
||||||
|
|
||||||
MAX_BAUMGARTE_VELOCITY :: 4.0
|
MAX_BAUMGARTE_VELOCITY :: 1000
|
||||||
|
|
||||||
if separation > 0 {
|
if separation > 0 {
|
||||||
bias = separation * inv_dt
|
bias = separation * inv_dt
|
||||||
} else if apply_bias {
|
} else if apply_bias {
|
||||||
@ -1332,6 +1331,8 @@ pgs_solve_suspension :: proc(
|
|||||||
|
|
||||||
if body.alive {
|
if body.alive {
|
||||||
if v.turn_wheel {
|
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_forward_vec := body_local_to_world_vec(body, {0, 0, 1})
|
||||||
body_right_vec := body_local_to_world_vec(body, {1, 0, 0})
|
body_right_vec := body_local_to_world_vec(body, {1, 0, 0})
|
||||||
lateral_to_longitudinal_relation :=
|
lateral_to_longitudinal_relation :=
|
||||||
@ -1349,6 +1350,11 @@ pgs_solve_suspension :: proc(
|
|||||||
drift_amount *
|
drift_amount *
|
||||||
math.PI *
|
math.PI *
|
||||||
0.15
|
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)
|
// 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 :=
|
long_friction :=
|
||||||
abs(
|
abs(
|
||||||
pacejka_94_longitudinal(
|
pacejka_94_longitudinal(
|
||||||
v.pacejka_long,
|
v.pacejka_long,
|
||||||
slip_ratio,
|
slip_ratio,
|
||||||
max(abs(v.spring_impulse), 0.001) * inv_dt * 0.001,
|
v.spring_impulse * inv_dt * 0.001,
|
||||||
),
|
),
|
||||||
) *
|
) *
|
||||||
abs(slip_vec.y)
|
abs(slip_vec.y)
|
||||||
@ -1513,8 +1523,8 @@ pgs_solve_suspension :: proc(
|
|||||||
pacejka_94_lateral(
|
pacejka_94_lateral(
|
||||||
v.pacejka_lat,
|
v.pacejka_lat,
|
||||||
slip_angle,
|
slip_angle,
|
||||||
max(abs(v.spring_impulse), 0.001) * inv_dt * 0.001,
|
v.spring_impulse * inv_dt * 0.001,
|
||||||
0.0,
|
v.camber,
|
||||||
),
|
),
|
||||||
) *
|
) *
|
||||||
abs(slip_vec.x)
|
abs(slip_vec.x)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user