Repository navigation
fix: join the deferred BVH pass before a zero-length step returns - #1067
Open
haowang1013 wants to merge 1 commit into
Open
haowang1013 wants to merge 1 commit into
haowang1013 wants to merge 1 commit into
Conversation
A step with `dt <= 0.0` returned right after collision detection. When that broad-phase update deferred its optimization pass, `take_deferred_optimize` had moved the tree out of the broad-phase, and nothing put it back before the next full step. Until then every scene query missed every collider, including the ones that did not move. Join the deferred pass before the early return, as the end of a full step does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Since #1012, a step with
dt <= 0.0returns right after collision detection. When the broad-phase update in that step defers its optimization pass,take_deferred_optimizemoves the tree out of the broad-phase (mem::replace(&mut self.tree, Bvh::new())). A full step always puts it back: its last action,update_moved_collider_aabbs, callsjoin_deferred_bvh_optimize. The zero-length early return did not. Until the next full step, the broad-phase holds an empty tree, so every scene query misses every collider, including the ones that did not move.This PR calls
join_deferred_bvh_optimizebefore that early return.Why this matters
A zero-length step is the usual way to refresh scene queries between steps. For example, an engine teleports a body, then runs a zero-length step so that raycasts see the new pose. In
@dimforge/rapier3d-compat0.21.0, queries made right after such a step can return nothing. 0.20.0 (Rapier 0.35) does not have the early return and is not affected.The pass is deferred when either:
frame_index % 8 == 0and the in-place leaf updates since the last pass reach 1/64 of the leaves.The second condition can fire in a zero-length step that has no user changes. So running more zero-length steps does not reliably work around the problem from the outside: whichever step lands on that frame leaves the tree out.
Tests
New
crates/rapier3d/tests/zero_dt_step_scene_queries.rs:zero_length_step_after_a_teleport_keeps_every_collider_queryable: teleports a fixed, kinematic or dynamic body, runs one zero-length step, then checks the moved collider at its new pose, the old pose and an untouched collider.consecutive_zero_length_steps_keep_every_collider_queryable: 640 colliders and 1 to 3 consecutive zero-length steps across all eight frame alignments, so that one step lands on the periodic optimizer.Both tests fail on
masterand pass with this change.Validation
cargo test -p rapier3d --release(445 passed, 0 failed)cargo test -p rapier3d --release --features parallel --test zero_dt_step_scene_queries --test single_worker_deferred_bvh(passed)cargo fmt -- --check(passed)cargo clippy -p rapier3d --tests --releasewith and without--features parallel,RUSTFLAGS="-D warnings"(passed)I did not rebuild the TypeScript bindings. I reproduced the problem against the published
@dimforge/rapier3d-compat0.21.0 and confirmed that 0.20.0 does not show it.This is unrelated to #1008 / #1018, which are about the
paralleljoin deadlocking. This bug also shows up in single-threaded builds.🤖 Generated with Claude Code