bevy_xpbd
bevy_xpbd copied to clipboard
Rigidbodies squash and bounce off each other when restitution is zero
Rigidbodies seem to squash and bounce off other bodies despite restitution being disabled on everything. Increasing the density exacerbates this.
Here's a somewhat extreme example, where the yellow cube is very dense. The orientation doesn't matter, but I think it makes the effect more visible.
The issue is also visible in the dynamic_character_2d example when jumping on top of the cube. It doesn't happen every time, but it seems to happen more often when jumping on or near the corner of the cube.
I've also attached the code used to reproduce the issue as in the video.
Show code
use avian2d::prelude::*;
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, PhysicsPlugins::default().with_length_unit(10.0)))
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
// Upper cube (yellow)
commands.spawn((
Sprite {
color: Color::srgb(0.8, 0.8, 0.0),
custom_size: Some(Vec2::new(3.0, 3.0)),
..default()
},
Transform::from_xyz(5.0, 20.0, 0.0).with_rotation(Quat::from_rotation_z(std::f32::consts::PI / 4.)),
RigidBody::Dynamic,
ColliderDensity(1000.),
Restitution::ZERO.with_combine_rule(CoefficientCombine::Min),
Collider::rectangle(3.0, 3.0),
));
// Lower cube (blue)
commands.spawn((
Sprite {
color: Color::srgb(0.0, 0.8, 0.8),
custom_size: Some(Vec2::new(3.0, 3.0)),
..default()
},
Transform::from_xyz(5.0, -15.0, 0.0),
RigidBody::Dynamic,
ColliderDensity(1.),
Restitution::ZERO.with_combine_rule(CoefficientCombine::Min),
Collider::rectangle(3.0, 3.0),
));
// Floor
commands.spawn((
Sprite {
color: Color::srgb(0.7, 0.7, 0.8),
custom_size: Some(Vec2::new(100.0, 5.0)),
..default()
},
Transform::from_xyz(0.0, -20.0, 0.0),
RigidBody::Static,
Restitution::ZERO.with_combine_rule(CoefficientCombine::Min),
Collider::rectangle(100.0, 5.0),
));
// Camera
commands.spawn(Camera2d).insert(OrthographicProjection {
scale: 0.1,
..OrthographicProjection::default_2d()
});
}
For reference, I'm using the latest main: commit c4840ddf4a3adb081bb21c992e524231df83e195
This is "expected" behavior, in that it's a known limitation. It is briefly mentioned in the docs under the Accuracy section here.
The issue here is the large mass ratio of 1:1000, which is something that the vast majority of physics engines and constraint solvers struggle with (specifically dual solvers, if you're interested). If you make the masses closer to each other, it should behave more like you'd expect.
The problem is essentially that the contact between the two dynamic boxes only "sees" their masses, while the contact between the lower box and ground only "sees" the mass of that one box. Each individual contact has no real awareness of any other interactions. Thus, the impulse applied by the high-density box will sort of "overpower" the impulse applied by the ground, and it can take many more solver iterations for the impulses to truly stabilize and converge on an accurate solution.
A similar phenomenon could be seen for a chain consisting of light segments connected by joints, and a heavy sphere at the bottom; the chain will stretch more and more the heavier the bottom sphere is.
Now, even with a mass ratio of 1:1, you might see a very small bounce when the upper box hits the lower box. There could be a few reasons for this, like how Avian (similarly to Box2D and Rapier) uses "soft constraints", which solve constraints "softly" and dampen constraint responses. This remaining bounce can be largely mitigated by tweaking some parameters in the SolverConfig resource; in this case, I noticed that e.g. reducing the contact_frequency_factor helped with this particular issue.