bevy_xpbd icon indicating copy to clipboard operation
bevy_xpbd copied to clipboard

Unstable collision with cubes joined by fixed joints

Open azazdeaz opened this issue 1 year ago • 1 comments

I ran into this while experimenting with joints:

  • When two cube colliders
  • joined with fixed joints
  • are hitting ground collider
  • face down
  • at the same time, the solver goes into an unstable state.

This is an edge case, and easy to work around it, but I wanted to open an issue in case it's useful. I'll try to look into this over the weekend.

use bevy::prelude::*;
use bevy_xpbd_3d::{math::*, prelude::*};
use examples_common_3d::XpbdExamplePlugin;

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, XpbdExamplePlugin))
        .insert_resource(ClearColor(Color::rgb(0.05, 0.05, 0.1)))
        .insert_resource(Msaa::Sample4)
        .insert_resource(SubstepCount(50))
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    mut materials: ResMut<Assets<StandardMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
) {
    let cube_mesh = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
    let cube_collider = Collider::cuboid(1.0, 1.0, 1.0);
    let cube_material_1 = materials.add(Color::BEIGE.into());
    let cube_material_2 = materials.add(Color::LIME_GREEN.into());

    // Kinematic rotating "anchor" object
    let anchor = commands
        .spawn((
            PbrBundle {
                mesh: cube_mesh.clone(),
                material: cube_material_1,
                transform: Transform::from_xyz(0.0, 3.5, 0.0),
                ..default()
            },
            MassPropertiesBundle::new_computed(&cube_collider, 1.0),
            cube_collider.clone(),
            // Collider::ball(0.5), // Using ball colliders fixes the issue
            RigidBody::Dynamic,
        ))
        .id();

    // Dynamic object rotating around anchor
    let object = commands
        .spawn((
            PbrBundle {
                mesh: cube_mesh,
                material: cube_material_2,
                transform: Transform::from_xyz(4.0, 3.5, 0.0)
                    // .with_rotation(Quat::from_rotation_x(0.01)) // Uncomment to fix the unstable collision issue
                    ,
                ..default()
            },
            RigidBody::Dynamic,
            MassPropertiesBundle::new_computed(&cube_collider, 1.0),
            cube_collider,
            // Collider::ball(0.5)
        ))
        .id();

    // Connect anchor and dynamic object
    commands.spawn(
        // RevoluteJoint::new(anchor, object) // Using revolute joints fixes the issue
        FixedJoint::new(anchor, object)
            .with_local_anchor_1(Vector::X * 2.0)
            .with_local_anchor_2(Vector::X * -2.0),
    );

    // Ground plane
    commands.spawn((
        RigidBody::Static,
        Collider::cuboid(50.0, 0.1, 50.0),
        PbrBundle {
            mesh: meshes.add(shape::Plane::from_size(50.0).into()),
            material: materials.add(Color::SILVER.into()),
            transform: Transform::from_xyz(0.0, -1.0, 0.0),
            ..default()
        },
    ));

    // Directional light
    commands.spawn(DirectionalLightBundle {
        directional_light: DirectionalLight {
            illuminance: 20_000.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::default().looking_at(Vec3::new(-1.0, -2.5, -1.5), Vec3::Y),
        ..default()
    });

    // Camera
    commands.spawn(Camera3dBundle {
        transform: Transform::from_translation(Vec3::Z * 10.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

https://github.com/Jondolf/bevy_xpbd/assets/2298371/a43cf99c-e53d-4e78-a2a3-a6154cd29c4b

Adding a minimal rotation fixes the issue

https://github.com/Jondolf/bevy_xpbd/assets/2298371/e3411d54-21cb-4c7f-a26f-93e962972714

azazdeaz avatar Nov 07 '23 10:11 azazdeaz

I'm still trying to understand a lot of things about XPBD, but i'm not sure that this is a bug. I don't think the issue is removable without making some joint specific workarounds in the solver. I didn't find any XPBD implementation with fixed joint constrains to compare the behaviours.

The above scenario can be stabilized by adding a non-zero compilance to the joint:

Compilance=0.001 Substeps=50
compilance_0_001_substepcount_50.webm

Compilance=0.01 Substeps=50
compilance_0_01_substepcount_50.webm

Compilance=0.001 Substeps=1 compilance_0_001_substepcount_1.webm

Compilance=0.01 Substeps=1 compilance_0_01_substepcount_1.webm

azazdeaz avatar Nov 18 '23 08:11 azazdeaz