Add tyre friction debug visualization and tweak tyres to be more slidy
This commit is contained in:
parent
02d4a7aac5
commit
08b6748d76
@ -1,6 +1,6 @@
|
|||||||
a
|
a
|
||||||
1.5
|
1.5
|
||||||
0
|
-80
|
||||||
1100
|
1100
|
||||||
1100
|
1100
|
||||||
10
|
10
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
b
|
b
|
||||||
1.5
|
1.6
|
||||||
-2.0
|
-80
|
||||||
1100
|
1100
|
||||||
0
|
0
|
||||||
300
|
300
|
||||||
|
|
@ -440,7 +440,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
|||||||
axle = physics.Drive_Axle_Config {
|
axle = physics.Drive_Axle_Config {
|
||||||
wheels = {wheel_rl, wheel_rr},
|
wheels = {wheel_rl, wheel_rr},
|
||||||
wheel_count = 2,
|
wheel_count = 2,
|
||||||
diff_type = .Fixed,
|
diff_type = .Open,
|
||||||
final_drive_ratio = 4.1,
|
final_drive_ratio = 4.1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -586,6 +586,8 @@ orbit_camera_to_rl :: proc(camera: Orbit_Camera) -> rl.Camera3D {
|
|||||||
update :: proc() {
|
update :: proc() {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
|
|
||||||
|
ui.begin(&g_mem.ui_context)
|
||||||
|
|
||||||
if rl.IsKeyPressed(.TAB) {
|
if rl.IsKeyPressed(.TAB) {
|
||||||
g_mem.editor = !g_mem.editor
|
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)
|
update_runtime_world(get_runtime_world(), dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -768,6 +748,7 @@ draw :: proc() {
|
|||||||
// rl.DrawGrid(100, 1)
|
// rl.DrawGrid(100, 1)
|
||||||
|
|
||||||
physics.draw_debug_scene(&world.physics_scene)
|
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.Matrix4f32(1)
|
||||||
box1_mat = linalg.matrix4_rotate(45 * math.RAD_PER_DEG, rl.Vector3{0, 1, 0}) * box1_mat
|
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())
|
rl.BeginMode2D(ui_camera())
|
||||||
defer rl.EndMode2D()
|
defer rl.EndMode2D()
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package physics
|
package physics
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:math"
|
import "core:math"
|
||||||
import lg "core:math/linalg"
|
import lg "core:math/linalg"
|
||||||
import "game:debug"
|
import "game:debug"
|
||||||
import "game:halfedge"
|
import "game:halfedge"
|
||||||
|
import "game:ui"
|
||||||
import "libs:tracy"
|
import "libs:tracy"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
import "vendor:raylib/rlgl"
|
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) {
|
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []Vec3) {
|
||||||
for i in 0 ..< len(points) {
|
for i in 0 ..< len(points) {
|
||||||
points[i] = body_local_to_world(body, points[i])
|
points[i] = body_local_to_world(body, points[i])
|
||||||
|
@ -175,6 +175,12 @@ Suspension_Constraint :: struct {
|
|||||||
brake_impulse: f32,
|
brake_impulse: f32,
|
||||||
applied_impulse: Vec3,
|
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
|
// Free list
|
||||||
next_plus_one: i32,
|
next_plus_one: i32,
|
||||||
}
|
}
|
||||||
|
@ -720,6 +720,7 @@ pgs_solve_suspension :: proc(
|
|||||||
v.hit_point = wheel_world_pos + dir * v.hit_t
|
v.hit_point = wheel_world_pos + dir * v.hit_t
|
||||||
|
|
||||||
forward := wheel_get_forward_vec(body, v)
|
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)
|
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)
|
apply_velocity_correction(body, incremental_impulse * dir, wheel_world_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
right := wheel_get_right_vec(body, v)
|
|
||||||
|
|
||||||
// Positive means spinning forward
|
// Positive means spinning forward
|
||||||
wheel_spin_vel := -v.radius * v.w
|
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 :=
|
// contact_patch_linear_vel :=
|
||||||
// body_vel_at_contact_patch + (v.radius * v.w * forward)
|
// body_vel_at_contact_patch + (v.radius * v.w * forward)
|
||||||
|
|
||||||
slip_ratio :=
|
slip_ratio :=
|
||||||
ground_vel == 0 ? 0 : clamp(wheel_spin_vel / ground_vel - 1, -1, 1) * 100.0
|
ground_vel_y == 0 ? 0 : clamp(wheel_spin_vel / ground_vel_y - 1, -1, 1) * 100.0
|
||||||
slip_angle :=
|
|
||||||
-lg.angle_between(forward, body_vel_at_contact_patch) * math.DEG_PER_RAD
|
|
||||||
|
|
||||||
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_vec := Vec2 {
|
||||||
slip_angle / PACEJKA94_LATERAL_PEAK_X / MAX_SLIP_LEN,
|
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_len = slip_len == 0 ? 0 : min(slip_len, 1) / slip_len
|
||||||
slip_vec *= slip_len
|
slip_vec *= slip_len
|
||||||
|
|
||||||
|
v.slip_vec = slip_vec
|
||||||
|
|
||||||
// log.debugf("slip_vec: %v", slip_vec)
|
// log.debugf("slip_vec: %v", slip_vec)
|
||||||
|
|
||||||
long_friction :=
|
long_friction :=
|
||||||
@ -829,7 +836,7 @@ pgs_solve_suspension :: proc(
|
|||||||
// Longitudinal friction
|
// Longitudinal friction
|
||||||
if true {
|
if true {
|
||||||
// Wheel linear velocity relative to ground
|
// 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
|
friction_clamp := abs(v.spring_impulse) * long_friction
|
||||||
|
|
||||||
|
@ -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
|
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)
|
@(private)
|
||||||
default_draw_frame :: proc(ctx: ^Context, rect: Rect, colorid: Color_Type) {
|
default_draw_frame :: proc(ctx: ^Context, rect: Rect, colorid: Color_Type) {
|
||||||
draw_rect(ctx, rect, ctx.style.colors[colorid])
|
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 {
|
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]
|
||||||
}
|
}
|
||||||
|
|
||||||
/*============================================================================
|
/*============================================================================
|
||||||
|
Loading…
x
Reference in New Issue
Block a user