Skip to content
Closed
1 change: 0 additions & 1 deletion src/pipeline/query_filter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use bevy::prelude::Entity;

pub use rapier::geometry::InteractionGroups;
pub use rapier::pipeline::QueryFilterFlags;

use crate::geometry::CollisionGroups;
Expand Down
57 changes: 3 additions & 54 deletions src/plugin/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,6 @@ use bevy::prelude::Resource;

use crate::math::Vect;

/// Difference between simulation and rendering time
#[derive(Resource, Default)]
pub struct SimulationToRenderTime {
/// Difference between simulation and rendering time
pub diff: f32,
}

/// The different ways of adjusting the timestep length.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TimestepMode {
/// Use a fixed timestep: the physics simulation will be advanced by the fixed value
/// `dt` seconds at each Bevy tick by performing `substeps` of length `dt / substeps`.
Fixed {
/// The physics simulation will be advanced by this total amount at each Bevy tick.
dt: f32,
/// This number of substeps of length `dt / substeps` will be performed at each Bevy tick.
substeps: usize,
},
/// Use a variable timestep: the physics simulation will be advanced by the variable value
/// `min(max_dt, Time::delta_seconds() * time_scale)` seconds at each Bevy tick. If
/// `time_scale > 1.0` then the simulation will appear to run faster than real-time whereas
/// `time_scale < 1.0` makes the simulation run in slow-motion.
Variable {
/// Maximum amount of time the physics simulation may be advanced at each Bevy tick.
max_dt: f32,
/// Multiplier controlling if the physics simulation should advance faster (> 1.0),
/// at the same speed (= 1.0) or slower (< 1.0) than the real time.
time_scale: f32,
/// The number of substeps that will be performed at each tick.
substeps: usize,
},
/// Use a fixed timestep equal to `IntegrationParameters::dt`, but don't step if the
/// physics simulation advanced by a time greater than the real-world elapsed time multiplied by `time_scale`.
/// Rigid-bodies with a component `InterpolatedTransform` attached will use interpolation to
/// estimate the rigid-bodies position in-between steps.
Interpolated {
/// The physics simulation will be advanced by this total amount at each Bevy tick, unless
/// the physics simulation time is ahead of a the real time.
dt: f32,
/// Multiplier controlling if the physics simulation should advance faster (> 1.0),
/// at the same speed (= 1.0) or slower (< 1.0) than the real time.
time_scale: f32,
/// The number of substeps that will be performed whenever the physics simulation is advanced.
substeps: usize,
},
}

#[derive(Resource, Copy, Clone, Debug)]
/// A resource for specifying configuration information for the physics simulation
pub struct RapierConfiguration {
Expand All @@ -58,8 +11,6 @@ pub struct RapierConfiguration {
pub physics_pipeline_active: bool,
/// Specifies if the query pipeline is active and update the query pipeline.
pub query_pipeline_active: bool,
/// Specifies the way the timestep length should be adjusted at each frame.
pub timestep_mode: TimestepMode,
/// Specifies the number of subdivisions along each axes a shape should be subdivided
/// if its scaled representation cannot be represented with the same shape type.
///
Expand All @@ -70,6 +21,8 @@ pub struct RapierConfiguration {
pub scaled_shape_subdivision: u32,
/// Specifies if backend sync should always accept tranform changes, which may be from the writeback stage.
pub force_update_from_transform_changes: bool,
/// The number of substeps that will be performed at each tick.
pub substeps: usize,
}

impl Default for RapierConfiguration {
Expand All @@ -81,13 +34,9 @@ impl Default for RapierConfiguration {
gravity: Vect::Y * -9.81,
physics_pipeline_active: true,
query_pipeline_active: true,
timestep_mode: TimestepMode::Variable {
max_dt: 1.0 / 60.0,
time_scale: 1.0,
substeps: 1,
},
scaled_shape_subdivision: 10,
force_update_from_transform_changes: false,
substeps: 1,
}
}
}
138 changes: 30 additions & 108 deletions src/plugin/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use bevy::prelude::{Entity, EventWriter, GlobalTransform, Query};

use crate::control::{CharacterCollision, MoveShapeOptions, MoveShapeOutput};
use crate::dynamics::TransformInterpolation;
use crate::plugin::configuration::{SimulationToRenderTime, TimestepMode};
use crate::prelude::{CollisionGroups, RapierRigidBodyHandle};
use rapier::control::CharacterAutostep;

Expand Down Expand Up @@ -208,14 +207,11 @@ impl RapierContext {
pub fn step_simulation(
&mut self,
gravity: Vect,
timestep_mode: TimestepMode,
events: Option<(EventWriter<CollisionEvent>, EventWriter<ContactForceEvent>)>,
hooks: &dyn PhysicsHooks,
time: &Time,
sim_to_render_time: &mut SimulationToRenderTime,
mut interpolation_query: Option<
Query<(&RapierRigidBodyHandle, &mut TransformInterpolation)>,
>,
delta_time: f32,
substeps: usize,
mut interpolation_query: Query<(&RapierRigidBodyHandle, &mut TransformInterpolation)>,
) {
let event_queue = events.map(|(ce, fe)| EventQueue {
deleted_colliders: &self.deleted_colliders,
Expand All @@ -229,108 +225,34 @@ impl RapierContext {
.or_else(|| event_queue.as_ref().map(|q| q as &dyn EventHandler))
.unwrap_or(&() as &dyn EventHandler);

match timestep_mode {
TimestepMode::Interpolated {
dt,
time_scale,
substeps,
} => {
self.integration_parameters.dt = dt;

sim_to_render_time.diff += time.delta_seconds();

while sim_to_render_time.diff > 0.0 {
// NOTE: in this comparison we do the same computations we
// will do for the next `while` iteration test, to make sure we
// don't get bit by potential float inaccuracy.
if sim_to_render_time.diff - dt <= 0.0 {
if let Some(interpolation_query) = interpolation_query.as_mut() {
// This is the last simulation step to be executed in the loop
// Update the previous state transforms
for (handle, mut interpolation) in interpolation_query.iter_mut() {
if let Some(body) = self.bodies.get(handle.0) {
interpolation.start = Some(*body.position());
interpolation.end = None;
}
}
}
}

let mut substep_integration_parameters = self.integration_parameters;
substep_integration_parameters.dt = dt / (substeps as Real) * time_scale;

for _ in 0..substeps {
self.pipeline.step(
&(gravity / self.physics_scale).into(),
&substep_integration_parameters,
&mut self.islands,
&mut self.broad_phase,
&mut self.narrow_phase,
&mut self.bodies,
&mut self.colliders,
&mut self.impulse_joints,
&mut self.multibody_joints,
&mut self.ccd_solver,
None,
hooks,
events,
);
}
self.integration_parameters.dt = delta_time;

let mut substep_integration_parameters = self.integration_parameters;
substep_integration_parameters.dt = delta_time / substeps as Real;

for _ in 0..substeps {
self.pipeline.step(
&(gravity / self.physics_scale).into(),
&substep_integration_parameters,
&mut self.islands,
&mut self.broad_phase,
&mut self.narrow_phase,
&mut self.bodies,
&mut self.colliders,
&mut self.impulse_joints,
&mut self.multibody_joints,
&mut self.ccd_solver,
None,
hooks,
events,
);
}

sim_to_render_time.diff -= dt;
}
}
TimestepMode::Variable {
max_dt,
time_scale,
substeps,
} => {
self.integration_parameters.dt = (time.delta_seconds() * time_scale).min(max_dt);

let mut substep_integration_parameters = self.integration_parameters;
substep_integration_parameters.dt /= substeps as Real;

for _ in 0..substeps {
self.pipeline.step(
&(gravity / self.physics_scale).into(),
&substep_integration_parameters,
&mut self.islands,
&mut self.broad_phase,
&mut self.narrow_phase,
&mut self.bodies,
&mut self.colliders,
&mut self.impulse_joints,
&mut self.multibody_joints,
&mut self.ccd_solver,
None,
hooks,
events,
);
}
}
TimestepMode::Fixed { dt, substeps } => {
self.integration_parameters.dt = dt;

let mut substep_integration_parameters = self.integration_parameters;
substep_integration_parameters.dt = dt / (substeps as Real);

for _ in 0..substeps {
self.pipeline.step(
&(gravity / self.physics_scale).into(),
&substep_integration_parameters,
&mut self.islands,
&mut self.broad_phase,
&mut self.narrow_phase,
&mut self.bodies,
&mut self.colliders,
&mut self.impulse_joints,
&mut self.multibody_joints,
&mut self.ccd_solver,
None,
hooks,
events,
);
}
// NOTE: Update the interpolation data must be after all substeps.
for (handle, mut interpolation) in interpolation_query.iter_mut() {
if let Some(body) = self.bodies.get(handle.0) {
interpolation.start = interpolation.end;
interpolation.end = Some(*body.position());
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugin/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub use self::configuration::{RapierConfiguration, SimulationToRenderTime, TimestepMode};
pub use self::configuration::RapierConfiguration;
pub use self::context::RapierContext;
pub use self::plugin::{NoUserData, PhysicsSet, RapierPhysicsPlugin, RapierTransformPropagateSet};

Expand Down
Loading