use crate::{
dynamics::solver::{
solver_body::{SolverBody, SolverBodyInertia},
xpbd::*,
},
prelude::*,
};
use bevy::prelude::*;
#[derive(Clone, Copy, Debug, Default, PartialEq, Reflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, PartialEq)]
pub struct PointConstraintShared {
pub world_r1: Vector,
pub world_r2: Vector,
pub center_difference: Vector,
pub total_lagrange: Vector,
}
impl XpbdConstraintSolverData for PointConstraintShared {
fn clear_lagrange_multipliers(&mut self) {
self.total_lagrange = Vector::ZERO;
}
fn total_position_lagrange(&self) -> Vector {
self.total_lagrange
}
}
impl PointConstraintShared {
pub fn prepare(
&mut self,
bodies: [&RigidBodyQueryReadOnlyItem; 2],
local_anchor1: Vector,
local_anchor2: Vector,
) {
let [body1, body2] = bodies;
self.world_r1 = body1.rotation * (local_anchor1 - body1.center_of_mass.0);
self.world_r2 = body2.rotation * (local_anchor2 - body2.center_of_mass.0);
self.center_difference = (body2.position.0 - body1.position.0)
+ (body2.rotation * body2.center_of_mass.0 - body1.rotation * body1.center_of_mass.0);
}
pub fn solve(
&mut self,
bodies: [&mut SolverBody; 2],
inertias: [&SolverBodyInertia; 2],
compliance: Scalar,
dt: Scalar,
) {
let [body1, body2] = bodies;
let [inertia1, inertia2] = inertias;
let inv_mass1 = inertia1.effective_inv_mass();
let inv_mass2 = inertia2.effective_inv_mass();
let inv_angular_inertia1 = inertia1.effective_inv_angular_inertia();
let inv_angular_inertia2 = inertia2.effective_inv_angular_inertia();
let world_r1 = body1.delta_rotation * self.world_r1;
let world_r2 = body2.delta_rotation * self.world_r2;
let separation = (body2.delta_position - body1.delta_position)
+ (world_r2 - world_r1)
+ self.center_difference;
let magnitude_squared = separation.length_squared();
if magnitude_squared == 0.0 {
return;
}
let magnitude = magnitude_squared.sqrt();
let dir = -separation / magnitude;
let w1 = self.compute_generalized_inverse_mass(
inv_mass1.max_element(), inv_angular_inertia1,
world_r1,
dir,
);
let w2 = self.compute_generalized_inverse_mass(
inv_mass2.max_element(), inv_angular_inertia2,
world_r2,
dir,
);
let delta_lagrange = compute_lagrange_update(0.0, magnitude, &[w1, w2], compliance, dt);
let impulse = delta_lagrange * dir;
self.total_lagrange += impulse;
self.apply_positional_impulse(
body1, body2, inertia1, inertia2, impulse, world_r1, world_r2,
);
}
}
impl PositionConstraint for PointConstraintShared {}