dimforge / bevy_rapier

Official Rapier plugin for the Bevy game engine.
https://rapier.rs
Apache License 2.0
1.19k stars 256 forks source link

RevoluteJoint ignores Transform #457

Open dankirkham opened 7 months ago

dankirkham commented 7 months ago

Rapier cylinders are spawned with the flat side facing up. I need to rotate them about the x axis to make them stand up in order to function as a wheel. I am able to do this without the Rapier by providing a Transform to the PbrBundle. However when I try to attach the cylinder to a RevoluteJoint, this rotation is lost. I saw an example where you could provide a position to a ColliderBundle, but that appears to be a deprecated API. How I am I supposed to rotate the Collider?

let mut spawn_wheel = move |x, z| {
    let wheel_y = constants::WHEEL_THICKNESS;

    let joint = RevoluteJointBuilder::new(Vec3::Z)
        .local_anchor1(Vec3::new(x, -constants::TRUCK_HEIGHT / 3., 2. * z))
        .local_anchor2(Vec3::new(0., wheel_y, 0.));

    let transform = Transform {
        translation: Vec3::new(x, -constants::TRUCK_HEIGHT / 3., 2. * z),
        rotation: -Quat::from_rotation_x(PI / 2.),
        ..default()
    };

    child_builder.spawn((
        PbrBundle {
            mesh: mesh.clone(),
            material: material.clone(),
            transform,
            ..default()
        },
        RigidBody::Dynamic,
        Collider::cylinder(
            constants::WHEEL_THICKNESS / 2.,
            constants::WHEEL_DIAMETER / 2.,
        ),
        ImpulseJoint::new(child_builder.parent_entity(), joint),
    ));
};

Expected (joint/physics disabled):

Screen Shot 2023-12-07 at 1 30 12 PM

Actual (joints enabled):

Screen Shot 2023-12-07 at 1 31 31 PM

dankirkham commented 7 months ago

I noticed that there was a rapier3d::geometry::ColliderBuilder and thought that I could use this to set the position of the Collider. Unfortunately, this is not the same as a bevy_rapier3d::geometry::Collider.

let rotation = nalgebra::UnitQuaternion::from_axis_angle(
    &nalgebra::Vector3::z_axis(),
    std::f32::consts::FRAC_PI_2,
);

let position = nalgebra::Isometry3 {
    rotation,
    ..Default::default()
};

let collider_builder = ColliderBuilder::new(SharedShape::cylinder(
    constants::WHEEL_THICKNESS / 2.,
    constants::WHEEL_DIAMETER / 2.,
));

// This yields a rapier3d::geometry::Collider which is
// NOT a bevy_rapier3d::geometry::Collider and thus
// does not implement Bundle.
let collider = collider_builder.position(position).build();

child_builder.spawn((
    PbrBundle {
        mesh: mesh.clone(),
        material: material.clone(),
        ..default()
    },
    RigidBody::Dynamic,
    collider,
    ImpulseJoint::new(child_builder.parent_entity(), joint),
));
error[E0277]: the trait bound `(MaterialMeshBundle<bevy::prelude::StandardMaterial>, bevy_rapier3d::dynamics::RigidBody, bevy_rapier3d::rapier3d::geometry::Collider, bevy_rapier3d::dynamics::ImpulseJoint): Bundle` is not satisfied
0x2a-42 commented 1 week ago

It should work if you convert joint into a GenericJoint and adjust the second local basis.

let mut joint: GenericJoint = RevoluteJointBuilder::new(Vec3::Z)
    .local_anchor1(Vec3::new(x, -constants::TRUCK_HEIGHT / 3., 2. * z))
    .local_anchor2(Vec3::new(0., wheel_y, 0.))
    .into();
joint.set_local_basis2(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2));