From 00190a45fc9d6841106c68dbc4c17e93c8048b89 Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Tue, 1 Jul 2025 00:09:10 +0400 Subject: [PATCH] Lots of optimizations and bug fixes for static geometry, improved debugging --- assets/testblend.glb | 4 +- game/game.odin | 27 ++- game/physics/collision/convex.odin | 35 ++-- game/physics/debug.odin | 120 +++++++++--- game/physics/scene.odin | 8 +- game/physics/simulation.odin | 287 ++++++++++++++++++----------- game/physics/xpbd.odin | 4 - game/ui/microui.odin | 22 ++- src_assets/testblend.blend | 4 +- src_assets/testblend.blend1 | 4 +- 10 files changed, 335 insertions(+), 180 deletions(-) diff --git a/assets/testblend.glb b/assets/testblend.glb index a861918..846cda6 100644 --- a/assets/testblend.glb +++ b/assets/testblend.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56d430b11fdf2b7633791c69f9f4ac300f1b683503892aab3cc88a2501cba738 -size 7549972 +oid sha256:3f5b4194a22b029fa56f6931ac53b14120df4376f8d6436f6606a1f9ed617ae2 +size 11324244 diff --git a/game/game.odin b/game/game.odin index 7c2e972..58f066b 100644 --- a/game/game.odin +++ b/game/game.odin @@ -697,7 +697,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) { { level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb") - for i in 0 ..< min(level_model.meshCount, 32) { + for i in 0 ..< level_model.meshCount { mesh := &level_model.meshes[i] if mesh.triangleCount > 0 { @@ -1051,16 +1051,15 @@ catmull_rom :: proc(a, b, c, d: rl.Vector3, t: f32) -> rl.Vector3 { draw_world :: proc(world: ^World) { tracy.Zone() - if world.debug_state.draw_physics_scene { - physics.draw_debug_scene(&world.physics_scene) - } - sim_state := physics.get_sim_state(&world.physics_scene) - // level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb") + level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb") + car_model := assets.get_model(&g_mem.assetman, "assets/ice_cream_truck.glb") + + phys_debug_state: physics.Debug_State + physics.init_debug_state(&phys_debug_state) car_body := physics.get_body(sim_state, world.car_handle) - car_model := assets.get_model(&g_mem.assetman, "assets/ice_cream_truck.glb") engine := physics.get_engine(sim_state, world.engine_handle) { @@ -1102,7 +1101,12 @@ draw_world :: proc(world: ^World) { } if .ACTIVE in ui.header(ui_ctx, "Physics") { - physics.draw_debug_ui(ui_ctx, &world.physics_scene, SOLVER_CONFIG) + physics.draw_debug_ui( + &phys_debug_state, + ui_ctx, + &world.physics_scene, + SOLVER_CONFIG, + ) } } else { log.infof("Window closed") @@ -1111,6 +1115,11 @@ draw_world :: proc(world: ^World) { } } + if world.debug_state.draw_physics_scene { + physics.draw_debug_scene(&world.physics_scene, &phys_debug_state) + } + + car_matrix := rl.QuaternionToMatrix(car_body.q) car_matrix = (auto_cast linalg.matrix4_translate_f32(physics.body_get_shape_pos(car_body))) * car_matrix @@ -1133,7 +1142,7 @@ draw_world :: proc(world: ^World) { // .VEC3, // ) - // render.draw_model(level_model, {}, 1) + render.draw_model(level_model, {}, 1) render.draw_model(car_model, {}, car_matrix) diff --git a/game/physics/collision/convex.odin b/game/physics/collision/convex.odin index 9818811..18c3496 100644 --- a/game/physics/collision/convex.odin +++ b/game/physics/collision/convex.odin @@ -1,5 +1,6 @@ package collision +import "base:runtime" import "core:container/bit_array" import "core:log" import "core:math" @@ -28,13 +29,25 @@ box_corners_norm := [8]Vec3 { } box_indices := [6 * 4]u16{0, 4, 6, 2, 3, 2, 6, 7, 7, 6, 4, 5, 5, 1, 3, 7, 1, 0, 2, 3, 5, 4, 0, 1} +double_sided_triangle_indices := [6]u16{0, 1, 2, 0, 2, 1} @(private = "file") box_mesh: Convex +@(private = "file") +triangle_mesh: Convex + @(init) init_box_mesh :: proc() { box_mesh = Convex(halfedge.mesh_from_vertex_index_list(box_corners_norm[:], box_indices[:], 4)) + + triangle_mesh = Convex( + halfedge.mesh_from_vertex_index_list( + []Vec3{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}}, + double_sided_triangle_indices[:], + 3, + ), + ) } @(fini) @@ -54,23 +67,16 @@ box_to_convex :: proc(box: Box, allocator := context.allocator) -> (convex: Conv return } -double_sided_triangle_indices := [6]u16{0, 1, 2, 0, 2, 1} - double_sided_triangle_to_convex :: proc( tri: [3]Vec3, allocator := context.allocator, ) -> ( convex: Convex, ) { - tri := tri - convex = Convex( - halfedge.mesh_from_vertex_index_list( - tri[:], - double_sided_triangle_indices[:], - 3, - allocator, - ), - ) + convex = halfedge.copy_mesh(triangle_mesh, allocator) + convex.vertices[0].pos = tri[0] + convex.vertices[1].pos = tri[1] + convex.vertices[2].pos = tri[2] return } @@ -257,11 +263,14 @@ query_separation_edges :: proc( a_edge = -1 b_edge = -1 + temp := runtime.default_temp_allocator_temp_begin() + defer runtime.default_temp_allocator_temp_end(temp) + checked_pairs: bit_array.Bit_Array bit_array.init(&checked_pairs, len(a.edges) * len(b.edges), 0, context.temp_allocator) a_len := len(a.edges) - calc_pair_index :: proc(a, b, a_len: int) -> int { + calc_pair_index :: #force_inline proc(a, b, a_len: int) -> int { return (b * a_len) + a } @@ -320,7 +329,7 @@ create_face_contact_manifold :: proc( ) { tracy.Zone() - is_ref_a := (face_query_a.separation + 0.01) > face_query_b.separation + is_ref_a := (face_query_a.separation + 0.001) > face_query_b.separation ref_face_query := is_ref_a ? face_query_a : face_query_b ref_convex := is_ref_a ? a : b inc_convex := is_ref_a ? b : a diff --git a/game/physics/debug.odin b/game/physics/debug.odin index 30e5391..0ee1189 100644 --- a/game/physics/debug.odin +++ b/game/physics/debug.odin @@ -6,6 +6,7 @@ import "core:log" import "core:math" import lg "core:math/linalg" import "core:mem" +import "core:slice" import "core:strings" import "game:debug" import he "game:halfedge" @@ -49,23 +50,30 @@ draw_debug_shape :: proc( } } -draw_debug_scene :: proc(scene: ^Scene) { +Debug_State :: struct { + selected_contacts: map[int]struct {}, +} + +init_debug_state :: proc(debug_state: ^Debug_State) { + debug_state.selected_contacts = make(map[int]struct {}, context.temp_allocator) +} + +draw_debug_scene :: proc(scene: ^Scene, debug_state: ^Debug_State) { tracy.Zone() sim_state := get_sim_state(scene) // Static_TLAS if true && sim_state.static_tlas.built { - bvh.debug_draw_bvh_bounds_mesh( - &sim_state.static_tlas.bvh_tree.bvh, - sim_state.static_tlas.bvh_tree.mesh, - 0, + bvh.debug_draw_bvh_bounds( + &sim_state.static_tlas.bvh_tree, + sim_state.static_tlas.level_geom_aabbs, 0, ) } // Dynamic TLAS - if true && sim_state.dynamic_tlas.built { + if false && sim_state.dynamic_tlas.built { bvh.debug_draw_bvh_bounds( &sim_state.dynamic_tlas.bvh_tree, sim_state.dynamic_tlas.body_aabbs, @@ -182,32 +190,47 @@ draw_debug_scene :: proc(scene: ^Scene) { } } - if false { + if true { for &contact, contact_idx in sim_state.contact_container.contacts { - points_a := contact.manifold.points_a - points_b := contact.manifold.points_b - points_a_slice, points_b_slice := - points_a[:contact.manifold.points_len], points_b[:contact.manifold.points_len] - debug_transform_points_local_to_world(get_body(sim_state, contact.a), points_a_slice) - b_handle := Body_Handle(contact.b) if contact.type == .Body_vs_Body else INVALID_BODY - debug_transform_points_local_to_world(get_body(sim_state, b_handle), points_b_slice) - debug_draw_manifold_points( - contact, - -1, - points_a_slice, - color = debug.int_to_color(i32(contact_idx * 2 + 0)), - ) - debug_draw_manifold_points( - contact, - 1, - points_b_slice, - color = debug.int_to_color(i32(contact_idx * 2 + 1)), - ) + if contact_idx in debug_state.selected_contacts || + len(debug_state.selected_contacts) == 0 { + points_a := contact.manifold.points_a + points_b := contact.manifold.points_b + points_a_slice, points_b_slice := + points_a[:contact.manifold.points_len], points_b[:contact.manifold.points_len] + debug_transform_points_local_to_world( + get_body(sim_state, contact.a), + points_a_slice, + ) + b_handle := + Body_Handle(contact.b) if contact.type == .Body_vs_Body else INVALID_BODY + debug_transform_points_local_to_world( + get_body(sim_state, b_handle), + points_b_slice, + ) + debug_draw_manifold_points( + contact, + -1, + points_a_slice, + color = debug.int_to_color(i32(contact_idx * 2 + 0)), + ) + debug_draw_manifold_points( + contact, + 1, + points_b_slice, + color = debug.int_to_color(i32(contact_idx * 2 + 1)), + ) + } } } } -draw_debug_ui :: proc(ctx: ^ui.Context, scene: ^Scene, config: Solver_Config) { +draw_debug_ui :: proc( + debug_state: ^Debug_State, + ctx: ^ui.Context, + scene: ^Scene, + config: Solver_Config, +) { tracy.Zone() sim_state := get_sim_state(scene) @@ -233,7 +256,29 @@ draw_debug_ui :: proc(ctx: ^ui.Context, scene: ^Scene, config: Solver_Config) { @(static) search_len: int ui.textbox(ctx, search_buf[:], &search_len) search_str := string(search_buf[0:search_len]) + Contact_And_Index :: struct { + contact: Contact, + idx: int, + } + sorted_contacts := make( + []Contact_And_Index, + len(sim_state.contact_container.contacts), + context.temp_allocator, + ) for &contact, i in sim_state.contact_container.contacts { + sorted_contacts[i] = Contact_And_Index { + contact = contact, + idx = i, + } + } + slice.reverse_sort_by_key( + sorted_contacts, + #force_inline proc(contact_and_index: Contact_And_Index) -> f32 { + return lg.max(contact_and_index.contact.total_normal_impulse) + }, + ) + for &contact_and_index, i in sorted_contacts { + contact := contact_and_index.contact title: string ui.push_id(ctx, mem.any_to_bytes(i)) @@ -241,23 +286,38 @@ draw_debug_ui :: proc(ctx: ^ui.Context, scene: ^Scene, config: Solver_Config) { if contact.type == .Body_vs_Body { title = fmt.tprintf( - "%v v %v", + "%d %v v %v", + contact_and_index.idx, name.to_string(get_body(sim_state, contact.a).name), name.to_string(get_body(sim_state, Body_Handle(contact.b)).name), ) } else { title = fmt.tprintf( - "%v v lvl", + "%d %v v lvl", + contact_and_index.idx, name.to_string(get_body(sim_state, contact.a).name), ) } if strings.contains(title, search_str) { - ui.inspect_value(ctx, title, contact) + if ui.inspect_value(ctx, title, contact) { + debug_state.selected_contacts[contact_and_index.idx] = {} + } } } } + if .ACTIVE in ui.treenode(ctx, "Static TLAS") { + if sim_state.static_tlas.built { + bvh.debug_ui_bvh_node_recursive( + ctx, + sim_state.static_tlas.bvh_tree, + sim_state.static_tlas.level_geom_aabbs, + 0, + ) + } + } + if .ACTIVE in ui.treenode(ctx, "Dynamic TLAS") { if sim_state.dynamic_tlas.built { bvh.debug_ui_bvh_node_recursive( diff --git a/game/physics/scene.odin b/game/physics/scene.odin index ef82dc7..5e11624 100644 --- a/game/physics/scene.odin +++ b/game/physics/scene.odin @@ -35,14 +35,14 @@ Contact_Pair :: union { } make_contact_pair_bodies :: proc( - body_a: i32, - body_b: i32, + body_a: int, + body_b: int, shape_a: i32, shape_b: i32, ) -> Contact_Pair_Bodies { return { - index_to_body_handle(int(min(body_a, body_b))), - index_to_body_handle(int(max(body_a, body_b))), + index_to_body_handle(min(body_a, body_b)), + index_to_body_handle(max(body_a, body_b)), shape_a, shape_b, } diff --git a/game/physics/simulation.odin b/game/physics/simulation.odin index aabb36f..9ecfab3 100644 --- a/game/physics/simulation.odin +++ b/game/physics/simulation.odin @@ -204,29 +204,27 @@ raycasts_level :: proc( blas := get_level_geom_blas(sim_state, level_geom.blas) vertices, indices := get_level_geom_data(sim_state, level_geom.geometry) + // TODO: transform ray into blas space and back + blas_it := bvh.iterator_intersect_leaf_ray(&blas, ray, distance) - for blas_leaf_node in bvh.iterator_intersect_leaf_next(&it) { + for blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) { for k in 0 ..< blas_leaf_node.prim_len { - tri_idx := blas.primitives[blas_leaf_node.child_or_prim_start + k] + tri_idx := int(blas.primitives[blas_leaf_node.child_or_prim_start + k]) + + tri := get_triangle(vertices, indices, 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 + } } } - - 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 - } } } @@ -384,21 +382,22 @@ remove_invalid_contacts :: proc( if !should_remove { level_geom_handle := Level_Geom_Handle(contact.b) - tri_offset := - static_tlas.level_geom_tri_offset[level_geom_handle_to_index(level_geom_handle)] - tri_idx := tri_offset + int(contact.local_tri_idx) - should_remove |= (tri_idx * 3) >= len(static_tlas.bvh_tree.mesh.indices) + level_geom := get_level_geom(sim_state, level_geom_handle) + + should_remove |= !level_geom.alive if !should_remove { - aabb_a := dyn_tlas.body_aabbs[body_handle_to_index(contact.a)] - tri := get_triangle( - static_tlas.bvh_tree.mesh.vertices, - static_tlas.bvh_tree.mesh.indices, - tri_idx, - ) - aabb_b := get_triangle_aabb(tri) + tri_idx := int(contact.local_tri_idx) + vertices, indices := get_level_geom_data(sim_state, level_geom.geometry) + should_remove |= tri_idx * 3 >= len(indices) - should_remove |= !bvh.test_aabb_vs_aabb(aabb_a, aabb_b) + if !should_remove { + aabb_a := dyn_tlas.body_aabbs[body_handle_to_index(contact.a)] + tri := get_triangle(vertices, indices, tri_idx) + aabb_b := get_triangle_aabb(tri) + + should_remove |= !bvh.test_aabb_vs_aabb(aabb_a, aabb_b) + } } } } @@ -406,8 +405,8 @@ remove_invalid_contacts :: proc( pair_from_contact :: proc(contact: Contact) -> (pair: Contact_Pair) { if contact.type == .Body_vs_Body { pair = make_contact_pair_bodies( - i32(contact.a) - 1, - i32(contact.b) - 1, + body_handle_to_index(contact.a), + body_handle_to_index(Body_Handle(contact.b)), contact.shape_a, contact.shape_b, ) @@ -452,9 +451,12 @@ find_new_contacts :: proc( body_idx := u16(i) body := &sim_state.bodies_slice[i] - if body.alive { + if body.alive && body.inv_mass != 0 { + tracy.ZoneN(name.to_string(body.name)) + body_aabb := dyn_tlas.body_aabbs[i] { + tracy.ZoneN("find_new_contacts::dynamic_vs_dynamic") it := bvh.iterator_intersect_leaf_aabb(&dyn_tlas.bvh_tree, body_aabb) for leaf_node in bvh.iterator_intersect_leaf_next(&it) { @@ -485,8 +487,8 @@ find_new_contacts :: proc( ) pair := make_contact_pair_bodies( - i32(body_idx), - i32(other_body_idx), + int(body_idx), + int(other_body_idx), shape_a_idx, shape_b_idx, ) @@ -531,66 +533,90 @@ find_new_contacts :: proc( } { - it := bvh.iterator_intersect_leaf_aabb(&static_tlas.bvh_tree.bvh, body_aabb) + tracy_ctx := tracy.ZoneN("find_new_contacts::dynamic_vs_static") + it := bvh.iterator_intersect_leaf_aabb(&static_tlas.bvh_tree, body_aabb) + + num_contacts_found := 0 for leaf_node in bvh.iterator_intersect_leaf_next(&it) { for j in 0 ..< leaf_node.prim_len { - tri_idx := - static_tlas.bvh_tree.bvh.primitives[leaf_node.child_or_prim_start + j] - tri := get_triangle( - static_tlas.bvh_tree.mesh.vertices, - static_tlas.bvh_tree.mesh.indices, - int(tri_idx), + level_geom_handle := index_to_level_geom( + int( + static_tlas.bvh_tree.primitives[leaf_node.child_or_prim_start + j], + ), ) - prim_aabb := get_triangle_aabb(tri) - level_geom_handle := static_tlas.tri_to_level_geom[tri_idx] - local_tri_idx := - int(tri_idx) - - static_tlas.level_geom_tri_offset[level_geom_handle_to_index(level_geom_handle)] - assert(local_tri_idx >= 0) + level_geom := get_level_geom(sim_state, level_geom_handle) + if level_geom.alive { + blas := get_level_geom_blas(sim_state, level_geom.blas) + vertices, indices := get_level_geom_data( + sim_state, + level_geom.geometry, + ) - if bvh.test_aabb_vs_aabb(body_aabb, prim_aabb) { - - shapes_it := shapes_iterator(sim_state, body.shape) - for shape in shapes_iterator_next(&shapes_it) { - shape_idx := shapes_it.counter - 1 - shape_aabb := shape_get_aabb(shape^) - shape_aabb = body_transform_shape_aabb(body, shape_aabb) - bvh_shape_aabb := bvh.AABB { - min = shape_aabb.center - shape_aabb.extent, - max = shape_aabb.center + shape_aabb.extent, - } - - pair := make_contact_pair_body_level( - index_to_body_handle(int(body_idx)), - level_geom_handle, - shape_idx, - i32(local_tri_idx), - ) - - if bvh.test_aabb_vs_aabb(prim_aabb, bvh_shape_aabb) && - !(pair in sim_state.contact_container.lookup) { - new_contact_idx := len(sim_state.contact_container.contacts) - resize_soa( - &sim_state.contact_container.contacts, - new_contact_idx + 1, + blas_it := bvh.iterator_intersect_leaf_aabb(&blas, body_aabb) + for blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) { + for k in 0 ..< blas_leaf_node.prim_len { + tri_idx := int( + blas.primitives[blas_leaf_node.child_or_prim_start + k], ) - contact := &sim_state.contact_container.contacts[new_contact_idx] + tri := get_triangle(vertices, indices, tri_idx) + prim_aabb := get_triangle_aabb(tri) - contact^ = Contact { - type = .Body_vs_Level, - a = index_to_body_handle(i), - shape_a = shape_idx, - b = i32(level_geom_handle), - local_tri_idx = i32(local_tri_idx), + if bvh.test_aabb_vs_aabb(body_aabb, prim_aabb) { + + shapes_it := shapes_iterator(sim_state, body.shape) + for shape in shapes_iterator_next(&shapes_it) { + shape_idx := shapes_it.counter - 1 + shape_aabb := shape_get_aabb(shape^) + shape_aabb = body_transform_shape_aabb( + body, + shape_aabb, + ) + bvh_shape_aabb := bvh.AABB { + min = shape_aabb.center - shape_aabb.extent, + max = shape_aabb.center + shape_aabb.extent, + } + + pair := make_contact_pair_body_level( + index_to_body_handle(int(body_idx)), + level_geom_handle, + shape_idx, + i32(tri_idx), + ) + + if bvh.test_aabb_vs_aabb(prim_aabb, bvh_shape_aabb) && + !(pair in sim_state.contact_container.lookup) { + num_contacts_found += 1 + new_contact_idx := len( + sim_state.contact_container.contacts, + ) + resize_soa( + &sim_state.contact_container.contacts, + new_contact_idx + 1, + ) + contact := &sim_state.contact_container.contacts[new_contact_idx] + + contact^ = Contact { + type = .Body_vs_Level, + a = index_to_body_handle(i), + shape_a = shape_idx, + b = i32(level_geom_handle), + local_tri_idx = i32(tri_idx), + } + + sim_state.contact_container.lookup[pair] = i32( + new_contact_idx, + ) + } + } } - - sim_state.contact_container.lookup[pair] = i32(new_contact_idx) } } } } } + + tracy.ZoneValue(tracy_ctx, u64(num_contacts_found)) } } } @@ -662,8 +688,6 @@ Contact :: struct { // shape index in each body shape_a, shape_b: i32, local_tri_idx: i32, - prev_x_a, prev_x_b: Vec3, - prev_q_a, prev_q_b: Quat, manifold: collision.Contact_Manifold, applied_corrections: int, @@ -682,6 +706,9 @@ Contact :: struct { update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { tracy.Zone() + temp := runtime.default_temp_allocator_temp_begin() + defer runtime.default_temp_allocator_temp_end(temp) + graph_color_bitmask: [4]bit_array.Bit_Array for i in 0 ..< len(graph_color_bitmask) { bit_array.init( @@ -692,6 +719,38 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { ) } + Body_And_Shape_Index :: struct { + body_index: i32, + shape_index: i32, + } + + body_mesh_cache := make(map[Body_And_Shape_Index]collision.Convex, context.temp_allocator) + + get_body_mesh :: #force_inline proc( + body_mesh_cache: ^map[Body_And_Shape_Index]collision.Convex, + sim_state: ^Sim_State, + body_idx: int, + shape: i32, + ) -> ( + convex: collision.Convex, + ) { + key := Body_And_Shape_Index { + body_index = i32(body_idx), + shape_index = shape, + } + ok: bool + convex, ok = body_mesh_cache[key] + if !ok { + convex = body_get_convex_shape_by_linear_index_world( + sim_state, + &sim_state.bodies_slice[body_idx], + shape, + ) + body_mesh_cache[key] = convex + } + return convex + } + for contact_idx in 0 ..< len(sim_state.contact_container.contacts) { contact := &sim_state.contact_container.contacts[contact_idx] @@ -704,10 +763,6 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { old_total_normal_impulse := contact.total_normal_impulse old_total_friction_impulse := contact.total_friction_impulse - contact.prev_x_a = body.x - contact.prev_x_b = body2.x - contact.prev_q_a = body.q - contact.prev_q_b = body2.q contact.manifold = {} contact.total_normal_impulse = 0 contact.total_friction_impulse = 0 @@ -716,9 +771,18 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { contact.applied_static_friction = false contact.applied_normal_correction = 0 - // aabb1, aabb2 := body_get_aabb(body), body_get_aabb(body2) + // aabb1 := body_get_aabb(body) + // aabb2: AABB + // switch contact.type { + // case .Body_vs_Body: + // aabb2 = body_get_aabb(body2) + // case .Body_vs_Level: + // level_geom_handle := Level_Geom_Handle(contact.b) + // level_geom := get_level_geom(sim_state, level_geom_handle) + // aabb2 = level_geom.aabb + // } - // TODO: extract common math functions into a sane place + // // TODO: extract common math functions into a sane place // if !collision.test_aabb_vs_aabb( // {min = aabb1.center - aabb1.extent, max = aabb1.center + aabb1.extent}, // {min = aabb2.center - aabb2.extent, max = aabb2.center + aabb2.extent}, @@ -726,22 +790,27 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { // continue // } - m1 := body_get_convex_shape_by_linear_index_world(sim_state, body, contact.shape_a) + m1 := get_body_mesh( + &body_mesh_cache, + sim_state, + body_handle_to_index(contact.a), + contact.shape_a, + ) m2: collision.Convex switch contact.type { case .Body_vs_Body: - m2 = body_get_convex_shape_by_linear_index_world(sim_state, body2, contact.shape_b) + m2 = get_body_mesh( + &body_mesh_cache, + sim_state, + body_handle_to_index(b_handle), + contact.shape_b, + ) case .Body_vs_Level: level_geom_handle := Level_Geom_Handle(contact.b) - tri_idx := - static_tlas.level_geom_tri_offset[level_geom_handle_to_index(level_geom_handle)] + - int(contact.local_tri_idx) - tri := get_triangle( - static_tlas.bvh_tree.mesh.vertices, - static_tlas.bvh_tree.mesh.indices, - tri_idx, - ) + level_geom := get_level_geom(sim_state, level_geom_handle) + vertices, indices := get_level_geom_data(sim_state, level_geom.geometry) + tri := get_triangle(vertices, indices, int(contact.local_tri_idx)) m2 = collision.double_sided_triangle_to_convex(tri, context.temp_allocator) } @@ -814,7 +883,7 @@ pgs_solve_contacts :: proc( inv_dt: f32, apply_bias: bool, ) { - bias_rate, mass_coef, impulse_coef := calculate_soft_constraint_params(30, 0.8, dt) + bias_rate, mass_coef, impulse_coef := calculate_soft_constraint_params(40, 1.0, dt) if !apply_bias { mass_coef = 1 bias_rate = 0 @@ -827,10 +896,10 @@ pgs_solve_contacts :: proc( random_order[i] = i32(i) } - for i in 0 ..< len(random_order) - 1 { - j := rand.int_max(len(random_order)) - slice.swap(random_order, i, j) - } + // for i in 0 ..< len(random_order) - 1 { + // j := rand.int_max(len(random_order)) + // slice.swap(random_order, i, j) + // } } for i in 0 ..< len(sim_state.contact_container.contacts) { @@ -1369,7 +1438,11 @@ pgs_substep :: proc( manifold := &contact.manifold body1, body2 := - get_body(sim_state, contact.a), get_body(sim_state, Body_Handle(contact.b)) + get_body(sim_state, contact.a), + get_body( + sim_state, + contact.type == .Body_vs_Body ? Body_Handle(contact.b) : INVALID_BODY, + ) for point_idx in 0 ..< manifold.points_len { p1, p2 := diff --git a/game/physics/xpbd.odin b/game/physics/xpbd.odin index a30bcb1..6eee2c1 100644 --- a/game/physics/xpbd.odin +++ b/game/physics/xpbd.odin @@ -50,10 +50,6 @@ xpbd_substep :: proc(sim_state: ^Sim_State, config: Solver_Config, dt: f32, inv_ contact^ = Contact { a = contact.a, b = contact.b, - prev_x_a = body.x, - prev_x_b = body2.x, - prev_q_a = body.q, - prev_q_b = body2.q, manifold = contact.manifold, } diff --git a/game/ui/microui.odin b/game/ui/microui.odin index 60fc456..2cafda5 100644 --- a/game/ui/microui.odin +++ b/game/ui/microui.odin @@ -1845,7 +1845,7 @@ inspect_struct :: proc( v: any, info: runtime.Type_Info_Struct, type_name: string, -) { +) -> bool { if .ACTIVE in treenode(ctx, name) { if .raw_union in info.flags { if type_name == "" { @@ -1853,7 +1853,7 @@ inspect_struct :: proc( } else { keyval(ctx, name, fmt.tprintf("%v{}", type_name)) } - return + return true } is_soa := info.soa_kind != .None @@ -1923,7 +1923,11 @@ inspect_struct :: proc( } } } + + return true } + + return false } is_type_numeric :: proc(type_info: ^runtime.Type_Info) -> bool { @@ -1934,10 +1938,10 @@ is_type_numeric :: proc(type_info: ^runtime.Type_Info) -> bool { return false } -inspect_value :: proc(ctx: ^Context, name: string, v: any, type_name: string = "") { +inspect_value :: proc(ctx: ^Context, name: string, v: any, type_name: string = "") -> bool { if v.data == nil || v.id == nil { label(ctx, "") - return + return true } type_info := type_info_of(v.id) @@ -1945,7 +1949,7 @@ inspect_value :: proc(ctx: ^Context, name: string, v: any, type_name: string = " case runtime.Type_Info_Any: // Ignore case runtime.Type_Info_Parameters: // Ignore case runtime.Type_Info_Named: - inspect_value(ctx, name, any{v.data, info.base.id}, info.name) + return inspect_value(ctx, name, any{v.data, info.base.id}, info.name) case runtime.Type_Info_Boolean, runtime.Type_Info_Integer, @@ -2157,7 +2161,7 @@ inspect_value :: proc(ctx: ^Context, name: string, v: any, type_name: string = " m := (^mem.Raw_Map)(v.data) if m != nil { if info.map_info == nil { - return + return false } map_cap := uintptr(runtime.map_cap(m^)) ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info) @@ -2178,15 +2182,19 @@ inspect_value :: proc(ctx: ^Context, name: string, v: any, type_name: string = " ) } } + } else { + return false } case runtime.Type_Info_Struct: - inspect_struct(ctx, name, v, info, "") + return inspect_struct(ctx, name, v, info, "") case runtime.Type_Info_Union: // fmt_union(fi, v, verb, info, type_info.size) } + + return true } @(private) diff --git a/src_assets/testblend.blend b/src_assets/testblend.blend index 38e4040..a498d98 100644 --- a/src_assets/testblend.blend +++ b/src_assets/testblend.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5a61b68fa0350c31b5c02d456f4b661a790bec568c6d7ba01716ca9fc9e0066 -size 13321681 +oid sha256:351bc2737f5326ab8b76c8e3b5521b1a269a5460a28dde5a56de8f1c4e09b7b0 +size 12945841 diff --git a/src_assets/testblend.blend1 b/src_assets/testblend.blend1 index c22e491..3761c43 100644 --- a/src_assets/testblend.blend1 +++ b/src_assets/testblend.blend1 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4db340afd41c32bf3576fa18eeec89127cef66a9c4c090ef4f652b65e14536e -size 13321681 +oid sha256:58f2b434d209a093693b88742b17f3f2774d275937a7a1b435d696e38d3fe058 +size 12945841