aboutsummaryrefslogtreecommitdiff
path: root/src/dynamics/solver/velocity_ground_constraint_wide.rs
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2021-03-08 10:09:43 +0100
committerGitHub <noreply@github.com>2021-03-08 10:09:43 +0100
commitbeaddea6f2596dce936355940fd98ca90945cb65 (patch)
tree22a8e6863cce5daab7782c5de108749e5d046fbb /src/dynamics/solver/velocity_ground_constraint_wide.rs
parente7f805aea45612abb655b3c36a133357fecfcdc4 (diff)
parent152ada67ecd122fe38a9cae8b262542b4abf25fc (diff)
downloadrapier-beaddea6f2596dce936355940fd98ca90945cb65.tar.gz
rapier-beaddea6f2596dce936355940fd98ca90945cb65.tar.bz2
rapier-beaddea6f2596dce936355940fd98ca90945cb65.zip
Merge pull request #146 from dimforge/implicit_friction_cone
Projection friction impulses on an implicit cone instead of a pyramid approximation.
Diffstat (limited to 'src/dynamics/solver/velocity_ground_constraint_wide.rs')
-rw-r--r--src/dynamics/solver/velocity_ground_constraint_wide.rs170
1 files changed, 61 insertions, 109 deletions
diff --git a/src/dynamics/solver/velocity_ground_constraint_wide.rs b/src/dynamics/solver/velocity_ground_constraint_wide.rs
index 8e9f3a1..ba1c46a 100644
--- a/src/dynamics/solver/velocity_ground_constraint_wide.rs
+++ b/src/dynamics/solver/velocity_ground_constraint_wide.rs
@@ -1,51 +1,26 @@
-use super::{AnyVelocityConstraint, DeltaVel};
+use super::{
+ AnyVelocityConstraint, DeltaVel, VelocityGroundConstraintElement,
+ VelocityGroundConstraintNormalPart,
+};
use crate::dynamics::{IntegrationParameters, RigidBodySet};
use crate::geometry::{ContactManifold, ContactManifoldIndex};
use crate::math::{
AngVector, AngularInertia, Point, Real, SimdReal, Vector, DIM, MAX_MANIFOLD_POINTS, SIMD_WIDTH,
};
-use crate::utils::{WAngularInertia, WBasis, WCross, WDot};
+#[cfg(feature = "dim2")]
+use crate::utils::WBasis;
+use crate::utils::{WAngularInertia, WCross, WDot};
use num::Zero;
use simba::simd::{SimdPartialOrd, SimdValue};
#[derive(Copy, Clone, Debug)]
-pub(crate) struct WVelocityGroundConstraintElementPart {
- pub gcross2: AngVector<SimdReal>,
- pub rhs: SimdReal,
- pub impulse: SimdReal,
- pub r: SimdReal,
-}
-
-impl WVelocityGroundConstraintElementPart {
- pub fn zero() -> Self {
- Self {
- gcross2: AngVector::zero(),
- rhs: SimdReal::zero(),
- impulse: SimdReal::zero(),
- r: SimdReal::zero(),
- }
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub(crate) struct WVelocityGroundConstraintElement {
- pub normal_part: WVelocityGroundConstraintElementPart,
- pub tangent_parts: [WVelocityGroundConstraintElementPart; DIM - 1],
-}
-
-impl WVelocityGroundConstraintElement {
- pub fn zero() -> Self {
- Self {
- normal_part: WVelocityGroundConstraintElementPart::zero(),
- tangent_parts: [WVelocityGroundConstraintElementPart::zero(); DIM - 1],
- }
- }
-}
-
-#[derive(Copy, Clone, Debug)]
pub(crate) struct WVelocityGroundConstraint {
pub dir1: Vector<SimdReal>, // Non-penetration force direction for the first body.
- pub elements: [WVelocityGroundConstraintElement; MAX_MANIFOLD_POINTS],
+ #[cfg(feature = "dim3")]
+ pub tangent1: Vector<SimdReal>, // One of the friction force directions.
+ #[cfg(feature = "dim3")]
+ pub tangent_rot1: na::UnitComplex<SimdReal>, // Orientation of the tangent basis wrt. the reference basis.
+ pub elements: [VelocityGroundConstraintElement<SimdReal>; MAX_MANIFOLD_POINTS],
pub num_contacts: u8,
pub im2: SimdReal,
pub limit: SimdReal,
@@ -104,13 +79,23 @@ impl WVelocityGroundConstraint {
let warmstart_coeff = warmstart_multiplier * SimdReal::splat(params.warmstart_coeff);
let num_active_contacts = manifolds[0].data.num_active_contacts();
+ #[cfg(feature = "dim2")]
+ let tangents1 = force_dir1.orthonormal_basis();
+ #[cfg(feature = "dim3")]
+ let (tangents1, tangent_rot1) =
+ super::compute_tangent_contact_directions(&force_dir1, &linvel1, &linvel2);
+
for l in (0..num_active_contacts).step_by(MAX_MANIFOLD_POINTS) {
let manifold_points = array![|ii| &manifolds[ii].data.solver_contacts[l..]; SIMD_WIDTH];
let num_points = manifold_points[0].len().min(MAX_MANIFOLD_POINTS);
let mut constraint = WVelocityGroundConstraint {
dir1: force_dir1,
- elements: [WVelocityGroundConstraintElement::zero(); MAX_MANIFOLD_POINTS],
+ #[cfg(feature = "dim3")]
+ tangent1: tangents1[0],
+ #[cfg(feature = "dim3")]
+ tangent_rot1,
+ elements: [VelocityGroundConstraintElement::zero(); MAX_MANIFOLD_POINTS],
im2,
limit: SimdReal::splat(0.0),
mj_lambda2,
@@ -158,7 +143,7 @@ impl WVelocityGroundConstraint {
rhs +=
dist.simd_min(SimdReal::zero()) * (velocity_based_erp_inv_dt * is_resting);
- constraint.elements[k].normal_part = WVelocityGroundConstraintElementPart {
+ constraint.elements[k].normal_part = VelocityGroundConstraintNormalPart {
gcross2,
rhs,
impulse: impulse * warmstart_coeff,
@@ -167,29 +152,25 @@ impl WVelocityGroundConstraint {
}
// tangent parts.
- let tangents1 = force_dir1.orthonormal_basis();
-
- for j in 0..DIM - 1 {
- #[cfg(feature = "dim2")]
- let impulse = SimdReal::from(
+ #[cfg(feature = "dim2")]
+ let impulse = [SimdReal::from(
+ array![|ii| manifold_points[ii][k].data.tangent_impulse; SIMD_WIDTH],
+ )];
+ #[cfg(feature = "dim3")]
+ let impulse = tangent_rot1
+ * na::Vector2::from(
array![|ii| manifold_points[ii][k].data.tangent_impulse; SIMD_WIDTH],
);
- #[cfg(feature = "dim3")]
- let impulse = SimdReal::from(
- array![|ii| manifold_points[ii][k].data.tangent_impulse[j]; SIMD_WIDTH],
- );
+ constraint.elements[k].tangent_part.impulse = impulse;
+ for j in 0..DIM - 1 {
let gcross2 = ii2.transform_vector(dp2.gcross(-tangents1[j]));
let r = SimdReal::splat(1.0) / (im2 + gcross2.gdot(gcross2));
let rhs = (vel1 - vel2 + tangent_velocity * flipped_sign).dot(&tangents1[j]);
- constraint.elements[k].tangent_parts[j] =
- WVelocityGroundConstraintElementPart {
- gcross2,
- rhs,
- impulse: impulse * warmstart_coeff,
- r,
- };
+ constraint.elements[k].tangent_part.gcross2[j] = gcross2;
+ constraint.elements[k].tangent_part.r[j] = r;
+ constraint.elements[k].tangent_part.rhs[j] = rhs;
}
}
@@ -212,19 +193,14 @@ impl WVelocityGroundConstraint {
),
};
- let tangents1 = self.dir1.orthonormal_basis();
-
- for i in 0..self.num_contacts as usize {
- let elt = &self.elements[i].normal_part;
- mj_lambda2.linear += self.dir1 * (-self.im2 * elt.impulse);
- mj_lambda2.angular += elt.gcross2 * elt.impulse;
-
- for j in 0..DIM - 1 {
- let elt = &self.elements[i].tangent_parts[j];
- mj_lambda2.linear += tangents1[j] * (-self.im2 * elt.impulse);
- mj_lambda2.angular += elt.gcross2 * elt.impulse;
- }
- }
+ VelocityGroundConstraintElement::warmstart_group(
+ &self.elements[..self.num_contacts as usize],
+ &self.dir1,
+ #[cfg(feature = "dim3")]
+ &self.tangent1,
+ self.im2,
+ &mut mj_lambda2,
+ );
for ii in 0..SIMD_WIDTH {
mj_lambdas[self.mj_lambda2[ii] as usize].linear = mj_lambda2.linear.extract(ii);
@@ -235,46 +211,22 @@ impl WVelocityGroundConstraint {
pub fn solve(&mut self, mj_lambdas: &mut [DeltaVel<Real>]) {
let mut mj_lambda2 = DeltaVel {
linear: Vector::from(
- array![ |ii| mj_lambdas[ self.mj_lambda2[ii] as usize].linear; SIMD_WIDTH],
+ array![|ii| mj_lambdas[ self.mj_lambda2[ii] as usize].linear; SIMD_WIDTH],
),
angular: AngVector::from(
- array![ |ii| mj_lambdas[ self.mj_lambda2[ii] as usize].angular; SIMD_WIDTH],
+ array![|ii| mj_lambdas[ self.mj_lambda2[ii] as usize].angular; SIMD_WIDTH],
),
};
- // Solve friction first.
- let tangents1 = self.dir1.orthonormal_basis();
-
- for i in 0..self.num_contacts as usize {
- let normal_elt = &self.elements[i].normal_part;
-
- for j in 0..DIM - 1 {
- let elt = &mut self.elements[i].tangent_parts[j];
- let dimpulse = -tangents1[j].dot(&mj_lambda2.linear)
- + elt.gcross2.gdot(mj_lambda2.angular)
- + elt.rhs;
- let limit = self.limit * normal_elt.impulse;
- let new_impulse = (elt.impulse - elt.r * dimpulse).simd_clamp(-limit, limit);
- let dlambda = new_impulse - elt.impulse;
- elt.impulse = new_impulse;
-
- mj_lambda2.linear += tangents1[j] * (-self.im2 * dlambda);
- mj_lambda2.angular += elt.gcross2 * dlambda;
- }
- }
-
- // Solve non-penetration after friction.
- for i in 0..self.num_contacts as usize {
- let elt = &mut self.elements[i].normal_part;
- let dimpulse =
- -self.dir1.dot(&mj_lambda2.linear) + elt.gcross2.gdot(mj_lambda2.angular) + elt.rhs;
- let new_impulse = (elt.impulse - elt.r * dimpulse).simd_max(SimdReal::zero());
- let dlambda = new_impulse - elt.impulse;
- elt.impulse = new_impulse;
-
- mj_lambda2.linear += self.dir1 * (-self.im2 * dlambda);
- mj_lambda2.angular += elt.gcross2 * dlambda;
- }
+ VelocityGroundConstraintElement::solve_group(
+ &mut self.elements[..self.num_contacts as usize],
+ &self.dir1,
+ #[cfg(feature = "dim3")]
+ &self.tangent1,
+ self.im2,
+ self.limit,
+ &mut mj_lambda2,
+ );
for ii in 0..SIMD_WIDTH {
mj_lambdas[self.mj_lambda2[ii] as usize].linear = mj_lambda2.linear.extract(ii);
@@ -286,11 +238,12 @@ impl WVelocityGroundConstraint {
pub fn writeback_impulses(&self, manifolds_all: &mut [&mut ContactManifold]) {
for k in 0..self.num_contacts as usize {
let impulses: [_; SIMD_WIDTH] = self.elements[k].normal_part.impulse.into();
- let tangent_impulses: [_; SIMD_WIDTH] =
- self.elements[k].tangent_parts[0].impulse.into();
+ #[cfg(feature = "dim2")]
+ let tangent_impulses: [_; SIMD_WIDTH] = self.elements[k].tangent_part.impulse[0].into();
#[cfg(feature = "dim3")]
- let bitangent_impulses: [_; SIMD_WIDTH] =
- self.elements[k].tangent_parts[1].impulse.into();
+ let tangent_impulses = self
+ .tangent_rot1
+ .inverse_transform_vector(&self.elements[k].tangent_part.impulse);
for ii in 0..SIMD_WIDTH {
let manifold = &mut manifolds_all[self.manifold_id[ii]];
@@ -304,8 +257,7 @@ impl WVelocityGroundConstraint {
}
#[cfg(feature = "dim3")]
{
- active_contact.data.tangent_impulse =
- [tangent_impulses[ii], bitangent_impulses[ii]];
+ active_contact.data.tangent_impulse = tangent_impulses.extract(ii);
}
}
}