aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThierry Berger <contact@thierryberger.com>2024-06-23 18:18:54 +0200
committerGitHub <noreply@github.com>2024-06-23 18:18:54 +0200
commit3e8650f3a761422f0926300dc98f9870e5d92776 (patch)
tree91b95ae4cffd09f993733f2326010867f15205cc /src
parent8a592e458e45c2896c52a931ca04a69868efdd53 (diff)
downloadrapier-3e8650f3a761422f0926300dc98f9870e5d92776.tar.gz
rapier-3e8650f3a761422f0926300dc98f9870e5d92776.tar.bz2
rapier-3e8650f3a761422f0926300dc98f9870e5d92776.zip
Fix delta_time being 0 resulting in incorrect simulation (#660)
* Add failing test * fix tests * better fix * add changelog * fix propagated to `contact_cfm_factor` * PR feedback * more PR feedbacks
Diffstat (limited to 'src')
-rw-r--r--src/dynamics/integration_parameters.rs15
-rw-r--r--src/dynamics/rigid_body_set.rs2
-rw-r--r--src/pipeline/physics_pipeline.rs68
3 files changed, 80 insertions, 5 deletions
diff --git a/src/dynamics/integration_parameters.rs b/src/dynamics/integration_parameters.rs
index 2de58ae..f475fd4 100644
--- a/src/dynamics/integration_parameters.rs
+++ b/src/dynamics/integration_parameters.rs
@@ -181,7 +181,12 @@ impl IntegrationParameters {
/// [`Self::contact_damping_ratio`] and the substep length.
pub fn contact_cfm_factor(&self) -> Real {
// Compute CFM assuming a critically damped spring multiplied by the damping ratio.
- let inv_erp_minus_one = 1.0 / self.contact_erp() - 1.0;
+ // The logic is similar to [`Self::joint_cfm_coeff`].
+ let contact_erp = self.contact_erp();
+ if contact_erp == 0.0 {
+ return 0.0;
+ }
+ let inv_erp_minus_one = 1.0 / contact_erp - 1.0;
// let stiffness = 4.0 * damping_ratio * damping_ratio * projected_mass
// / (dt * dt * inv_erp_minus_one * inv_erp_minus_one);
@@ -220,8 +225,12 @@ impl IntegrationParameters {
/// [`Self::joint_damping_ratio`] and the substep length.
pub fn joint_cfm_coeff(&self) -> Real {
// Compute CFM assuming a critically damped spring multiplied by the damping ratio.
- // The logic is similar to `Self::cfm_factor`.
- let inv_erp_minus_one = 1.0 / self.joint_erp() - 1.0;
+ // The logic is similar to `Self::contact_cfm_factor`.
+ let joint_erp = self.joint_erp();
+ if joint_erp == 0.0 {
+ return 0.0;
+ }
+ let inv_erp_minus_one = 1.0 / joint_erp - 1.0;
inv_erp_minus_one * inv_erp_minus_one
/ ((1.0 + inv_erp_minus_one)
* 4.0
diff --git a/src/dynamics/rigid_body_set.rs b/src/dynamics/rigid_body_set.rs
index a7d2ec3..2ef91be 100644
--- a/src/dynamics/rigid_body_set.rs
+++ b/src/dynamics/rigid_body_set.rs
@@ -23,7 +23,7 @@ impl BodyPair {
}
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
-#[derive(Clone, Default)]
+#[derive(Clone, Default, Debug)]
/// A set of rigid bodies that can be handled by a physics pipeline.
pub struct RigidBodySet {
// NOTE: the pub(crate) are needed by the broad phase
diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs
index 95e408f..7723fc3 100644
--- a/src/pipeline/physics_pipeline.rs
+++ b/src/pipeline/physics_pipeline.rs
@@ -662,6 +662,8 @@ impl PhysicsPipeline {
#[cfg(test)]
mod test {
+ use na::point;
+
use crate::dynamics::{
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, RigidBodyBuilder,
RigidBodySet,
@@ -669,7 +671,7 @@ mod test {
use crate::geometry::{BroadPhaseMultiSap, ColliderBuilder, ColliderSet, NarrowPhase};
use crate::math::Vector;
use crate::pipeline::PhysicsPipeline;
- use crate::prelude::{MultibodyJointSet, RigidBodyType};
+ use crate::prelude::{MultibodyJointSet, RevoluteJointBuilder, RigidBodyType};
#[test]
fn kinematic_and_fixed_contact_crash() {
@@ -937,4 +939,68 @@ mod test {
// Expect body to now be in active_dynamic_set
assert!(islands.active_dynamic_set.contains(&h));
}
+
+ #[test]
+ fn joint_step_delta_time_0() {
+ let mut colliders = ColliderSet::new();
+ let mut impulse_joints = ImpulseJointSet::new();
+ let mut multibody_joints = MultibodyJointSet::new();
+ let mut pipeline = PhysicsPipeline::new();
+ let mut bf = BroadPhaseMultiSap::new();
+ let mut nf = NarrowPhase::new();
+ let mut islands = IslandManager::new();
+
+ let mut bodies = RigidBodySet::new();
+
+ // Initialize bodies
+ let rb = RigidBodyBuilder::fixed().additional_mass(1.0).build();
+ let h = bodies.insert(rb.clone());
+ let rb_dynamic = RigidBodyBuilder::dynamic().additional_mass(1.0).build();
+ let h_dynamic = bodies.insert(rb_dynamic.clone());
+
+ // Add joint
+ #[cfg(feature = "dim2")]
+ let joint = RevoluteJointBuilder::new()
+ .local_anchor1(point![0.0, 1.0])
+ .local_anchor2(point![0.0, -3.0]);
+ #[cfg(feature = "dim3")]
+ let joint = RevoluteJointBuilder::new(Vector::z_axis())
+ .local_anchor1(point![0.0, 1.0, 0.0])
+ .local_anchor2(point![0.0, -3.0, 0.0]);
+ impulse_joints.insert(h, h_dynamic, joint, true);
+
+ let mut parameters = IntegrationParameters::default();
+ parameters.dt = 0.0;
+ // Step once
+ let gravity = Vector::y() * -9.81;
+ pipeline.step(
+ &gravity,
+ &parameters,
+ &mut islands,
+ &mut bf,
+ &mut nf,
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ &mut CCDSolver::new(),
+ None,
+ &(),
+ &(),
+ );
+ let translation = bodies[h_dynamic].translation();
+ let rotation = bodies[h_dynamic].rotation();
+ assert!(translation.x.is_finite());
+ assert!(translation.y.is_finite());
+ #[cfg(feature = "dim2")]
+ assert!(rotation.is_finite());
+ #[cfg(feature = "dim3")]
+ {
+ assert!(translation.z.is_finite());
+ assert!(rotation.i.is_finite());
+ assert!(rotation.j.is_finite());
+ assert!(rotation.k.is_finite());
+ assert!(rotation.w.is_finite());
+ }
+ }
}