dimforge / rapier

2D and 3D physics engines focused on performance.
https://rapier.rs
Apache License 2.0
3.77k stars 235 forks source link

Nonsymmetric collision with 2 colliders #668

Closed Easyoakland closed 6 days ago

Easyoakland commented 1 week ago
bevy = "0.13.2"
bevy_rapier3d = { version = "0.26.0", features = ["enhanced-determinism", "debug-render-3d"] }

When spawning a cuboid symmetric about x and z and letting it fall due to gravity onto a plane also symmetric about x and z it bounces asymmetrically about x and z. This is strange because the contact force is only in the y direction but yet the cuboid moves in x, y, and z and changes rotation.

...
transform: [0, 2.6107643, 0][0, 0, 0, 1]
transform: [0, 2.5287278, 0][0, 0, 0, 1]
transform: [0, 2.4457104, 0][0, 0, 0, 1]
contact force: ContactForceEvent { collider1: 2v1, collider2: 3v1, total_force: Vec3(0.0, 627313.8, 0.0), total_force_magnitude: 627313.8, max_force_direction: Vec3(0.0, 1.0, 0.0), max_force_magnitude: 181722.42 }
transform: [0.000025853486, 2.4768658, 0.000768425][0.00020019147, -0.0000022479767, -0.000013771602, 1]
contact force: ContactForceEvent { collider1: 2v1, collider2: 3v1, total_force: Vec3(0.0, 323.05383, 0.0), total_force_magnitude: 323.05383, max_force_direction: Vec3(0.0, 1.0, 0.0), max_force_magnitude: 323.05383 }
transform: [-0.00009083122, 2.500795, 0.0010656837][0.00006835201, 0.00007495749, 0.00010290937, 1]

Surely the cuboid should only move along the y-axis without rotation due to symmetry and the force only pointing along the y-axis?

In the following example you can see this effect resulting in one of the corners hitting the y=0 plane before the opposite on the second bounce.

Minimal reproducible example ```rust use bevy::{ecs::schedule::ScheduleLabel, input::common_conditions::input_pressed, prelude::*}; use bevy_rapier3d::prelude::*; #[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)] struct PhysicsSchedule; fn setup_physics(mut commands: Commands) { // Spawn camera commands.spawn(Camera3dBundle { transform: Transform::from_xyz(0.0, 6., 20.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y), ..default() }); // Create the ground. let _ground = commands .spawn(Collider::cuboid(5000.0, 0.50, 5000.0)) .insert(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 0.0))) .id(); // Create box let boxy = commands .spawn(( RigidBody::Dynamic, Collider::cuboid(0.06 * 100., 2.0, 0.06 * 100.), Restitution::coefficient(0.5), TransformBundle::from(Transform::from_xyz(0., 6., 0.)), ActiveEvents::all(), ContactForceEventThreshold(0.), )) .id(); // Print box's transform and collision forces to stderr commands.add(move |world: &mut World| { world.schedule_scope(Update, move |_world, schedule| { schedule.add_systems(move |q: Query<&Transform, Changed>| { if let Ok(x) = q.get(boxy) { eprintln!("transform: {}{}", x.translation, x.rotation); } }); schedule.add_systems(move |mut ev: EventReader| { for e in ev.read() { eprintln!("contact force: {e:?}"); } }); }); }); } fn run_physics(world: &mut World) { world.run_schedule(PhysicsSchedule) } fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(RapierPhysicsPlugin::<()>::default().in_schedule(PhysicsSchedule)) .add_plugins(RapierDebugRenderPlugin::default()) .insert_resource({ let mut out = RapierConfiguration::new(1.); out.timestep_mode = TimestepMode::Fixed { dt: 1. / 100., substeps: 1, }; out }) .add_systems(Startup, setup_physics) .add_systems(Update, run_physics.run_if(input_pressed(KeyCode::Space))) .run(); } ````
sebcrozet commented 6 days ago

Hi! This an expect consequence of the incremental constraints solver. This will generally result in uneven forces at all four contact points. So even if all of these forces are along +Y, the result in a non-zero torque (creating a rotation). The accurate way to fix that is by solving all four constraints simultaneously which is extremely complex and expensive in 3D (we do this in 2D though, resolving two constraints simultaneously).

The alternative is to increase the number of solver iterations, but this is often not worth the performance impact.