Add tyre friction debug visualization and tweak tyres to be more slidy

This commit is contained in:
sergeypdev 2025-05-02 20:32:13 +04:00
parent 02d4a7aac5
commit 08b6748d76
7 changed files with 173 additions and 35 deletions

View File

@ -1,6 +1,6 @@
a
1.5
0
-80
1100
1100
10

1 a
2 1.5
3 0 -80
4 1100
5 1100
6 10

View File

@ -1,6 +1,6 @@
b
1.5
-2.0
1.6
-80
1100
0
300

1 b
2 1.5 1.6
3 -2.0 -80
4 1100
5 0
6 300

View File

@ -440,7 +440,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
axle = physics.Drive_Axle_Config {
wheels = {wheel_rl, wheel_rr},
wheel_count = 2,
diff_type = .Fixed,
diff_type = .Open,
final_drive_ratio = 4.1,
},
},
@ -586,6 +586,8 @@ orbit_camera_to_rl :: proc(camera: Orbit_Camera) -> rl.Camera3D {
update :: proc() {
tracy.Zone()
ui.begin(&g_mem.ui_context)
if rl.IsKeyPressed(.TAB) {
g_mem.editor = !g_mem.editor
}
@ -670,28 +672,6 @@ update :: proc() {
}
}
{
ui.begin(&g_mem.ui_context)
defer ui.end(&g_mem.ui_context)
if ui.window(
&g_mem.ui_context,
"Hello, world",
ui.Rect{x = 0, y = 0, w = 100, h = 100},
ui.Options{.AUTO_SIZE},
) {
ui.layout_column(&g_mem.ui_context)
ui.text(&g_mem.ui_context, "It Works!")
ui.begin_line(&g_mem.ui_context, ui.Color{255, 0, 0, 255})
defer ui.end_line(&g_mem.ui_context)
ui.push_line_point(&g_mem.ui_context, {0, 0})
ui.push_line_point(&g_mem.ui_context, {1, 1})
}
}
update_runtime_world(get_runtime_world(), dt)
}
}
@ -768,6 +748,7 @@ draw :: proc() {
// rl.DrawGrid(100, 1)
physics.draw_debug_scene(&world.physics_scene)
physics.draw_debug_ui(&g_mem.ui_context, &world.physics_scene, SOLVER_CONFIG)
box1_mat := linalg.Matrix4f32(1)
box1_mat = linalg.matrix4_rotate(45 * math.RAD_PER_DEG, rl.Vector3{0, 1, 0}) * box1_mat
@ -887,7 +868,10 @@ draw :: proc() {
}
}
{
ui.end(&g_mem.ui_context)
rl.BeginMode2D(ui_camera())
defer rl.EndMode2D()

View File

@ -1,10 +1,12 @@
package physics
import "core:fmt"
import "core:log"
import "core:math"
import lg "core:math/linalg"
import "game:debug"
import "game:halfedge"
import "game:ui"
import "libs:tracy"
import rl "vendor:raylib"
import "vendor:raylib/rlgl"
@ -144,6 +146,141 @@ draw_debug_scene :: proc(scene: ^Scene) {
}
}
draw_debug_ui :: proc(ctx: ^ui.Context, scene: ^Scene, config: Solver_Config) {
tracy.Zone()
sim_state := get_sim_state(scene)
active_wheels := []int{2, 3}
w, h: i32 = 200, 200
window_x: i32 = 0
for i in 0 ..< len(sim_state.suspension_constraints_slice) {
s := &sim_state.suspension_constraints_slice[i]
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{.AUTO_SIZE},
) {
NUM_SAMPLES :: 100
dt := f32(config.timestep) / f32(config.substreps_minus_one + 1)
inv_dt := 1.0 / dt
{
// ui.layout_row(ctx, {0}, 200)
{
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
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},
)
}
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
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},
)
}
}
{
// ui.layout_row(ctx, {0}, 200)
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
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})
}
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
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
}
}
}
}
}
}
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []Vec3) {
for i in 0 ..< len(points) {
points[i] = body_local_to_world(body, points[i])

View File

@ -175,6 +175,12 @@ Suspension_Constraint :: struct {
brake_impulse: f32,
applied_impulse: Vec3,
// Convenience for debug visualization to avoid recomputing
slip_angle: f32,
slip_ratio: f32,
// Multipliers for combined friction
slip_vec: Vec2,
// Free list
next_plus_one: i32,
}

View File

@ -720,6 +720,7 @@ pgs_solve_suspension :: proc(
v.hit_point = wheel_world_pos + dir * v.hit_t
forward := wheel_get_forward_vec(body, v)
right := wheel_get_right_vec(body, v)
body_vel_at_contact_patch := body_velocity_at_point(body, v.hit_point)
@ -780,20 +781,24 @@ pgs_solve_suspension :: proc(
apply_velocity_correction(body, incremental_impulse * dir, wheel_world_pos)
}
right := wheel_get_right_vec(body, v)
// Positive means spinning forward
wheel_spin_vel := -v.radius * v.w
ground_vel := lg.dot(body_vel_at_contact_patch, forward)
ground_vel_x := lg.dot(body_vel_at_contact_patch, right)
ground_vel_y := lg.dot(body_vel_at_contact_patch, forward)
// contact_patch_linear_vel :=
// body_vel_at_contact_patch + (v.radius * v.w * forward)
slip_ratio :=
ground_vel == 0 ? 0 : clamp(wheel_spin_vel / ground_vel - 1, -1, 1) * 100.0
slip_angle :=
-lg.angle_between(forward, body_vel_at_contact_patch) * math.DEG_PER_RAD
ground_vel_y == 0 ? 0 : clamp(wheel_spin_vel / ground_vel_y - 1, -1, 1) * 100.0
MAX_SLIP_LEN :: f32(1.0)
slip_angle :=
-lg.angle_between(Vec2{0, 1}, Vec2{ground_vel_x, ground_vel_y}) *
math.DEG_PER_RAD
v.slip_ratio = slip_ratio
v.slip_angle = slip_angle
MAX_SLIP_LEN :: f32(2.0)
slip_vec := Vec2 {
slip_angle / PACEJKA94_LATERAL_PEAK_X / MAX_SLIP_LEN,
@ -804,6 +809,8 @@ pgs_solve_suspension :: proc(
slip_len = slip_len == 0 ? 0 : min(slip_len, 1) / slip_len
slip_vec *= slip_len
v.slip_vec = slip_vec
// log.debugf("slip_vec: %v", slip_vec)
long_friction :=
@ -829,7 +836,7 @@ pgs_solve_suspension :: proc(
// Longitudinal friction
if true {
// Wheel linear velocity relative to ground
relative_vel := ground_vel - wheel_spin_vel
relative_vel := ground_vel_y - wheel_spin_vel
friction_clamp := abs(v.spring_impulse) * long_friction

View File

@ -345,6 +345,10 @@ rect_overlaps_vec2 :: proc(r: Rect, p: Vec2) -> bool {
return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h
}
rect_from_point_extent :: proc(p, e: Vec2) -> Rect {
return Rect{x = p.x - e.x, y = p.y - e.y, w = e.x * 2, h = e.y * 2}
}
@(private)
default_draw_frame :: proc(ctx: ^Context, rect: Rect, colorid: Color_Type) {
draw_rect(ctx, rect, ctx.style.colors[colorid])
@ -836,7 +840,7 @@ push_line_point :: proc(ctx: ^Context, p: Vec2f) {
}
get_line_segments :: proc(ctx: ^Context, first_segment: i32, num_segments: i32) -> []Vec2f {
return ctx.line_segments_pool[first_segment:num_segments]
return ctx.line_segments_pool[first_segment:first_segment + num_segments]
}
/*============================================================================