Skip to main content

bevy_rapier3d/plugin/
configuration.rs

1//! Components used to configure a simulation run by rapier, these are not modified by bevy_rapier.
2
3use bevy::{
4    prelude::{Component, Resource},
5    reflect::Reflect,
6};
7
8use crate::math::{Real, Vect};
9
10#[cfg(doc)]
11use crate::prelude::TransformInterpolation;
12
13/// The friction model selected by [`IntegrationParameters::friction_model`].
14#[cfg(feature = "dim3")]
15pub use rapier::dynamics::FrictionModel;
16/// The low-level parameters of a context's simulation (see
17/// [`RapierContextSimulation::integration_parameters`](crate::plugin::context::RapierContextSimulation::integration_parameters)
18/// and [`RapierContextInitialization`](crate::plugin::RapierContextInitialization)).
19pub use rapier::dynamics::IntegrationParameters;
20
21/// The different ways of adjusting the timestep length each frame.
22#[derive(Copy, Clone, Debug, PartialEq, Resource)]
23#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
24pub enum TimestepMode {
25    /// Use a fixed timestep: the physics simulation will be advanced by the fixed value
26    /// `dt` seconds at each Bevy tick by performing `substeps` of length `dt / substeps`.
27    Fixed {
28        /// The physics simulation will be advanced by this total amount at each Bevy tick.
29        dt: f32,
30        /// This number of substeps of length `dt / substeps` will be performed at each Bevy tick.
31        substeps: usize,
32    },
33    /// Use a variable timestep: the physics simulation will be advanced by the variable value
34    /// `min(max_dt, Time::delta_seconds() * time_scale)` seconds at each Bevy tick. If
35    /// `time_scale > 1.0` then the simulation will appear to run faster than real-time whereas
36    /// `time_scale < 1.0` makes the simulation run in slow-motion. No step is performed on ticks
37    /// where this is zero (e.g. the first tick, or `time_scale == 0.0`).
38    Variable {
39        /// Maximum amount of time the physics simulation may be advanced at each Bevy tick.
40        max_dt: f32,
41        /// Multiplier controlling if the physics simulation should advance faster (> 1.0),
42        /// at the same speed (= 1.0) or slower (< 1.0) than the real time.
43        time_scale: f32,
44        /// The number of substeps that will be performed at each tick.
45        substeps: usize,
46    },
47    /// Use a fixed timestep equal to `IntegrationParameters::dt`, but don't step if the
48    /// physics simulation advanced by a time greater than the real-world elapsed time multiplied by `time_scale`.
49    /// Rigid-bodies with a component [`TransformInterpolation`] attached will use interpolation to
50    /// estimate the rigid-bodies position in-between steps.
51    Interpolated {
52        /// The physics simulation will be advanced by this total amount at each Bevy tick, unless
53        /// the physics simulation time is ahead of a the real time.
54        dt: f32,
55        /// Multiplier controlling if the physics simulation should advance faster (> 1.0),
56        /// at the same speed (= 1.0) or slower (< 1.0) than the real time.
57        time_scale: f32,
58        /// The number of substeps that will be performed whenever the physics simulation is advanced.
59        substeps: usize,
60    },
61}
62
63impl Default for TimestepMode {
64    fn default() -> Self {
65        TimestepMode::Variable {
66            max_dt: 1.0 / 60.0,
67            time_scale: 1.0,
68            substeps: 1,
69        }
70    }
71}
72
73/// Selects what a simulation step of a Rapier context does.
74#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Reflect)]
75#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
76pub enum SimulationMode {
77    /// Run the full physics pipeline: collision detection, constraints resolution and
78    /// integration of the rigid-bodies' motion.
79    #[default]
80    Full,
81    /// Only run collision detection with Rapier's `CollisionPipeline`.
82    ///
83    /// Collision events, contact pairs, intersections, physics hooks and scene queries keep
84    /// working, but the dynamics are not simulated: no forces, joints or contact responses are
85    /// applied and rigid-bodies only move when their `Transform` is modified (kinematic
86    /// position-based bodies are teleported to their next kinematic position). Contact force
87    /// events are never emitted in this mode.
88    CollisionOnly,
89}
90
91/// Strategy used to keep the broad-phase BVH efficient as colliders move.
92///
93/// Mirrors Rapier’s [`BvhOptimizationStrategy`](rapier::geometry::BvhOptimizationStrategy).
94#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Reflect)]
95#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
96pub enum BroadPhaseOptimizationStrategy {
97    /// Different sub-trees of the BVH are optimized at each step.
98    #[default]
99    SubtreeOptimizer,
100    /// Disables incremental BVH optimization (discouraged, meant for debugging).
101    None,
102}
103
104impl From<BroadPhaseOptimizationStrategy> for rapier::geometry::BvhOptimizationStrategy {
105    fn from(value: BroadPhaseOptimizationStrategy) -> Self {
106        match value {
107            BroadPhaseOptimizationStrategy::SubtreeOptimizer => Self::SubtreeOptimizer,
108            BroadPhaseOptimizationStrategy::None => Self::None,
109        }
110    }
111}
112
113impl From<rapier::geometry::BvhOptimizationStrategy> for BroadPhaseOptimizationStrategy {
114    fn from(value: rapier::geometry::BvhOptimizationStrategy) -> Self {
115        match value {
116            rapier::geometry::BvhOptimizationStrategy::SubtreeOptimizer => Self::SubtreeOptimizer,
117            rapier::geometry::BvhOptimizationStrategy::None => Self::None,
118        }
119    }
120}
121
122#[derive(Component, Copy, Clone, Debug, Reflect)]
123#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
124/// A component for specifying configuration information for the physics simulation
125pub struct RapierConfiguration {
126    /// Specifying the gravity of the physics simulation.
127    pub gravity: Vect,
128    /// Specifies if the physics simulation is active and update the physics world.
129    pub physics_pipeline_active: bool,
130    /// Specifies the number of subdivisions along each axes a shape should be subdivided
131    /// if its scaled representation cannot be represented with the same shape type.
132    ///
133    /// For example, a ball subject to a non-uniform scaling cannot be represented as a ball
134    /// (it’s an ellipsoid). Thus, in order to be compatible with Rapier, the shape is automatically
135    /// discretized into a convex polyhedron, using `scaled_shape_subdivision` as the number of subdivisions
136    /// along each spherical coordinates angle.
137    pub scaled_shape_subdivision: u32,
138    /// Specifies if backend sync should always accept transform changes, which may be from the writeback stage.
139    pub force_update_from_transform_changes: bool,
140    /// Whether this context simulates the full dynamics, or only detects collisions.
141    pub simulation_mode: SimulationMode,
142    /// The number of worker threads of a thread pool dedicated to this context’s simulation.
143    ///
144    /// If `None` (the default), the simulation runs on the thread pool of the calling thread,
145    /// usually Rayon’s global pool. Changes are applied before the next simulation step. This
146    /// is ignored unless the `parallel` feature is enabled (and `unsync-callbacks` is not).
147    pub num_threads: Option<usize>,
148}
149
150impl RapierConfiguration {
151    /// Configures rapier with the specified length unit.
152    ///
153    /// See the documentation of [`IntegrationParameters::length_unit`] for additional details
154    /// on that argument.
155    ///
156    /// The default gravity is automatically scaled by that length unit.
157    pub fn new(length_unit: Real) -> Self {
158        Self {
159            gravity: Vect::Y * -9.81 * length_unit,
160            physics_pipeline_active: true,
161            scaled_shape_subdivision: 10,
162            force_update_from_transform_changes: false,
163            simulation_mode: SimulationMode::Full,
164            num_threads: None,
165        }
166    }
167}