Lots of optimizations and bug fixes for static geometry, improved debugging
This commit is contained in:
parent
bce37a3b7e
commit
00190a45fc
BIN
assets/testblend.glb
(Stored with Git LFS)
BIN
assets/testblend.glb
(Stored with Git LFS)
Binary file not shown.
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,15 +190,24 @@ draw_debug_scene :: proc(scene: ^Scene) {
|
||||
}
|
||||
}
|
||||
|
||||
if false {
|
||||
if true {
|
||||
for &contact, contact_idx in sim_state.contact_container.contacts {
|
||||
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_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,
|
||||
@ -205,9 +222,15 @@ draw_debug_scene :: proc(scene: ^Scene) {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,22 +286,37 @@ 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 {
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -204,18 +204,14 @@ raycasts_level :: proc(
|
||||
blas := get_level_geom_blas(sim_state, level_geom.blas)
|
||||
vertices, indices := get_level_geom_data(sim_state, level_geom.geometry)
|
||||
|
||||
blas_it := bvh.iterator_intersect_leaf_ray(&blas, ray, distance)
|
||||
for blas_leaf_node in bvh.iterator_intersect_leaf_next(&it) {
|
||||
for k in 0 ..< blas_leaf_node.prim_len {
|
||||
tri_idx := blas.primitives[blas_leaf_node.child_or_prim_start + k]
|
||||
}
|
||||
}
|
||||
// TODO: transform ray into blas space and back
|
||||
|
||||
tri := get_triangle(
|
||||
tlas.bvh_tree.mesh.vertices,
|
||||
tlas.bvh_tree.mesh.indices,
|
||||
int(tri_idx),
|
||||
)
|
||||
blas_it := bvh.iterator_intersect_leaf_ray(&blas, ray, distance)
|
||||
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])
|
||||
|
||||
tri := get_triangle(vertices, indices, tri_idx)
|
||||
|
||||
hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle(
|
||||
{origin, origin + dir},
|
||||
@ -229,6 +225,8 @@ raycasts_level :: proc(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@ -384,30 +382,31 @@ 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 {
|
||||
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)
|
||||
|
||||
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,
|
||||
)
|
||||
tri := get_triangle(vertices, indices, tri_idx)
|
||||
aabb_b := get_triangle_aabb(tri)
|
||||
|
||||
should_remove |= !bvh.test_aabb_vs_aabb(aabb_a, aabb_b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,23 +533,34 @@ 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],
|
||||
),
|
||||
)
|
||||
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,
|
||||
)
|
||||
|
||||
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],
|
||||
)
|
||||
tri := get_triangle(vertices, indices, tri_idx)
|
||||
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)
|
||||
|
||||
if bvh.test_aabb_vs_aabb(body_aabb, prim_aabb) {
|
||||
|
||||
@ -555,7 +568,10 @@ find_new_contacts :: proc(
|
||||
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)
|
||||
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,
|
||||
@ -565,12 +581,15 @@ find_new_contacts :: proc(
|
||||
index_to_body_handle(int(body_idx)),
|
||||
level_geom_handle,
|
||||
shape_idx,
|
||||
i32(local_tri_idx),
|
||||
i32(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)
|
||||
num_contacts_found += 1
|
||||
new_contact_idx := len(
|
||||
sim_state.contact_container.contacts,
|
||||
)
|
||||
resize_soa(
|
||||
&sim_state.contact_container.contacts,
|
||||
new_contact_idx + 1,
|
||||
@ -582,10 +601,12 @@ find_new_contacts :: proc(
|
||||
a = index_to_body_handle(i),
|
||||
shape_a = shape_idx,
|
||||
b = i32(level_geom_handle),
|
||||
local_tri_idx = i32(local_tri_idx),
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -594,6 +615,11 @@ find_new_contacts :: proc(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracy.ZoneValue(tracy_ctx, u64(num_contacts_found))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Outer simulation loop for fixed timestepping
|
||||
@ -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 :=
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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, "<nil>")
|
||||
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)
|
||||
|
BIN
src_assets/testblend.blend
(Stored with Git LFS)
BIN
src_assets/testblend.blend
(Stored with Git LFS)
Binary file not shown.
BIN
src_assets/testblend.blend1
(Stored with Git LFS)
BIN
src_assets/testblend.blend1
(Stored with Git LFS)
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user