Timestep independence, finally

This commit is contained in:
sergeypdev 2025-01-09 15:07:19 +04:00
parent e22e667e27
commit e618ad9520
3 changed files with 29 additions and 19 deletions

2
.nvim.lua Normal file
View File

@ -0,0 +1,2 @@
vim.opt_global.makeprg = "./build_hot_reload.sh"
vim.opt.errorformat = "%f(%l:%c)\\ %m"

View File

@ -62,7 +62,7 @@ Car :: struct {
} }
SOLVER_CONFIG :: physics.Solver_Config { SOLVER_CONFIG :: physics.Solver_Config {
timestep = 1.0 / 120, timestep = 1.0 / 104,
gravity = rl.Vector3{0, -9.8, 0}, gravity = rl.Vector3{0, -9.8, 0},
substreps_minus_one = 4 - 1, substreps_minus_one = 4 - 1,
} }
@ -245,20 +245,20 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
}, },
) )
car_body := physics.get_body(&world.physics_scene, runtime_world.car_handle) // car_body := physics.get_body(&world.physics_scene, runtime_world.car_handle)
camera := &runtime_world.camera camera := &runtime_world.camera
camera.up = rl.Vector3{0, 1, 0} camera.up = rl.Vector3{0, 1, 0}
camera.fovy = 60 camera.fovy = 60
camera.projection = .PERSPECTIVE camera.projection = .PERSPECTIVE
camera.position = physics.body_local_to_world( // camera.position = physics.body_local_to_world(
car_body, // car_body,
physics.body_world_to_local( // physics.body_world_to_local(
car_body, // car_body,
physics.body_local_to_world(car_body, rl.Vector3{1, 0, -2}), // physics.body_local_to_world(car_body, rl.Vector3{1, 0, -2}),
), // ),
) // )
camera.target = physics.get_body(&world.physics_scene, runtime_world.car_handle).x camera.target = physics.get_body(&world.physics_scene, runtime_world.car_handle).x
if runtime_world.camera.position == {} { if runtime_world.camera.position == {} {
runtime_world.camera.position = runtime_world.camera.target - rl.Vector3{10, 0, 10} runtime_world.camera.position = runtime_world.camera.target - rl.Vector3{10, 0, 10}
@ -333,8 +333,8 @@ 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}
DRIVE_IMPULSE :: 1 DRIVE_IMPULSE :: 20
BRAKE_IMPULSE :: 2 BRAKE_IMPULSE :: 50
TURN_ANGLE :: -f32(30) * math.RAD_PER_DEG TURN_ANGLE :: -f32(30) * math.RAD_PER_DEG
for wheel_handle in drive_wheels { for wheel_handle in drive_wheels {
@ -520,7 +520,12 @@ draw :: proc() {
car_matrix := rl.QuaternionToMatrix(car_body.q) car_matrix := rl.QuaternionToMatrix(car_body.q)
car_model.transform = car_matrix car_model.transform = car_matrix
rl.DrawModel(car_model, car_body.x + runtime_world.car_com, 1, rl.WHITE) rl.DrawModel(
car_model,
physics.body_local_to_world(car_body, -runtime_world.car_com),
1,
rl.WHITE,
)
} else { } else {
if g_mem.draw_car { if g_mem.draw_car {
rl.DrawModel(car_model, 0, 1, rl.WHITE) rl.DrawModel(car_model, 0, 1, rl.WHITE)
@ -572,6 +577,8 @@ draw :: proc() {
rl.BeginMode2D(ui_camera()) rl.BeginMode2D(ui_camera())
defer rl.EndMode2D() defer rl.EndMode2D()
rl.DrawFPS(0, 0)
if g_mem.editor { if g_mem.editor {
rl.DrawText("Editor", 5, 5, 8, rl.ORANGE) rl.DrawText("Editor", 5, 5, 8, rl.ORANGE)
@ -782,7 +789,7 @@ game_init_window :: proc() {
rl.InitWindow(1280, 720, "Odin + Raylib + Hot Reload template!") rl.InitWindow(1280, 720, "Odin + Raylib + Hot Reload template!")
rl.SetExitKey(.KEY_NULL) rl.SetExitKey(.KEY_NULL)
rl.SetWindowPosition(200, 200) rl.SetWindowPosition(200, 200)
rl.SetTargetFPS(60) rl.SetTargetFPS(120)
} }
@(export) @(export)

View File

@ -48,7 +48,7 @@ simulate :: proc(scene: ^Scene, state: ^Solver_State, config: Solver_Config, dt:
state.accumulated_time += dt state.accumulated_time += dt
num_steps := 0 num_steps := 0
for state.accumulated_time > config.timestep { for state.accumulated_time >= config.timestep {
num_steps += 1 num_steps += 1
state.accumulated_time -= config.timestep state.accumulated_time -= config.timestep
@ -135,17 +135,21 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
for _, i in scene.suspension_constraints { for _, i in scene.suspension_constraints {
v := &scene.suspension_constraints_slice[i] v := &scene.suspension_constraints_slice[i]
if v.alive { if v.alive {
body_idx := int(v.body) - 1
body := get_body(scene, v.body) body := get_body(scene, v.body)
if body.alive && v.hit { if body.alive && v.hit {
prev_x, prev_q := body_states[body_idx].prev_x, body_states[body_idx].prev_q
wheel_world_pos := body_local_to_world(body, v.rel_pos) wheel_world_pos := body_local_to_world(body, v.rel_pos)
prev_wheel_world_pos := prev_x + lg.quaternion_mul_vector3(prev_q, v.rel_pos)
vel_3d := (wheel_world_pos - prev_wheel_world_pos) * inv_dt
dir := body_local_to_world_vec(body, v.rel_dir) dir := body_local_to_world_vec(body, v.rel_dir)
body_state := body_states[i32(v.body) - 1] body_state := body_states[i32(v.body) - 1]
// Spring damping // Spring damping
if true { if true {
vel_3d := body_velocity_at_local_point(body, wheel_world_pos - body.x)
vel := lg.dot(vel_3d, dir) vel := lg.dot(vel_3d, dir)
damping := -vel * min(v.damping * dt, 1) damping := -vel * min(v.damping * dt, 1)
@ -166,8 +170,6 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
total_impulse := v.drive_impulse - v.brake_impulse total_impulse := v.drive_impulse - v.brake_impulse
forward := body_local_to_world_vec(body, rl.Vector3{0, 0, 1}) forward := body_local_to_world_vec(body, rl.Vector3{0, 0, 1})
corr := total_impulse * forward * dt
apply_constraint_correction_unilateral( apply_constraint_correction_unilateral(
dt, dt,
body, body,
@ -176,7 +178,6 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
forward, forward,
wheel_world_pos, wheel_world_pos,
) )
apply_correction(body, corr, wheel_world_pos)
body_solve_velocity(body, body_state, inv_dt) body_solve_velocity(body, body_state, inv_dt)
} }