pub struct TransformExtrapolationPlugin<LinVel: VelocitySource, AngVel: VelocitySource> {
pub extrapolate_translation_all: bool,
pub extrapolate_rotation_all: bool,
/* private fields */
}Expand description
A plugin for Transform extrapolation, making movement in FixedUpdate appear smooth.
Transform extrapolation predicts future positions based on velocity, and applies easing
between the current and predicted Transform in between fixed timesteps.
This results in movement that looks smooth and feels responsive, but can stutter
when the prediction is incorrect, such as when velocity changes abruptly.
This plugin requires the TransformEasingPlugin to function. It is automatically added
if not already present in the app.
Note that unlike TransformInterpolationPlugin, this plugin does not support scale easing.
However, the ScaleInterpolation component can still be used even when translation and rotation are extrapolated.
§Usage
Transform extrapolation requires velocity to predict future positions.
Instead of providing its own velocity components, the TransformExtrapolationPlugin
lets you specify your own velocity components that you manage yourself.
First, make sure you have components for velocity, and implement the VelocitySource trait on a QueryData type:
use bevy::{ecs::query::QueryData, prelude::*};
use bevy_transform_interpolation::VelocitySource;
#[derive(Component, Default)]
struct LinearVelocity(Vec3);
#[derive(Component, Default)]
struct AngularVelocity(Vec3);
#[derive(QueryData)]
struct LinVelSource;
impl VelocitySource for LinVelSource {
// Components storing the previous and current velocities.
// Note: For extrapolation, the `Previous` component is not used, so we can make it the same as `Current`.
type Previous = LinearVelocity;
type Current = LinearVelocity;
fn previous(start: &Self::Previous) -> Vec3 {
start.0
}
fn current(end: &Self::Current) -> Vec3 {
end.0
}
}
#[derive(QueryData)]
struct AngVelSource;
impl VelocitySource for AngVelSource {
type Previous = AngularVelocity;
type Current = AngularVelocity;
fn previous(start: &Self::Previous) -> Vec3 {
start.0
}
fn current(end: &Self::Current) -> Vec3 {
end.0
}
}Then, add the TransformExtrapolationPlugin to the app with the velocity sources:
use bevy::{ecs::query::QueryData, prelude::*};
use bevy_transform_interpolation::{prelude::*, VelocitySource};
fn main() {
let mut app = App::new();
app.add_plugins((
TransformInterpolationPlugin::default(),
TransformExtrapolationPlugin::<LinVelSource, AngVelSource>::default(),
));
// Optional: Insert velocity components automatically for entities with extrapolation.
app.register_required_components::<TranslationExtrapolation, LinearVelocity>();
app.register_required_components::<RotationExtrapolation, AngularVelocity>();
// ...
app.run();
}Transform extrapolation can now be enabled for a given entity by adding the TransformExtrapolation component:
fn setup(mut commands: Commands) {
// Extrapolate translation and rotation.
commands.spawn((
Transform::default(),
TransformExtrapolation,
));
}Now, any changes made to the translation or rotation of the entity in FixedPreUpdate, FixedUpdate,
or FixedPostUpdate will automatically be smoothed in between fixed timesteps.
Transform properties can also be extrapolated individually by adding the TranslationExtrapolation
and RotationExtrapolation components.
fn setup(mut commands: Commands) {
// Only extrapolate translation.
commands.spawn((Transform::default(), TranslationExtrapolation));
// Only extrapolate rotation.
commands.spawn((Transform::default(), RotationExtrapolation));
}If you want all entities with a Transform to be extrapolated by default, you can use
TransformExtrapolationPlugin::extrapolate_all(), or set the extrapolate_translation_all
and extrapolate_rotation_all fields.
fn main() {
App::new()
.add_plugins(TransformExtrapolationPlugin::<LinVelSource, AngVelSource> {
// Extrapolate translation by default, but not rotation.
extrapolate_translation_all: true,
extrapolate_rotation_all: false,
})
// ...
.run();
}When extrapolation is enabled for all entities by default, you can still opt out of it for individual entities
by adding the NoTransformEasing component, or the individual NoTranslationEasing and NoRotationEasing components.
Note that changing Transform manually in any schedule that doesn’t use a fixed timestep is also supported,
but it is equivalent to teleporting, and disables extrapolation for the entity for the remainder of that fixed timestep.
§Alternatives
For many applications, the stutter caused by mispredictions in extrapolation may be undesirable.
In these cases, the TransformInterpolationPlugin can be a better alternative.
Transform interpolation eases between the previous and current Transform,
resulting in movement that is always smooth and accurate. The downside is that the rendered
positions can lag slightly behind the true positions, making movement feel delayed.
§Easing Backends
By default, transform extrapolation uses linear interpolation (lerp) for easing translation,
and spherical linear interpolation (slerp) for easing rotation.
If the previous and current velocities are also available, it is possible to use Hermite interpolation
with the TransformHermiteEasingPlugin to get smoother and more accurate easing. To enable Hermite interpolation
for extrapolation, add the TransformHermiteEasing component to the entity in addition to the extrapolation components.
Fields§
§extrapolate_translation_all: boolIf true, translation will be extrapolated for all entities with the Transform component by default.
This can be overridden for individual entities by adding the NoTranslationEasing or NoTransformEasing component.
extrapolate_rotation_all: boolIf true, rotation will be extrapolated for all entities with the Transform component by default.
This can be overridden for individual entities by adding the NoRotationEasing or NoTransformEasing component.
Implementations§
Source§impl<LinVel: VelocitySource, AngVel: VelocitySource> TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel: VelocitySource, AngVel: VelocitySource> TransformExtrapolationPlugin<LinVel, AngVel>
Sourcepub fn extrapolate_all() -> Self
pub fn extrapolate_all() -> Self
Enables extrapolation for translation and rotation for all entities with the Transform component.
This can be overridden for individual entities by adding the NoTransformEasing component,
or the individual NoTranslationEasing and NoRotationEasing components.
Trait Implementations§
Source§impl<LinVel: Debug + VelocitySource, AngVel: Debug + VelocitySource> Debug for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel: Debug + VelocitySource, AngVel: Debug + VelocitySource> Debug for TransformExtrapolationPlugin<LinVel, AngVel>
Source§impl<LinVel: VelocitySource, AngVel: VelocitySource> Default for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel: VelocitySource, AngVel: VelocitySource> Default for TransformExtrapolationPlugin<LinVel, AngVel>
Source§impl<LinVel: VelocitySource, AngVel: VelocitySource> Plugin for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel: VelocitySource, AngVel: VelocitySource> Plugin for TransformExtrapolationPlugin<LinVel, AngVel>
Source§fn finish(&self, app: &mut App)
fn finish(&self, app: &mut App)
App, once all plugins registered are ready. This can
be useful for plugins that depends on another plugin asynchronous setup, like the renderer.Source§fn ready(&self, _app: &App) -> bool
fn ready(&self, _app: &App) -> bool
finish should be called.Source§fn cleanup(&self, _app: &mut App)
fn cleanup(&self, _app: &mut App)
Auto Trait Implementations§
impl<LinVel, AngVel> Freeze for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel, AngVel> RefUnwindSafe for TransformExtrapolationPlugin<LinVel, AngVel>where
LinVel: RefUnwindSafe,
AngVel: RefUnwindSafe,
impl<LinVel, AngVel> Send for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel, AngVel> Sync for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel, AngVel> Unpin for TransformExtrapolationPlugin<LinVel, AngVel>
impl<LinVel, AngVel> UnwindSafe for TransformExtrapolationPlugin<LinVel, AngVel>where
LinVel: UnwindSafe,
AngVel: UnwindSafe,
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
Source§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Creates Self using default().
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more