Skip to content

broad_phase: the broad phase, and an overflow-free key hash - #13

Merged
nicolas-maman merged 1 commit into
mainfrom
feat/broad-phase
Sep 20, 2026
Merged

nicolas-maman merged 1 commit into
mainfrom
feat/broad-phase

Conversation

@nicolas-maman

Copy link
Copy Markdown
Contributor

The thirteenth layer: Box3D's broad_phase.c as aephysics.broad_phase, world-free.

  • Trees per body type, proxy keys with the type in the low bits, broad_phase_create/destroy/move_proxy, marks, test_overlap.
  • update_broad_phase_pairs(bp, visitors, has_compounds): the moved-sibling walk of the dynamic tree against itself, the breadth-first seeding against the static and kinematic trees, the pair set cull, the client's should_pair gauntlet, a compound's pair expanded per overlapping child through compound_tree_of/compound_transform, the keys sorted and deduplicated; the client reads them with pair_key_count/pair_key and adopts them with add_pair. Single-threaded; the seeds and siblings keep the reference's order.
  • test_broad_phase.ae: 36 checks against a brute force (first update, quiet update, moves, removed pairs, the filter, one body's shapes, a forced static proxy, a destroyed proxy, a compound's children).
  • Found on the way: core.key_hash multiplied signed longs (UB in C); at -O2 two inlined copies disagreed and a key stored by one was not found by the other. Rewritten in 32-bit products mixing both halves; the mesh's builds move from 199 to 221 ms.
  • bench/broad_phase.ae runs alone (the reference's pair update lives inside its world); scripts/bench.sh now runs a layer without a reference pair. 10,000 moving boxes at 4.6 ms a step.

aephysics.broad_phase, Box3D's broad_phase.c in Aether: a dynamic tree
per body type with the shapes' proxies keyed by type in the low bits,
and the pair update after a step: the dynamic tree against itself
through the sibling pairs a moved node touched (cross-subtree only, so
no duplicates) and against the static and kinematic trees from a
breadth-first seeding; the candidates culled by the pair set, filtered
by the client's visitor, a compound's pair expanded to one per
overlapping child through the client's compound lookups, and the keys
sorted so the contacts come out in an order the trees cannot change.
The reference filters and creates contacts inside its world; here the
update leaves the keys for the client, which adopts them into the set.

test_broad_phase.ae (ours; the reference covers this through its world
tests): keys and the sort, a grid of dynamic boxes over a static ground
with a kinematic platform against a brute force across the first
update, a quiet update, moves, a removed pair, the filter, one body's
shapes, a forced static proxy, a destroyed proxy, and a compound's
pairs one per child. 36 checks.

The hash under every set and map, core's key_hash, multiplied signed
longs: undefined in the C underneath, and gcc at -O2 made two inlined
copies disagree, so a key stored by one copy was not found by the
other (the broad phase test caught it; the mesh's maps had passed by
luck). It now mixes both halves in 32-bit products. The mesh builds
move from 199 to 221 ms with it.

bench/broad_phase.ae runs alone (the reference's update has no
free-standing counterpart): 10,000 moving boxes at 4.6 ms a step.
scripts/bench.sh runs a layer without a reference pair.
@nicolas-maman
nicolas-maman merged commit 4fed6cd into main Sep 20, 2026
1 check passed
@nicolas-maman
nicolas-maman deleted the feat/broad-phase branch September 20, 2026 02:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant