From 6e2ad6a3b0957edbf64852620ab500b7d723681e Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Mon, 12 May 2025 11:27:16 +0400 Subject: [PATCH] Raycast against level geom --- game/game.odin | 4 +- game/physics/debug.odin | 2 +- game/physics/simulation.odin | 103 ++++++++++++++++++++++++++++++++--- 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/game/game.odin b/game/game.odin index 13f10a7..3c44911 100644 --- a/game/game.odin +++ b/game/game.odin @@ -359,8 +359,6 @@ World_Update_Config :: struct { } update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) { - rl.BeginDrawing() - rl.BeginMode3D(game_camera_3d()) if !world.pause { car_model := assets.get_model(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb") car_bounds := rl.GetModelBoundingBox(car_model) @@ -1043,6 +1041,7 @@ draw_world :: proc(world: ^World) { draw :: proc() { tracy.Zone() + rl.BeginDrawing() defer rl.EndDrawing() rl.ClearBackground(rl.GRAY) render.clear_stencil() @@ -1061,6 +1060,7 @@ draw :: proc() { // ) { + rl.BeginMode3D(camera) defer rl.EndMode3D() draw_world(world) diff --git a/game/physics/debug.odin b/game/physics/debug.odin index dbeb5cf..58075e6 100644 --- a/game/physics/debug.odin +++ b/game/physics/debug.odin @@ -69,7 +69,7 @@ draw_debug_scene :: proc(scene: ^Scene) { } } - if false { + if true { for &level_geom, geom_idx in sim_state.level_geoms { if level_geom.alive { vertices, indices := get_level_geom_data(sim_state, level_geom.geometry) diff --git a/game/physics/simulation.odin b/game/physics/simulation.odin index dba09d2..08fae15 100644 --- a/game/physics/simulation.odin +++ b/game/physics/simulation.odin @@ -1,6 +1,5 @@ package physics -import rl " libs:raylib" import "base:runtime" import "bvh" import "collision" @@ -180,6 +179,52 @@ build_dynamic_tlas :: proc(sim_state: ^Sim_State, config: Solver_Config) -> Dyna return Dynamic_TLAS{bvh_tree = sim_state_bvh, body_aabbs = body_aabbs} } +raycasts_level :: proc( + sim_state: ^Sim_State, + tlas: ^Static_TLAS, + origin, dir: Vec3, + distance := max(f32), +) -> ( + t: f32, + normal: Vec3, + hit: bool, +) { + temp := runtime.default_temp_allocator_temp_begin() + defer runtime.default_temp_allocator_temp_end(temp) + + t = distance + + ray: bvh.Ray + ray.origin = origin + ray.dir = dir + ray.dir_inv = 1.0 / dir + it := bvh.iterator_intersect_leaf_ray(&tlas.bvh_tree.bvh, ray, distance) + + for leaf_node in bvh.iterator_intersect_leaf_next(&it) { + for j in 0 ..< leaf_node.prim_len { + tri_idx := tlas.bvh_tree.bvh.primitives[leaf_node.child_or_prim_start + j] + tri := get_triangle( + tlas.bvh_tree.mesh.vertices, + tlas.bvh_tree.mesh.indices, + int(tri_idx), + ) + + hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle( + {origin, origin + dir}, + tri, + ) + + if ok && (!hit || hit_t < t) { + t = hit_t + normal = tmp_normal + hit = true + } + } + } + + return +} + raycast_bodies :: proc( sim_state: ^Sim_State, tlas: ^Dynamic_TLAS, @@ -226,6 +271,43 @@ raycast_bodies :: proc( return } +raycast :: proc( + sim_state: ^Sim_State, + static_tlas: ^Static_TLAS, + dyn_tlas: ^Dynamic_TLAS, + origin, dir: Vec3, + distance := max(f32), +) -> ( + t: f32, + normal: Vec3, + hit: bool, +) { + t = distance + + t1, normal1, hit1 := raycasts_level(sim_state, static_tlas, origin, dir, t) + t2, normal2, hit2 := raycast_bodies(sim_state, dyn_tlas, origin, dir, t) + + hit = hit1 || hit2 + + if hit1 && hit2 { + if t1 < t2 { + t = t1 + normal = normal1 + } else { + t = t2 + normal = normal2 + } + } else if hit1 { + t = t1 + normal = normal1 + } else if hit2 { + t = t2 + normal = normal2 + } + + return +} + get_triangle :: proc(vertices: []Vec3, indices: []u16, tri_idx: int) -> (tri: [3]Vec3) { i1, i2, i3 := indices[tri_idx * 3 + 0], indices[tri_idx * 3 + 1], indices[tri_idx * 3 + 2] tri[0], tri[1], tri[2] = vertices[i1], vertices[i2], vertices[i3] @@ -556,8 +638,8 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { // rl.DrawTriangle3D(tri[0], tri[1], tri[2], rl.BLUE) m2 = collision.double_sided_triangle_to_convex(tri, context.temp_allocator) - // m2 = level_geom_get_convex_shape(sim_state, level_geom, int(contact.tri_idx)) - he.debug_draw_mesh_wires(m2, rl.BLUE) + // m2 = level_geom_get_convex_shape(sim_state, level_geom, int(contact.tri_idx)) + // he.debug_draw_mesh_wires(m2, rl.BLUE) } // Raw manifold has contact points in world space @@ -955,7 +1037,8 @@ calculate_ground_vel :: proc( pgs_solve_suspension :: proc( sim_state: ^Sim_State, - tlas: ^Dynamic_TLAS, + static_tlas: ^Static_TLAS, + dyn_tlas: ^Dynamic_TLAS, config: Solver_Config, dt: f32, inv_dt: f32, @@ -969,9 +1052,10 @@ pgs_solve_suspension :: proc( if body.alive { wheel_world_pos := body_local_to_world(body, v.rel_pos) dir := body_local_to_world_vec(body, v.rel_dir) - v.hit_t, v.hit_normal, v.hit = raycast_bodies( + v.hit_t, v.hit_normal, v.hit = raycast( sim_state, - tlas, + static_tlas, + dyn_tlas, wheel_world_pos, dir, v.rest, @@ -1159,7 +1243,8 @@ pgs_solve_suspension :: proc( pgs_substep :: proc( sim_state: ^Sim_State, - tlas: ^Dynamic_TLAS, + static_tlas: ^Static_TLAS, + dyn_tlas: ^Dynamic_TLAS, config: Solver_Config, dt: f32, inv_dt: f32, @@ -1272,7 +1357,7 @@ pgs_substep :: proc( apply_bias := true pgs_solve_contacts(sim_state, config, dt, inv_dt, apply_bias) pgs_solve_engines(sim_state, config, dt, inv_dt) - pgs_solve_suspension(sim_state, tlas, config, dt, inv_dt) + pgs_solve_suspension(sim_state, static_tlas, dyn_tlas, config, dt, inv_dt) for i in 0 ..< len(sim_state.bodies_slice) { body := &sim_state.bodies_slice[i] @@ -1345,7 +1430,7 @@ simulate_step :: proc(scene: ^Scene, sim_state: ^Sim_State, config: Solver_Confi } case .PGS: for _ in 0 ..< substeps { - pgs_substep(sim_state, &dyn_tlas, config, dt, inv_dt) + pgs_substep(sim_state, &static_tlas, &dyn_tlas, config, dt, inv_dt) } }