rapier
rapier copied to clipboard
Rigidbody colliders start failing after calling `ColliderSet::get_mut`
If at some point I do something like:
let body = rigid_body_set.get(rigidbody_handle)?;
for collider_handle in body.colliders() {
if let Some(collider) = collider_set.get_mut(collider_handle) {
// do whatever here...
}
}
then the collider stops interacting with any other colliders. I couldn't find an explanation for what might be going on in the docs, but am assuming it's related to the modification tracking in some way?
This was reduced down from a piece where I was trying to modify the collision groups of all the colliders attached to a rigidbody, but found it didn't matter what I did after I ran get_mut.
Hi! Could you please provide a more detailed way to reproduce this problem (in particular, how are the colliders and rigid-bodies initialized exactly)? Ideally, a complete piece of code I could run to reproduce the issue would be great!
Unfortunately it's tied into a game engine and my naive reduction doesn't expose the issue, so it might take a little while to get a reproducer I can share while I figure out what parts are relevant.
A good trick is to use rapier's built-in serialization to snapshot the issue immediately before it occurs, then write a simple test harness to drive it forwards to the point of occurrence. See the repro in https://github.com/dimforge/rapier/issues/246 for an example.
Hello. I am experiencing the same issue as @porglezomp. I further tested to see when does the issue occurs, so I have made a simple program, heavily based on https://rapier.rs/docs/user_guides/rust/getting_started. The test goes as follows: At the beginning a dynamic ball and a square are created; the square is placed very further away (to show that it has nothing to do with the collisions that we are testing, it could be anywhere); The ball is attached to a dynamic body so it will fall to infinity, if nothing stops it; The ball starts at height 10, and when it reaches height 5 a 'floor' collider will appear; if the colliders work as expected the ball will stop at the 'floor' collider. This is basically the getting started program provided with a difference: the floor is added not at first physics step. If you run this, you will notice that the ball falls to negative infinity because the collider 'floor' is ignored by the ball. This is where the issue of get_mut happens. If you notice in line 59 there is a method called get_mut() on the collider_set for the 'far_away_collider' which should not impact this floor+ball interaction. Calling get_mut and doing nothing with the returned value will break the 'floor' collider. If this line is commented, meaning you don't call get_mut(), the program works as expected. Upon further testing it seems to me that if the collider_set property is changed more than once, by inserting new elements or by calling get_mut(), the colliders might not behave properly.
use rapier2d::prelude::*;
//this code is mostly based from rapier guide: https://rapier.rs/docs/user_guides/rust/getting_started
fn main() {
let mut rigid_body_set = RigidBodySet::new();
let mut collider_set = ColliderSet::new();
/* Create random collider far away. */
let collider = ColliderBuilder::cuboid(1.0, 1.0).translation(vector![999.0,999.0]).build();
let far_away_collider_handle = collider_set.insert(collider);
/* Create the bouncing ball. */
let rigid_body = RigidBodyBuilder::new_dynamic()
.translation(vector![0.0, 10.0])
.build();
let collider = ColliderBuilder::ball(0.5).restitution(0.7).build();
let ball_body_handle = rigid_body_set.insert(rigid_body);
collider_set.insert_with_parent(collider, ball_body_handle, &mut rigid_body_set);
/* Create other structures necessary for the simulation. */
let gravity = vector![0.0, -9.81];
let integration_parameters = IntegrationParameters::default();
let mut physics_pipeline = PhysicsPipeline::new();
let mut island_manager = IslandManager::new();
let mut broad_phase = BroadPhase::new();
let mut narrow_phase = NarrowPhase::new();
let mut joint_set = JointSet::new();
let mut ccd_solver = CCDSolver::new();
let physics_hooks = ();
let event_handler = ();
let mut created_floor = false;
/* Run the game loop, stepping the simulation once per frame. */
for _ in 0..250 {
physics_pipeline.step(
&gravity,
&integration_parameters,
&mut island_manager,
&mut broad_phase,
&mut narrow_phase,
&mut rigid_body_set,
&mut collider_set,
&mut joint_set,
&mut ccd_solver,
&physics_hooks,
&event_handler,
);
let ball_body = &rigid_body_set[ball_body_handle];
//When ball is at height 5 a floor is create to stop the ball falling to infinity
if ball_body.translation().y<5.0 && !created_floor{
created_floor=true;
print!("\n*****Issue*****\n");
//if line bellow is uncommented it will break the floor and the ball continue falling to infinity
let _do_nothing_collider = collider_set.get_mut(far_away_collider_handle ).unwrap();
let floor = ColliderBuilder::cuboid(100.0, 0.1).build();
collider_set.insert(floor);
}
println!( "Ball altitude: {}", ball_body.translation().y);
}
}
Rapier version: 0.11.1
Thank you for the test case @rrProd. The bug is no longer happening with the latest version of rapier, so I’m closing the issue. Please feel free to open a new issue with a new test case if this bug happens again.