Lots of optimizations and bug fixes for static geometry, improved debugging

This commit is contained in:
sergeypdev 2025-07-01 00:09:10 +04:00
parent bce37a3b7e
commit 00190a45fc
10 changed files with 335 additions and 180 deletions

BIN
assets/testblend.glb (Stored with Git LFS)

Binary file not shown.

View File

@ -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)

View File

@ -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

View File

@ -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(

View File

@ -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,
}

View File

@ -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 :=

View File

@ -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,
}

View File

@ -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)

Binary file not shown.

BIN
src_assets/testblend.blend1 (Stored with Git LFS)

Binary file not shown.