bevy_rapier
bevy_rapier copied to clipboard
RevoluteJoint ignores Transform
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):
Actual (joints enabled):
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
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));
Is this considered a bug?
The above workaround seemed very promising at first, but I was seeing some very bizarre behavior from my vehicle -- almost as if the motor/collider were applying their forces in their "original" orientation or something. My bike was behaving sort of like a "vibrobot".
Ultimately, I was able to work around this by burying the collider in the hierarchy, giving the collider and joint "separate transforms."
commands
.spawn((
TransformBundle::default(),
RigidBody::Dynamic,
ImpulseJoint::new(bike, joint),
))
.with_children(|parent| {
parent.spawn((
TransformBundle::from_transform(Transform::from_rotation(rotation)),
Collider::cylinder(wheel_thickness, wheel_radius),
));
});