dimforge / rapier

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

Issue with limits in RopeJoint? #561

Closed ThomasCartier closed 5 months ago

ThomasCartier commented 7 months ago

Hi, The limit doesn't look respected. Is it me or a bug ? Y value goes down to circa 3.26 when it should be circa 4.0:

Looks like a big drift right now:

fn t2() {

          let gravity = vector![0.0, -9.81, 0.0];

          let integration_parameters = IntegrationParameters::default();

          let mut physics_pipeline = PhysicsPipeline::new();

          let mut island_manager = IslandManager::new();

          let mut broad_phase = BroadPhase::new();

          let mut narrow_phase = NarrowPhase::new();

          let mut impulse_joint_set = ImpulseJointSet::new();

          let mut multibody_joint_set = MultibodyJointSet::new();

          let mut ccd_solver = CCDSolver::new();

          let mut collider_set = ColliderSet::new();

          let physics_hooks = ();

          let event_handler = ();

          // -----------------------
          // Simulation setup
          // -----------------------
          let steps_count = 200;

          let mut out: Vec<Vec<[f32; 3]>> = vec![];

          // -------------------
          // Rigid bodies
          // -------------------
          let mut rigid_body_set = RigidBodySet::new();

          let rigid_builder0 = RigidBodyBuilder::dynamic()
                  .translation(vector![0., 5., 0.])
                  .build();

          let hdl0 = rigid_body_set.insert(rigid_builder0);

          let rigid_builder1 = RigidBodyBuilder::dynamic()
                  .translation(vector![0., 5., 0.])
                  .additional_mass(1.)
                  .build();

          let hdl1 = rigid_body_set.insert(rigid_builder1);

          // -----------------------
          // Center of rigid body
          // -----------------------
          let local_zero_vec = point![0., 0., 0.];

          let rope_joint = RopeJointBuilder::new()
                  .local_anchor1(local_zero_vec.into())
                  .local_anchor2(local_zero_vec.into())
                  .limits([0., 1.])
                  .build();

          impulse_joint_set.insert(hdl0, hdl1, rope_joint, true);

          // -----------------------
          // Simulation run
          // -----------------------
          for _ in 0..steps_count {

                  physics_pipeline.step(
                          &gravity,
                          &integration_parameters,
                          &mut island_manager,
                          &mut broad_phase,
                          &mut narrow_phase,
                          &mut rigid_body_set,
                          &mut collider_set,
                          &mut impulse_joint_set,
                          &mut multibody_joint_set,
                          &mut ccd_solver,
                          None,
                          &physics_hooks,
                          &event_handler
                  );

                  let mut current: Vec<[f32; 3]> = vec![];

                  for k in rigid_body_set.iter() {

                          current.push(k.1.position().translation.vector.into());
                  }

                  out.push(current);
          }

          print!("");
  }

Any idea ?

ThomasCartier commented 7 months ago

The issue only arise when I set multiple rotation angles.

with

let mut rope_joint = RopeJointBuilder::new()
        .local_anchor1(local_zero_vec.into())
        .local_anchor2(local_zero_vec.into())
        .build();

rope_joint
        .data
        .set_limits(rapier3d::dynamics::JointAxis::Y, [0., 1.]);

the limit is properly respected at 4. What is going on ?

sebcrozet commented 5 months ago

This was an issue with the way the joint set its limits. By setting the limits on all axes, the joint would actually consider vector![limit_x, limit_y, limit_z].magnitude() as the joint limit (it concatenate the limits in a vector and takes the norm). In your case, that gives an effective limit of 1.73 which explains the difference you were observing.

In the next release (and thanks to #579), the rope will only consider the limit specified along the first axis (i.e. the X axis). The API has changed a bit to so you could simply specify the rope length in its constructor RopeJointBuilder::new(1.0).

ThomasCartier commented 5 months ago

Great news!