diff options
| author | Sébastien Crozet <sebcrozet@dimforge.com> | 2024-04-14 15:53:35 +0200 |
|---|---|---|
| committer | Sébastien Crozet <sebastien@crozet.re> | 2024-04-30 23:10:46 +0200 |
| commit | 3ddf2441ea6c43aa98718e0ce8650c3b804062d4 (patch) | |
| tree | cb788bf95da707a683fd949d887d071c68934ae6 /src/dynamics/solver/contact_constraint/two_body_constraint.rs | |
| parent | 15c07cfeb3d59f116b26eec32e4590dc45d6c26c (diff) | |
| download | rapier-3ddf2441ea6c43aa98718e0ce8650c3b804062d4.tar.gz rapier-3ddf2441ea6c43aa98718e0ce8650c3b804062d4.tar.bz2 rapier-3ddf2441ea6c43aa98718e0ce8650c3b804062d4.zip | |
feat: add exact mlcp solver for pais of 2 constraints
Diffstat (limited to 'src/dynamics/solver/contact_constraint/two_body_constraint.rs')
| -rw-r--r-- | src/dynamics/solver/contact_constraint/two_body_constraint.rs | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/src/dynamics/solver/contact_constraint/two_body_constraint.rs b/src/dynamics/solver/contact_constraint/two_body_constraint.rs index 8abf5c5..24a5730 100644 --- a/src/dynamics/solver/contact_constraint/two_body_constraint.rs +++ b/src/dynamics/solver/contact_constraint/two_body_constraint.rs @@ -2,11 +2,13 @@ use super::{ContactConstraintTypes, ContactPointInfos}; use crate::dynamics::solver::SolverVel; use crate::dynamics::solver::{AnyConstraintMut, SolverBody}; +use crate::dynamics::integration_parameters::BLOCK_SOLVER_ENABLED; use crate::dynamics::{IntegrationParameters, MultibodyJointSet, RigidBodySet}; use crate::geometry::{ContactManifold, ContactManifoldIndex}; use crate::math::{Isometry, Real, Vector, DIM, MAX_MANIFOLD_POINTS}; use crate::utils::{self, SimdAngularInertia, SimdBasis, SimdCross, SimdDot}; -use na::DVector; +use na::{DVector, Matrix2}; +use num::Pow; use super::{TwoBodyConstraintElement, TwoBodyConstraintNormalPart}; @@ -225,6 +227,7 @@ impl TwoBodyConstraintBuilder { impulse: na::zero(), impulse_accumulator: na::zero(), r: projected_mass, + r_mat_elts: [0.0; 2], }; } @@ -284,6 +287,48 @@ impl TwoBodyConstraintBuilder { builder.infos[k] = infos; constraint.manifold_contact_id[k] = manifold_point.contact_id; } + + if BLOCK_SOLVER_ENABLED { + // Coupling between consecutive pairs. + for k in 0..manifold_points.len() / 2 { + let k0 = k * 2; + let k1 = k * 2 + 1; + + let mut r_mat = Matrix2::zeros(); + let imsum = mprops1.effective_inv_mass + mprops2.effective_inv_mass; + let r0 = constraint.elements[k0].normal_part.r; + let r1 = constraint.elements[k1].normal_part.r; + r_mat.m12 = force_dir1.dot(&imsum.component_mul(&force_dir1)) + + constraint.elements[k0] + .normal_part + .gcross1 + .gdot(constraint.elements[k1].normal_part.gcross1) + + constraint.elements[k0] + .normal_part + .gcross2 + .gdot(constraint.elements[k1].normal_part.gcross2); + r_mat.m21 = r_mat.m12; + r_mat.m11 = utils::inv(r0); + r_mat.m22 = utils::inv(r1); + + if let Some(inv) = r_mat.try_inverse() { + constraint.elements[k0].normal_part.r_mat_elts = [inv.m11, inv.m22]; + constraint.elements[k1].normal_part.r_mat_elts = [inv.m12, r_mat.m12]; + } else { + // If inversion failed, the contacts are redundant. + // Ignore the one with the smallest depth (it is too late to + // have the constraint removed from the constraint set, so just + // set the mass (r) matrix elements to 0. + constraint.elements[k0].normal_part.r_mat_elts = + if manifold_points[k0].dist <= manifold_points[k1].dist { + [r0, 0.0] + } else { + [0.0, r1] + }; + constraint.elements[k1].normal_part.r_mat_elts = [0.0; 2]; + } + } + } } } |
