aboutsummaryrefslogtreecommitdiff
path: root/src/dynamics/solver/joint_constraint/prismatic_velocity_constraint_wide.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/dynamics/solver/joint_constraint/prismatic_velocity_constraint_wide.rs')
-rw-r--r--src/dynamics/solver/joint_constraint/prismatic_velocity_constraint_wide.rs848
1 files changed, 0 insertions, 848 deletions
diff --git a/src/dynamics/solver/joint_constraint/prismatic_velocity_constraint_wide.rs b/src/dynamics/solver/joint_constraint/prismatic_velocity_constraint_wide.rs
deleted file mode 100644
index 984adcb..0000000
--- a/src/dynamics/solver/joint_constraint/prismatic_velocity_constraint_wide.rs
+++ /dev/null
@@ -1,848 +0,0 @@
-use simba::simd::{SimdBool as _, SimdPartialOrd, SimdValue};
-
-use crate::dynamics::solver::DeltaVel;
-use crate::dynamics::{
- IntegrationParameters, JointGraphEdge, JointIndex, JointParams, PrismaticJoint, RigidBodyIds,
- RigidBodyMassProps, RigidBodyPosition, RigidBodyVelocity,
-};
-use crate::math::{
- AngVector, AngularInertia, Isometry, Point, Real, SimdBool, SimdReal, Vector, SIMD_WIDTH,
-};
-use crate::utils::{WAngularInertia, WCross, WCrossMatrix, WDot};
-
-#[cfg(feature = "dim3")]
-use na::{Cholesky, Matrix3x2, Matrix5, Vector3, Vector5};
-
-#[cfg(feature = "dim2")]
-use {
- na::{Matrix2, Vector2},
- parry::utils::SdpMatrix2,
-};
-
-#[cfg(feature = "dim2")]
-const LIN_IMPULSE_DIM: usize = 1;
-
-#[cfg(feature = "dim3")]
-const LIN_IMPULSE_DIM: usize = 2;
-
-#[derive(Debug)]
-pub(crate) struct WPrismaticVelocityConstraint {
- mj_lambda1: [usize; SIMD_WIDTH],
- mj_lambda2: [usize; SIMD_WIDTH],
-
- joint_id: [JointIndex; SIMD_WIDTH],
-
- r1: Vector<SimdReal>,
- r2: Vector<SimdReal>,
-
- #[cfg(feature = "dim3")]
- inv_lhs: Matrix5<SimdReal>,
- #[cfg(feature = "dim3")]
- rhs: Vector5<SimdReal>,
- #[cfg(feature = "dim3")]
- impulse: Vector5<SimdReal>,
-
- #[cfg(feature = "dim2")]
- inv_lhs: Matrix2<SimdReal>,
- #[cfg(feature = "dim2")]
- rhs: Vector2<SimdReal>,
- #[cfg(feature = "dim2")]
- impulse: Vector2<SimdReal>,
-
- limits_active: bool,
- limits_impulse: SimdReal,
- limits_forcedir2: Vector<SimdReal>,
- limits_rhs: SimdReal,
- limits_inv_lhs: SimdReal,
- limits_impulse_limits: (SimdReal, SimdReal),
-
- #[cfg(feature = "dim2")]
- basis1: Vector2<SimdReal>,
- #[cfg(feature = "dim3")]
- basis1: Matrix3x2<SimdReal>,
-
- im1: SimdReal,
- im2: SimdReal,
-
- ii1_sqrt: AngularInertia<SimdReal>,
- ii2_sqrt: AngularInertia<SimdReal>,
-}
-
-impl WPrismaticVelocityConstraint {
- pub fn from_params(
- params: &IntegrationParameters,
- joint_id: [JointIndex; SIMD_WIDTH],
- rbs1: (
- [&RigidBodyPosition; SIMD_WIDTH],
- [&RigidBodyVelocity; SIMD_WIDTH],
- [&RigidBodyMassProps; SIMD_WIDTH],
- [&RigidBodyIds; SIMD_WIDTH],
- ),
- rbs2: (
- [&RigidBodyPosition; SIMD_WIDTH],
- [&RigidBodyVelocity; SIMD_WIDTH],
- [&RigidBodyMassProps; SIMD_WIDTH],
- [&RigidBodyIds; SIMD_WIDTH],
- ),
- cparams: [&PrismaticJoint; SIMD_WIDTH],
- ) -> Self {
- let (poss1, vels1, mprops1, ids1) = rbs1;
- let (poss2, vels2, mprops2, ids2) = rbs2;
-
- let position1 = Isometry::from(gather![|ii| poss1[ii].position]);
- let linvel1 = Vector::from(gather![|ii| vels1[ii].linvel]);
- let angvel1 = AngVector::<SimdReal>::from(gather![|ii| vels1[ii].angvel]);
- let world_com1 = Point::from(gather![|ii| mprops1[ii].world_com]);
- let im1 = SimdReal::from(gather![|ii| mprops1[ii].effective_inv_mass]);
- let ii1_sqrt = AngularInertia::<SimdReal>::from(gather![
- |ii| mprops1[ii].effective_world_inv_inertia_sqrt
- ]);
- let mj_lambda1 = gather![|ii| ids1[ii].active_set_offset];
-
- let position2 = Isometry::from(gather![|ii| poss2[ii].position]);
- let linvel2 = Vector::from(gather![|ii| vels2[ii].linvel]);
- let angvel2 = AngVector::<SimdReal>::from(gather![|ii| vels2[ii].angvel]);
- let world_com2 = Point::from(gather![|ii| mprops2[ii].world_com]);
- let im2 = SimdReal::from(gather![|ii| mprops2[ii].effective_inv_mass]);
- let ii2_sqrt = AngularInertia::<SimdReal>::from(gather![
- |ii| mprops2[ii].effective_world_inv_inertia_sqrt
- ]);
- let mj_lambda2 = gather![|ii| ids2[ii].active_set_offset];
-
- let local_anchor1 = Point::from(gather![|ii| cparams[ii].local_anchor1]);
- let local_anchor2 = Point::from(gather![|ii| cparams[ii].local_anchor2]);
- let local_axis1 = Vector::from(gather![|ii| *cparams[ii].local_axis1]);
- let local_axis2 = Vector::from(gather![|ii| *cparams[ii].local_axis2]);
-
- #[cfg(feature = "dim2")]
- let local_basis1 = [Vector::from(gather![|ii| cparams[ii].basis1[0]])];
- #[cfg(feature = "dim3")]
- let local_basis1 = [
- Vector::from(gather![|ii| cparams[ii].basis1[0]]),
- Vector::from(gather![|ii| cparams[ii].basis1[1]]),
- ];
-
- #[cfg(feature = "dim2")]
- let impulse = Vector2::from(gather![|ii| cparams[ii].impulse]);
- #[cfg(feature = "dim3")]
- let impulse = Vector5::from(gather![|ii| cparams[ii].impulse]);
-
- let anchor1 = position1 * local_anchor1;
- let anchor2 = position2 * local_anchor2;
- let axis1 = position1 * local_axis1;
- let axis2 = position2 * local_axis2;
-
- #[cfg(feature = "dim2")]
- let basis1 = position1 * local_basis1[0];
- #[cfg(feature = "dim3")]
- let basis1 =
- Matrix3x2::from_columns(&[position1 * local_basis1[0], position1 * local_basis1[1]]);
-
- // #[cfg(feature = "dim2")]
- // let r21 = Rotation::rotation_between_axis(&axis1, &axis2)
- // .to_rotation_matrix()
- // .into_inner();
- // #[cfg(feature = "dim3")]
- // let r21 = Rotation::rotation_between_axis(&axis1, &axis2)
- // .unwrap_or_else(Rotation::identity)
- // .to_rotation_matrix()
- // .into_inner();
- // let basis2 = r21 * basis1;
- // NOTE: we use basis2 := basis1 for now is that allows
- // simplifications of the computation without introducing
- // much instabilities.
-
- let ii1 = ii1_sqrt.squared();
- let r1 = anchor1 - world_com1;
- let r1_mat = r1.gcross_matrix();
-
- let ii2 = ii2_sqrt.squared();
- let r2 = anchor2 - world_com2;
- let r2_mat = r2.gcross_matrix();
-
- #[allow(unused_mut)] // For 2D.
- let mut lhs;
-
- #[cfg(feature = "dim3")]
- {
- let r1_mat_b1 = r1_mat * basis1;
- let r2_mat_b1 = r2_mat * basis1;
-
- lhs = Matrix5::zeros();
- let lhs00 = ii1.quadform3x2(&r1_mat_b1).add_diagonal(im1)
- + ii2.quadform3x2(&r2_mat_b1).add_diagonal(im2);
- let lhs10 = ii1 * r1_mat_b1 + ii2 * r2_mat_b1;
- let lhs11 = (ii1 + ii2).into_matrix();
- lhs.fixed_slice_mut::<2, 2>(0, 0)
- .copy_from(&lhs00.into_matrix());
- lhs.fixed_slice_mut::<3, 2>(2, 0).copy_from(&lhs10);
- lhs.fixed_slice_mut::<3, 3>(2, 2).copy_from(&lhs11);
- }
-
- #[cfg(feature = "dim2")]
- {
- let b1r1 = basis1.dot(&r1_mat);
- let b2r2 = basis1.dot(&r2_mat);
- let m11 = im1 + im2 + b1r1 * ii1 * b1r1 + b2r2 * ii2 * b2r2;
- let m12 = basis1.dot(&r1_mat) * ii1 + basis1.dot(&r2_mat) * ii2;
- let m22 = ii1 + ii2;
- lhs = SdpMatrix2::new(m11, m12, m22);
- }
-
- let anchor_linvel1 = linvel1 + angvel1.gcross(r1);
- let anchor_linvel2 = linvel2 + angvel2.gcross(r2);
-
- // NOTE: we don't use Cholesky in 2D because we only have a 2x2 matrix
- // for which a textbook inverse is still efficient.
- #[cfg(feature = "dim2")]
- let inv_lhs = lhs.inverse_unchecked().into_matrix();
- #[cfg(feature = "dim3")]
- let inv_lhs = Cholesky::new_unchecked(lhs).inverse();
-
- let linvel_err = basis1.tr_mul(&(anchor_linvel2 - anchor_linvel1));
- let angvel_err = angvel2 - angvel1;
-
- let velocity_solve_fraction = SimdReal::splat(params.velocity_solve_fraction);
-
- #[cfg(feature = "dim2")]
- let mut rhs = Vector2::new(linvel_err.x, angvel_err) * velocity_solve_fraction;
- #[cfg(feature = "dim3")]
- let mut rhs = Vector5::new(
- linvel_err.x,
- linvel_err.y,
- angvel_err.x,
- angvel_err.y,
- angvel_err.z,
- ) * velocity_solve_fraction;
-
- let velocity_based_erp_inv_dt = params.velocity_based_erp_inv_dt();
- if velocity_based_erp_inv_dt != 0.0 {
- let velocity_based_erp_inv_dt = SimdReal::splat(velocity_based_erp_inv_dt);
-
- let linear_err = basis1.tr_mul(&(anchor2 - anchor1));
-
- let local_frame1 = Isometry::from(gather![|ii| cparams[ii].local_frame1()]);
- let local_frame2 = Isometry::from(gather![|ii| cparams[ii].local_frame2()]);
-
- let frame1 = position1 * local_frame1;
- let frame2 = position2 * local_frame2;
- let ang_err = frame2.rotation * frame1.rotation.inverse();
-
- #[cfg(feature = "dim2")]
- {
- rhs += Vector2::new(linear_err.x, ang_err.angle()) * velocity_based_erp_inv_dt;
- }
-
- #[cfg(feature = "dim3")]
- {
- let ang_err = Vector3::from(gather![|ii| ang_err.extract(ii).scaled_axis()]);
- rhs += Vector5::new(linear_err.x, linear_err.y, ang_err.x, ang_err.y, ang_err.z)
- * velocity_based_erp_inv_dt;
- }
- }
-
- // Setup limit constraint.
- let zero: SimdReal = na::zero();
- let limits_forcedir2 = axis2; // hopefully axis1 is colinear with axis2
- let mut limits_active = false;
- let mut limits_rhs = zero;
- let mut limits_impulse = zero;
- let mut limits_inv_lhs = zero;
- let mut limits_impulse_limits = (zero, zero);
-
- let limits_enabled = SimdBool::from(gather![|ii| cparams[ii].limits_enabled]);
- if limits_enabled.any() {
- let danchor = anchor2 - anchor1;
- let dist = danchor.dot(&axis1);
-
- // TODO: we should allow predictive constraint activation.
-
- let min_limit = SimdReal::from(gather![|ii| cparams[ii].limits[0]]);
- let max_limit = SimdReal::from(gather![|ii| cparams[ii].limits[1]]);
-
- let min_enabled = dist.simd_lt(min_limit);
- let max_enabled = dist.simd_gt(max_limit);
-
- limits_impulse_limits.0 = SimdReal::splat(-Real::INFINITY).select(max_enabled, zero);
- limits_impulse_limits.1 = SimdReal::splat(Real::INFINITY).select(min_enabled, zero);
-
- limits_active = (min_enabled | max_enabled).any();
- if limits_active {
- let gcross1 = r1.gcross(axis1);
- let gcross2 = r2.gcross(axis2);
-
- limits_rhs = (anchor_linvel2.dot(&axis2) - anchor_linvel1.dot(&axis1))
- * velocity_solve_fraction;
-
- limits_rhs += ((dist - max_limit).simd_max(zero)
- - (min_limit - dist).simd_max(zero))
- * SimdReal::splat(velocity_based_erp_inv_dt);
-
- limits_impulse = SimdReal::from(gather![|ii| cparams[ii].limits_impulse])
- .simd_max(limits_impulse_limits.0)
- .simd_min(limits_impulse_limits.1);
-
- limits_inv_lhs = SimdReal::splat(1.0)
- / (im1
- + im2
- + gcross1.gdot(ii1.transform_vector(gcross1))
- + gcross2.gdot(ii2.transform_vector(gcross2)));
- }
- }
-
- WPrismaticVelocityConstraint {
- joint_id,
- mj_lambda1,
- mj_lambda2,
- im1,
- ii1_sqrt,
- im2,
- ii2_sqrt,
- limits_active,
- impulse: impulse * SimdReal::splat(params.warmstart_coeff),
- limits_impulse: limits_impulse * SimdReal::splat(params.warmstart_coeff),
- limits_forcedir2,
- limits_rhs,
- limits_inv_lhs,
- limits_impulse_limits,
- basis1,
- inv_lhs,
- rhs,
- r1,
- r2,
- }
- }
-
- pub fn warmstart(&self, mj_lambdas: &mut [DeltaVel<Real>]) {
- let mut mj_lambda1 = DeltaVel {
- linear: Vector::from(gather![|ii| mj_lambdas[self.mj_lambda1[ii] as usize].linear]),
- angular: AngVector::from(gather![
- |ii| mj_lambdas[self.mj_lambda1[ii] as usize].angular
- ]),
- };
- let mut mj_lambda2 = DeltaVel {
- linear: Vector::from(gather![|ii| mj_lambdas[self.mj_lambda2[ii] as usize].linear]),
- angular: AngVector::from(gather![
- |ii| mj_lambdas[self.mj_lambda2[ii] as usize].angular
- ]),
- };
-
- let lin_impulse = self.basis1 * self.impulse.fixed_rows::<LIN_IMPULSE_DIM>(0).into_owned();
- #[cfg(feature = "dim2")]
- let ang_impulse = self.impulse.y;
- #[cfg(feature = "dim3")]
- let ang_impulse = self.impulse.fixed_rows::<3>(2).into_owned();
-
- mj_lambda1.linear += lin_impulse * self.im1;
- mj_lambda1.angular += self
- .ii1_sqrt
- .transform_vector(ang_impulse + self.r1.gcross(lin_impulse));
-
- mj_lambda2.linear -= lin_impulse * self.im2;
- mj_lambda2.angular -= self
- .ii2_sqrt
- .transform_vector(ang_impulse + self.r2.gcross(lin_impulse));
-
- // Warmstart limits.
- if self.limits_active {
- let limit_impulse1 = -self.limits_forcedir2 * self.limits_impulse;
- let limit_impulse2 = self.limits_forcedir2 * self.limits_impulse;
-
- mj_lambda1.linear += limit_impulse1 * self.im1;
- mj_lambda1.angular += self
- .ii1_sqrt
- .transform_vector(self.r1.gcross(limit_impulse1));
- mj_lambda2.linear += limit_impulse2 * self.im2;
- mj_lambda2.angular += self
- .ii2_sqrt
- .transform_vector(self.r2.gcross(limit_impulse2));
- }
-
- for ii in 0..SIMD_WIDTH {
- mj_lambdas[self.mj_lambda1[ii] as usize].linear = mj_lambda1.linear.extract(ii);
- mj_lambdas[self.mj_lambda1[ii] as usize].angular = mj_lambda1.angular.extract(ii);
- }
- for ii in 0..SIMD_WIDTH {
- mj_lambdas[self.mj_lambda2[ii] as usize].linear = mj_lambda2.linear.extract(ii);
- mj_lambdas[self.mj_lambda2[ii] as usize].angular = mj_lambda2.angular.extract(ii);
- }
- }
-
- fn solve_dofs(
- &mut self,
- mj_lambda1: &mut DeltaVel<SimdReal>,
- mj_lambda2: &mut DeltaVel<SimdReal>,
- ) {
- let ang_vel1 = self.ii1_sqrt.transform_vector(mj_lambda1.angular);
- let ang_vel2 = self.ii2_sqrt.transform_vector(mj_lambda2.angular);
- let lin_vel1 = mj_lambda1.linear + ang_vel1.gcross(self.r1);
- let lin_vel2 = mj_lambda2.linear + ang_vel2.gcross(self.r2);
- let lin_dvel = self.basis1.tr_mul(&(lin_vel2 - lin_vel1));
- let ang_dvel = ang_vel2 - ang_vel1;
- #[cfg(feature = "dim2")]
- let rhs = Vector2::new(lin_dvel.x, ang_dvel) + self.rhs;
- #[cfg(feature = "dim3")]
- let rhs =
- Vector5::new(lin_dvel.x, lin_dvel.y, ang_dvel.x, ang_dvel.y, ang_dvel.z) + self.rhs;
- let impulse = self.inv_lhs * rhs;
- self.impulse += impulse;
- let lin_impulse = self.basis1 * impulse.fixed_rows::<LIN_IMPULSE_DIM>(0).into_owned();
- #[cfg(feature = "dim2")]
- let ang_impulse = impulse.y;
- #[cfg(feature = "dim3")]
- let ang_impulse = impulse.fixed_rows::<3>(2).into_owned();
-
- mj_lambda1.linear += lin_impulse * self.im1;
- mj_lambda1.angular += self
- .ii1_sqrt
- .transform_vector(ang_impulse + self.r1.gcross(lin_impulse));
-
- mj_lambda2.linear -= lin_impulse * self.im2;
- mj_lambda2.angular -= self
- .ii2_sqrt
- .transform_vector(ang_impulse + self.r2.gcross(lin_impulse));
- }
-
- fn solve_limits(
- &mut self,
- mj_lambda1: &mut DeltaVel<SimdReal>,
- mj_lambda2: &mut DeltaVel<SimdReal>,
- ) {
- if self.limits_active {
- let limits_forcedir1 = -self.limits_forcedir2;
- let limits_forcedir2 = self.limits_forcedir2;
-
- let ang_vel1 = self.ii1_sqrt.transform_vector(mj_lambda1.angular);
- let ang_vel2 = self.ii2_sqrt.transform_vector(mj_lambda2.angular);
-
- let lin_dvel = limits_forcedir2.dot(&(mj_lambda2.linear + ang_vel2.gcross(self.r2)))
- + limits_forcedir1.dot(&(mj_lambda1.linear + ang_vel1.gcross(self.r1)))
- + self.limits_rhs;
- let new_impulse = (self.limits_impulse - lin_dvel * self.limits_inv_lhs)
- .simd_max(self.limits_impulse_limits.0)
- .simd_min(self.limits_impulse_limits.1);
- let dimpulse = new_impulse - self.limits_impulse;
- self.limits_impulse = new_impulse;
-
- let lin_impulse1 = limits_forcedir1 * dimpulse;
- let lin_impulse2 = limits_forcedir2 * dimpulse;
-
- mj_lambda1.linear += lin_impulse1 * self.im1;
- mj_lambda1.angular += self.ii1_sqrt.transform_vector(self.r1.gcross(lin_impulse1));
- mj_lambda2.linear += lin_impulse2 * self.im2;
- mj_lambda2.angular += self.ii2_sqrt.transform_vector(self.r2.gcross(lin_impulse2));
- }
- }
-
- pub fn solve(&mut self, mj_lambdas: &mut [DeltaVel<Real>]) {
- let mut mj_lambda1 = DeltaVel {
- linear: Vector::from(gather![|ii| mj_lambdas[self.mj_lambda1[ii] as usize].linear]),
- angular: AngVector::from(gather![
- |ii| mj_lambdas[self.mj_lambda1[ii] as usize].angular
- ]),
- };
- let mut mj_lambda2 = DeltaVel {
- linear: Vector::from(gather![|ii| mj_lambdas[self.mj_lambda2[ii] as usize].linear]),
- angular: AngVector::from(gather![
- |ii| mj_lambdas[self.mj_lambda2[ii] as usize].angular
- ]),
- };
-
- self.solve_dofs(&mut mj_lambda1, &mut mj_lambda2);
- self.solve_limits(&mut mj_lambda1, &mut mj_lambda2);
-
- for ii in 0..SIMD_WIDTH {
- mj_lambdas[self.mj_lambda1[ii] as usize].linear = mj_lambda1.linear.extract(ii);
- mj_lambdas[self.mj_lambda1[ii] as usize].angular = mj_lambda1.angular.extract(ii);
- }
- for ii in 0..SIMD_WIDTH {
- mj_lambdas[self.mj_lambda2[ii] as usize].linear = mj_lambda2.linear.extract(ii);
- mj_lambdas[self.mj_lambda2[ii] as usize].angular = mj_lambda2.angular.extract(ii);
- }
- }
-
- pub fn writeback_impulses(&self, joints_all: &mut [JointGraphEdge]) {
- for ii in 0..SIMD_WIDTH {
- let joint = &mut joints_all[self.joint_id[ii]].weight;
- if let JointParams::PrismaticJoint(rev) = &mut joint.params {
- rev.impulse = self.impulse.extract(ii);
- rev.limits_impulse = self.limits_impulse.extract(ii);
- }
- }
- }
-}
-
-#[derive(Debug)]
-pub(crate) struct WPrismaticVelocityGroundConstraint {
- mj_lambda2: [usize; SIMD_WIDTH],
-
- joint_id: [JointIndex; SIMD_WIDTH],
-
- r2: Vector<SimdReal>,
-
- #[cfg(feature = "dim2")]
- inv_lhs: Matrix2<SimdReal>,
- #[cfg(feature = "dim2")]
- rhs: Vector2<SimdReal>,
- #[cfg(feature = "dim2")]
- impulse: Vector2<SimdReal>,
-
- #[cfg(feature = "dim3")]
- inv_lhs: Matrix5<SimdReal>,
- #[cfg(feature = "dim3")]
- rhs: Vector5<SimdReal>,
- #[cfg(feature = "dim3")]
- impulse: Vector5<SimdReal>,
-
- limits_active: bool,
- limits_forcedir2: Vector<SimdReal>,
- limits_impulse: SimdReal,
- limits_rhs: SimdReal,
- limits_impulse_limits: (SimdReal, SimdReal),
-
- axis2: Vector<SimdReal>,
- #[cfg(feature = "dim2")]
- basis1: Vector2<SimdReal>,
- #[cfg(feature = "dim3")]
- basis1: Matrix3x2<SimdReal>,
-
- im2: SimdReal,
- ii2_sqrt: AngularInertia<SimdReal>,
-}
-
-impl WPrismaticVelocityGroundConstraint {
- pub fn from_params(
- params: &IntegrationParameters,
- joint_id: [JointIndex; SIMD_WIDTH],
- rbs1: (
- [&RigidBodyPosition; SIMD_WIDTH],
- [&RigidBodyVelocity; SIMD_WIDTH],
- [&RigidBodyMassProps; SIMD_WIDTH],
- ),
- rbs2: (
- [&RigidBodyPosition; SIMD_WIDTH],
- [&RigidBodyVelocity; SIMD_WIDTH],
- [&RigidBodyMassProps; SIMD_WIDTH],
- [&RigidBodyIds; SIMD_WIDTH],
- ),
- cparams: [&PrismaticJoint; SIMD_WIDTH],
- flipped: [bool; SIMD_WIDTH],
- ) -> Self {
- let (poss1, vels1, mprops1) = rbs1;
- let (poss2, vels2, mprops2, ids2) = rbs2;
-
- let position1 = Isometry::from(gather![|ii| poss1[ii].position]);
- let linvel1 = Vector::from(gather![|ii| vels1[ii].linvel]);
- let angvel1 = AngVector::<SimdReal>::from(gather![|ii| vels1[ii].angvel]);
- let world_com1 = Point::from(gather![|ii| mprops1[ii].world_com]);
-
- let position2 = Isometry::from(gather![|ii| poss2[ii].position]);
- let linvel2 = Vector::from(gather![|ii| vels2[ii].linvel]);
- let angvel2 = AngVector::<SimdReal>::from(gather![|ii| vels2[ii].angvel]);
- let world_com2 = Point::from(gather![|ii| mprops2[ii].world_com]);
- let im2 = SimdReal::from(gather![|ii| mprops2[ii].effective_inv_mass]);
- let ii2_sqrt = AngularInertia::<SimdReal>::from(gather![
- |ii| mprops2[ii].effective_world_inv_inertia_sqrt
- ]);
- let mj_lambda2 = gather![|ii| ids2[ii].active_set_offset];
-
- #[cfg(feature = "dim2")]
- let impulse = Vector2::from(gather![|ii| cparams[ii].impulse]);
- #[cfg(feature = "dim3")]
- let impulse = Vector5::from(gather![|ii| cparams[ii].impulse]);
-
- let local_anchor1 = Point::from(gather![|ii| if flipped[ii] {
- cparams[ii].local_anchor2
- } else {
- cparams[ii].local_anchor1
- }]);
- let local_anchor2 = Point::from(gather![|ii| if flipped[ii] {
- cparams[ii].local_anchor1
- } else {
- cparams[ii].local_anchor2
- }]);
- let local_axis1 = Vector::from(gather![|ii| if flipped[ii] {
- *cparams[ii].local_axis2
- } else {
- *cparams[ii].local_axis1
- }]);
- let local_axis2 = Vector::from(gather![|ii| if flipped[ii] {
- *cparams[ii].local_axis1
- } else {
- *cparams[ii].local_axis2
- }]);
-
- #[cfg(feature = "dim2")]
- let basis1 = position1
- * Vector::from(gather![|ii| if flipped[ii] {
- cparams[ii].basis2[0]
- } else {
- cparams[ii].basis1[0]
- }]);
- #[cfg(feature = "dim3")]
- let basis1 = Matrix3x2::from_columns(&[
- position1
- * Vector::from(gather![|ii| if flipped[ii] {
- cparams[ii].basis2[0]
- } else {
- cparams[ii].basis1[0]
- }]),
- position1
- * Vector::from(gather![|ii| if flipped[ii] {
- cparams[ii].basis2[1]
- } else {
- cparams[ii].basis1[1]
- }]),
- ]);
-
- let anchor1 = position1 * local_anchor1;
- let anchor2 = position2 * local_anchor2;
- let axis1 = position1 * local_axis1;
- let axis2 = position2 * local_axis2;
-
- let ii2 = ii2_sqrt.squared();
- let r1 = anchor1 - world_com1;
- let r2 = anchor2 - world_com2;
- let r2_mat = r2.gcross_matrix();
-
- #[allow(unused_mut)] // For 2D.
- let mut lhs;
-
- #[cfg(feature = "dim3")]
- {
- let r2_mat_b1 = r2_mat * basis1;
-
- lhs = Matrix5::zeros();
- let lhs00 = ii2.quadform3x2(&r2_mat_b1).add_diagonal(im2);
- let lhs10 = ii2 * r2_mat_b1;
- let lhs11 = ii2.into_matrix();
- lhs.fixed_slice_mut::<2, 2>(0, 0)
- .copy_from(&lhs00.into_matrix());
- lhs.fixed_slice_mut::<3, 2>(2, 0).copy_from(&lhs10);
- lhs.fixed_slice_mut::<3, 3>(2, 2).copy_from(&lhs11);
- }
-
- #[cfg(feature = "dim2")]
- {
- let b2r2 = basis1.dot(&r2_mat);
- let m11 = im2 + b2r2 * ii2 * b2r2;
- let m12 = basis1.dot(&r2_mat) * ii2;
- let m22 = ii2;
- lhs = SdpMatrix2::new(m11, m12, m22);
- }
-
- let anchor_linvel1 = linvel1 + angvel1.gcross(r1);
- let anchor_linvel2 = linvel2 + angvel2.gcross(r2);
-
- // NOTE: we don't use Cholesky in 2D because we only have a 2x2 matrix
- // for which a textbook inverse is still efficient.
- #[cfg(feature = "dim2")]
- let inv_lhs = lhs.inverse_unchecked().into_matrix();
- #[cfg(feature = "dim3")]
- let inv_lhs = Cholesky::new_unchecked(lhs).inverse();
-
- let linvel_err = basis1.tr_mul(&(anchor_linvel2 - anchor_linvel1));
- let angvel_err = angvel2 - angvel1;
-
- let velocity_solve_fraction = SimdReal::splat(params.velocity_solve_fraction);
-
- #[cfg(feature = "dim2")]
- let mut rhs = Vector2::new(linvel_err.x, angvel_err) * velocity_solve_fraction;
- #[cfg(feature = "dim3")]
- let mut rhs = Vector5::new(
- linvel_err.x,
- linvel_err.y,
- angvel_err.x,
- angvel_err.y,
- angvel_err.z,
- ) * velocity_solve_fraction;
-
- let velocity_based_erp_inv_dt = params.velocity_based_erp_inv_dt();
- if velocity_based_erp_inv_dt != 0.0 {
- let velocity_based_erp_inv_dt = SimdReal::splat(velocity_based_erp_inv_dt);
-
- let linear_err = basis1.tr_mul(&(anchor2 - anchor1));
-
- let frame1 = position1
- * Isometry::from(gather![|ii| if flipped[ii] {
- cparams[ii].local_frame2()
- } else {
- cparams[ii].local_frame1()
- }]);
- let frame2 = position2
- * Isometry::from(gather![|ii| if flipped[ii] {
- cparams[ii].local_frame1()
- } else {
- cparams[ii].local_frame2()
- }]);
-
- let ang_err = frame2.rotation * frame1.rotation.inverse();
-
- #[cfg(feature = "dim2")]
- {
- rhs += Vector2::new(linear_err.x, ang_err.angle()) * velocity_based_erp_inv_dt;
- }
-
- #[cfg(feature = "dim3")]
- {
- let ang_err = Vector3::from(gather![|ii| ang_err.extract(ii).scaled_axis()]);
- rhs += Vector5::new(linear_err.x, linear_err.y, ang_err.x, ang_err.y, ang_err.z)
- * velocity_based_erp_inv_dt;
- }
- }
-
- // Setup limit constraint.
- let zero: SimdReal = na::zero();
- let limits_forcedir2 = axis2; // hopefully axis1 is colinear with axis2
- let mut limits_active = false;
- let mut limits_rhs = zero;
- let mut limits_impulse = zero;
- let mut limits_impulse_limits = (zero, zero);
-
- let limits_enabled = SimdBool::from(gather![|ii| cparams[ii].limits_enabled]);
- if limits_enabled.any() {
- let danchor = anchor2 - anchor1;
- let dist = danchor.dot(&axis1);
-
- // TODO: we should allow predictive constraint activation.
- let min_limit = SimdReal::from(gather![|ii| cparams[ii].limits[0]]);
- let max_limit = SimdReal::from(gather![|ii| cparams[ii].limits[1]]);
-
- let min_enabled = dist.simd_lt(min_limit);
- let max_enabled = dist.simd_gt(max_limit);
-
- limits_impulse_limits.0 = SimdReal::splat(-Real::INFINITY).select(max_enabled, zero);
- limits_impulse_limits.1 = SimdReal::splat(Real::INFINITY).select(min_enabled, zero);
-
- limits_active = (min_enabled | max_enabled).any();
- if limits_active {
- limits_rhs = (anchor_linvel2.dot(&axis2) - anchor_linvel1.dot(&axis1))
- * velocity_solve_fraction;
-
- limits_rhs += ((dist - max_limit).simd_max(zero)
- - (min_limit - dist).simd_max(zero))
- * SimdReal::splat(velocity_based_erp_inv_dt);
-
- limits_impulse = SimdReal::from(gather![|ii| cparams[ii].limits_impulse])
- .simd_max(limits_impulse_limits.0)
- .simd_min(limits_impulse_limits.1);
- }
- }
-
- WPrismaticVelocityGroundConstraint {
- joint_id,
- mj_lambda2,
- im2,
- ii2_sqrt,
- impulse: impulse * SimdReal::splat(params.warmstart_coeff),
- limits_active,
- limits_forcedir2,
- limits_rhs,
- limits_impulse: limits_impulse * SimdReal::splat(params.warmstart_coeff),
- limits_impulse_limits,
- basis1,
- inv_lhs,
- rhs,
- r2,
- axis2,
- }
- }
-
- pub fn warmstart(&self, mj_lambdas: &mut [DeltaVel<Real>]) {
- let mut mj_lambda2 = DeltaVel {
- linear: Vector::from(gather![|ii| mj_lambdas[self.mj_lambda2[ii] as usize].linear]),
- angular: AngVector::from(gather![
- |ii| mj_lambdas[self.mj_lambda2[ii] as usize].angular
- ]),
- };
-
- let lin_impulse = self.basis1 * self.impulse.fixed_rows::<LIN_IMPULSE_DIM>(0).into_owned();
- #[cfg(feature = "dim2")]
- let ang_impulse = self.impulse.y;
- #[cfg(feature = "dim3")]
- let ang_impulse = self.impulse.fixed_rows::<3>(2).into_owned();
-
- mj_lambda2.linear -= lin_impulse * self.im2;
- mj_lambda2.angular -= self
- .ii2_sqrt
- .transform_vector(ang_impulse + self.r2.gcross(lin_impulse));
-
- mj_lambda2.linear += self.limits_forcedir2 * (self.im2 * self.limits_impulse);
-
- for ii in 0..SIMD_WIDTH {
- mj_lambdas[self.mj_lambda2[ii] as usize].linear = mj_lambda2.linear.extract(ii);
- mj_lambdas[self.mj_lambda2[ii] as usize].angular = mj_lambda2.angular.extract(ii);
- }
- }
-
- fn solve_dofs(&mut self, mj_lambda2: &mut DeltaVel<SimdReal>) {
- let ang_vel2 = self.ii2_sqrt.transform_vector(mj_lambda2.angular);
- let lin_vel2 = mj_lambda2.linear + ang_vel2.gcross(self.r2);
- let lin_dvel = self.basis1.tr_mul(&lin_vel2);
- let ang_dvel = ang_vel2;
- #[cfg(feature = "dim2")]
- let rhs = Vector2::new(lin_dvel.x, ang_dvel) + self.rhs;
- #[cfg(feature = "dim3")]
- let rhs =
- Vector5::new(lin_dvel.x, lin_dvel.y, ang_dvel.x, ang_dvel.y, ang_dvel.z) + self.rhs;
- let impulse = self.inv_lhs * rhs;
- self.impulse += impulse;
- let lin_impulse = self.basis1 * impulse.fixed_rows::<LIN_IMPULSE_DIM>(0).into_owned();
- #[cfg(feature = "dim2")]
- let ang_impulse = impulse.y;
- #[cfg(feature = "dim3")]
- let ang_impulse = impulse.fixed_rows::<3>(2).into_owned();
-
- mj_lambda2.linear -= lin_impulse * self.im2;
- mj_lambda2.angular -= self
- .ii2_sqrt
- .transform_vector(ang_impulse + self.r2.gcross(lin_impulse));
- }
-
- fn solve_limits(&mut self, mj_lambda2: &mut DeltaVel<SimdReal>) {
- if self.limits_active {
- // FIXME: the transformation by ii2_sqrt could be avoided by
- // reusing some computations above.
- let ang_vel2 = self.ii2_sqrt.transform_vector(mj_lambda2.angular);
-
- let lin_dvel = self
- .limits_forcedir2
- .dot(&(mj_lambda2.linear + ang_vel2.gcross(self.r2)))
- + self.limits_rhs;
- let new_impulse = (self.limits_impulse - lin_dvel / self.im2)
- .simd_max(self.limits_impulse_limits.0)
- .simd_min(self.limits_impulse_limits.1);
- let dimpulse = new_impulse - self.limits_impulse;
- self.limits_impulse = new_impulse;
-
- mj_lambda2.linear += self.limits_forcedir2 * (self.im2 * dimpulse);
- }
- }
-
- pub fn solve(&mut self, mj_lambdas: &mut [DeltaVel<Real>]) {
- let mut mj_lambda2 = DeltaVel {
- linear: Vector::from(gather![|ii| mj_lambdas[self.mj_lambda2[ii] as usize].linear]),
- angular: AngVector::from(gather![
- |ii| mj_lambdas[self.mj_lambda2[ii] as usize].angular
- ]),
- };
-
- self.solve_dofs(&mut mj_lambda2);
- self.solve_limits(&mut mj_lambda2);
-
- for ii in 0..SIMD_WIDTH {
- mj_lambdas[self.mj_lambda2[ii] as usize].linear = mj_lambda2.linear.extract(ii);
- mj_lambdas[self.mj_lambda2[ii] as usize].angular = mj_lambda2.angular.extract(ii);
- }
- }
-
- pub fn writeback_impulses(&self, joints_all: &mut [JointGraphEdge]) {
- for ii in 0..SIMD_WIDTH {
- let joint = &mut joints_all[self.joint_id[ii]].weight;
- if let JointParams::PrismaticJoint(rev) = &mut joint.params {
- rev.impulse = self.impulse.extract(ii);
- rev.limits_impulse = self.limits_impulse.extract(ii);
- }
- }
- }
-}