Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip re-writing the same values to components, to satisfy bevy's change detection. #173

Merged
merged 8 commits into from
Oct 12, 2023
63 changes: 51 additions & 12 deletions src/plugins/integrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,15 @@ fn integrate_pos(
let gravitation_force =
effective_mass * gravity.0 * gravity_scale.map_or(1.0, |scale| scale.0);
let external_forces = gravitation_force + external_force.force();
lin_vel.0 += sub_dt.0 * external_forces * effective_inv_mass;
let delta_linvel = sub_dt.0 * external_forces * effective_inv_mass;
// avoid triggering bevy's change detection unnecessarily
if delta_linvel != Vector::ZERO {
lin_vel.0 += delta_linvel;
}
}
if lin_vel.0 != Vector::ZERO {
translation.0 += locked_axes.apply_to_vec(sub_dt.0 * lin_vel.0);
}

translation.0 += locked_axes.apply_to_vec(sub_dt.0 * lin_vel.0);
}
}

Expand Down Expand Up @@ -144,18 +149,28 @@ fn integrate_rot(
if rb.is_dynamic() {
// Apply damping
if let Some(damping) = ang_damping {
ang_vel.0 *= 1.0 / (1.0 + sub_dt.0 * damping.0);
// avoid triggering bevy's change detection unnecessarily
if ang_vel.0 != 0.0 && damping.0 != 0.0 {
ang_vel.0 *= 1.0 / (1.0 + sub_dt.0 * damping.0);
}
}

let effective_inv_inertia = locked_axes.apply_to_rotation(inv_inertia.0);

// Apply external torque
ang_vel.0 += sub_dt.0
let delta_ang_vel = sub_dt.0
* effective_inv_inertia
* (external_torque.torque() + external_force.torque());
// avoid triggering bevy's change detection unnecessarily
if delta_ang_vel != 0.0 {
ang_vel.0 += delta_ang_vel;
}
}
// avoid triggering bevy's change detection unnecessarily
let delta = locked_axes.apply_to_angular_velocity(sub_dt.0 * ang_vel.0);
if delta != 0.0 {
*rot += Rotation::from_radians(delta);
}

*rot += Rotation::from_radians(locked_axes.apply_to_angular_velocity(sub_dt.0 * ang_vel.0));
}
}

Expand Down Expand Up @@ -191,7 +206,10 @@ fn integrate_rot(
if rb.is_dynamic() {
// Apply damping
if let Some(damping) = ang_damping {
ang_vel.0 *= 1.0 / (1.0 + sub_dt.0 * damping.0);
// avoid triggering bevy's change detection unnecessarily
if ang_vel.0 != Vector::ZERO && damping.0 != 0.0 {
ang_vel.0 *= 1.0 / (1.0 + sub_dt.0 * damping.0);
}
}

let effective_inertia = locked_axes.apply_to_rotation(inertia.rotated(&rot).0);
Expand All @@ -202,14 +220,21 @@ fn integrate_rot(
* effective_inv_inertia
* ((external_torque.torque() + external_force.torque())
- ang_vel.0.cross(effective_inertia * ang_vel.0));
ang_vel.0 += delta_ang_vel;
// avoid triggering bevy's change detection unnecessarily
if delta_ang_vel != Vector::ZERO {
ang_vel.0 += delta_ang_vel;
}
}

let q = Quaternion::from_vec4(ang_vel.0.extend(0.0)) * rot.0;
let effective_dq = locked_axes
.apply_to_angular_velocity(sub_dt.0 * 0.5 * q.xyz())
.extend(sub_dt.0 * 0.5 * q.w);
rot.0 = (rot.0 + Quaternion::from_vec4(effective_dq)).normalize();
// avoid triggering bevy's change detection unnecessarily
let delta = Quaternion::from_vec4(effective_dq);
if delta != Quaternion::IDENTITY {
rot.0 = (rot.0 + delta).normalize();
}
}
}

Expand Down Expand Up @@ -247,8 +272,22 @@ fn apply_impulses(mut bodies: Query<ImpulseQueryComponents, Without<Sleeping>>)
let effective_inv_mass = locked_axes.apply_to_vec(Vector::splat(inv_mass.0));
let effective_inv_inertia = locked_axes.apply_to_rotation(inv_inertia.rotated(rotation).0);

lin_vel.0 += impulse.impulse() * effective_inv_mass;
ang_vel.0 += effective_inv_inertia * (ang_impulse.impulse() + impulse.angular_impulse());
// avoid triggering bevy's change detection unnecessarily
let delta_lin_vel = impulse.impulse() * effective_inv_mass;
let delta_ang_vel =
effective_inv_inertia * (ang_impulse.impulse() + impulse.angular_impulse());

if delta_lin_vel != Vector::ZERO {
lin_vel.0 += delta_lin_vel;
}
#[cfg(feature = "3d")]
if delta_ang_vel != Vector::ZERO {
ang_vel.0 += delta_ang_vel;
}
#[cfg(feature = "2d")]
if delta_ang_vel != 0.0 {
ang_vel.0 += delta_ang_vel;
}
}
}

Expand Down
20 changes: 11 additions & 9 deletions src/plugins/sleeping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ impl Plugin for SleepingPlugin {
app.get_schedule_mut(PhysicsSchedule)
.expect("add PhysicsSchedule first")
.add_systems(
(mark_sleeping_bodies, wake_up_bodies, gravity_wake_up_bodies)
(
mark_sleeping_bodies,
wake_up_bodies,
wake_all_sleeping_bodies.run_if(resource_changed::<Gravity>()),
)
.chain()
.in_set(PhysicsStepSet::Sleeping),
);
Expand Down Expand Up @@ -105,16 +109,14 @@ fn wake_up_bodies(
}
}

/// Removes the [`Sleeping`] component from sleeping bodies when [`Gravity`] is changed.
fn gravity_wake_up_bodies(
/// Removes the [`Sleeping`] component from all sleeping bodies.
/// Triggered automatically when [`Gravity`] is changed.
fn wake_all_sleeping_bodies(
mut commands: Commands,
mut bodies: Query<(Entity, &mut TimeSleeping), With<Sleeping>>,
gravity: Res<Gravity>,
) {
if gravity.is_changed() {
for (entity, mut time_sleeping) in &mut bodies {
commands.entity(entity).remove::<Sleeping>();
time_sleeping.0 = 0.0;
}
for (entity, mut time_sleeping) in &mut bodies {
commands.entity(entity).remove::<Sleeping>();
time_sleeping.0 = 0.0;
}
}
51 changes: 42 additions & 9 deletions src/plugins/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,11 @@ fn update_lin_vel(

if rb.is_dynamic() {
// v = (x - x_prev) / h
lin_vel.0 = (pos.0 - prev_pos.0 + translation.0) / sub_dt.0;
let new_lin_vel = (pos.0 - prev_pos.0 + translation.0) / sub_dt.0;
// avoid triggering bevy's change detection unnecessarily
if new_lin_vel != lin_vel.0 {
lin_vel.0 = new_lin_vel;
}
}
}
}
Expand Down Expand Up @@ -249,7 +253,11 @@ fn update_ang_vel(
pre_solve_ang_vel.0 = ang_vel.0;

if rb.is_dynamic() {
ang_vel.0 = (rot.mul(prev_rot.inverse())).as_radians() / sub_dt.0;
let new_ang_vel = (rot.mul(prev_rot.inverse())).as_radians() / sub_dt.0;
// avoid triggering bevy's change detection unnecessarily
if new_ang_vel != ang_vel.0 {
ang_vel.0 = new_ang_vel;
}
}
}
}
Expand Down Expand Up @@ -279,10 +287,13 @@ fn update_ang_vel(

if rb.is_dynamic() {
let delta_rot = rot.mul_quat(prev_rot.inverse().0);
ang_vel.0 = 2.0 * delta_rot.xyz() / sub_dt.0;

let mut new_ang_vel = 2.0 * delta_rot.xyz() / sub_dt.0;
if delta_rot.w < 0.0 {
ang_vel.0 = -ang_vel.0;
new_ang_vel = -new_ang_vel;
}
// avoid triggering bevy's change detection unnecessarily
if new_ang_vel != ang_vel.0 {
ang_vel.0 = new_ang_vel;
}
}
}
Expand Down Expand Up @@ -373,12 +384,34 @@ fn solve_vel(
}

if body1.rb.is_dynamic() {
body1.linear_velocity.0 += p * inv_mass1;
body1.angular_velocity.0 += compute_delta_ang_vel(inv_inertia1, r1, p);
let lin_vel_1 = p * inv_mass1;
let ang_vel_1 = compute_delta_ang_vel(inv_inertia1, r1, p);
if lin_vel_1 != Vector::ZERO {
body1.linear_velocity.0 += lin_vel_1;
}
#[cfg(feature = "2d")]
if ang_vel_1 != 0.0 {
body1.angular_velocity.0 += ang_vel_1;
}
#[cfg(feature = "3d")]
if ang_vel_1 != Vector::ZERO {
body1.angular_velocity.0 += ang_vel_1;
}
}
if body2.rb.is_dynamic() {
body2.linear_velocity.0 -= p * inv_mass2;
body2.angular_velocity.0 -= compute_delta_ang_vel(inv_inertia2, r2, p);
let lin_vel_2 = p * inv_mass2;
let ang_vel_2 = compute_delta_ang_vel(inv_inertia2, r2, p);
if lin_vel_2 != Vector::ZERO {
body2.linear_velocity.0 += lin_vel_2;
}
#[cfg(feature = "2d")]
if ang_vel_2 != 0.0 {
body2.angular_velocity.0 += ang_vel_2;
}
#[cfg(feature = "3d")]
if ang_vel_2 != Vector::ZERO {
body2.angular_velocity.0 += ang_vel_2;
}
}
}
}
Expand Down