Skip to content

Commit

Permalink
Refactor out Interpolate from Animatable, make example
Browse files Browse the repository at this point in the history
  • Loading branch information
mweatherley committed May 31, 2024
1 parent 8937db9 commit fd30d04
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 62 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2993,6 +2993,17 @@ description = "Demonstrates how to sample random points from mathematical primit
category = "Math"
wasm = true

[[example]]
name = "smooth_follow"
path = "examples/math/smooth_follow.rs"
doc-scrape-examples = true

[package.metadata.example.smooth_follow]
name = "Smooth Follow"
description = "Demonstrates how to make an entity smoothly follow another using interpolation"
category = "Math"
wasm = true

# Gizmos
[[example]]
name = "2d_gizmos"
Expand Down
46 changes: 1 addition & 45 deletions crates/bevy_animation/src/animatable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::util;
use bevy_color::{Laba, LinearRgba, Oklaba, Srgba, Xyza};
use bevy_ecs::world::World;
use bevy_math::*;
Expand All @@ -16,12 +15,7 @@ pub struct BlendInput<T> {
}

/// An animatable value type.
pub trait Animatable: Reflect + Sized + Send + Sync + 'static {
/// Interpolates between `a` and `b` with a interpolation factor of `time`.
///
/// The `time` parameter here may not be clamped to the range `[0.0, 1.0]`.
fn interpolate(a: &Self, b: &Self, time: f32) -> Self;

pub trait Animatable: Reflect + Interpolate + Sized + Send + Sync + 'static {
/// Blends one or more values together.
///
/// Implementors should return a default value when no inputs are provided here.
Expand All @@ -35,12 +29,6 @@ pub trait Animatable: Reflect + Sized + Send + Sync + 'static {
macro_rules! impl_float_animatable {
($ty: ty, $base: ty) => {
impl Animatable for $ty {
#[inline]
fn interpolate(a: &Self, b: &Self, t: f32) -> Self {
let t = <$base>::from(t);
(*a) * (1.0 - t) + (*b) * t
}

#[inline]
fn blend(inputs: impl Iterator<Item = BlendInput<Self>>) -> Self {
let mut value = Default::default();
Expand All @@ -60,12 +48,6 @@ macro_rules! impl_float_animatable {
macro_rules! impl_color_animatable {
($ty: ident) => {
impl Animatable for $ty {
#[inline]
fn interpolate(a: &Self, b: &Self, t: f32) -> Self {
let value = *a * (1. - t) + *b * t;
value
}

#[inline]
fn blend(inputs: impl Iterator<Item = BlendInput<Self>>) -> Self {
let mut value = Default::default();
Expand Down Expand Up @@ -100,11 +82,6 @@ impl_color_animatable!(Xyza);

// Vec3 is special cased to use Vec3A internally for blending
impl Animatable for Vec3 {
#[inline]
fn interpolate(a: &Self, b: &Self, t: f32) -> Self {
(*a) * (1.0 - t) + (*b) * t
}

#[inline]
fn blend(inputs: impl Iterator<Item = BlendInput<Self>>) -> Self {
let mut value = Vec3A::ZERO;
Expand All @@ -120,11 +97,6 @@ impl Animatable for Vec3 {
}

impl Animatable for bool {
#[inline]
fn interpolate(a: &Self, b: &Self, t: f32) -> Self {
util::step_unclamped(*a, *b, t)
}

#[inline]
fn blend(inputs: impl Iterator<Item = BlendInput<Self>>) -> Self {
inputs
Expand All @@ -135,14 +107,6 @@ impl Animatable for bool {
}

impl Animatable for Transform {
fn interpolate(a: &Self, b: &Self, t: f32) -> Self {
Self {
translation: Vec3::interpolate(&a.translation, &b.translation, t),
rotation: Quat::interpolate(&a.rotation, &b.rotation, t),
scale: Vec3::interpolate(&a.scale, &b.scale, t),
}
}

fn blend(inputs: impl Iterator<Item = BlendInput<Self>>) -> Self {
let mut translation = Vec3A::ZERO;
let mut scale = Vec3A::ZERO;
Expand Down Expand Up @@ -173,14 +137,6 @@ impl Animatable for Transform {
}

impl Animatable for Quat {
/// Performs a slerp to smoothly interpolate between quaternions.
#[inline]
fn interpolate(a: &Self, b: &Self, t: f32) -> Self {
// We want to smoothly interpolate between the two quaternions by default,
// rather than using a quicker but less correct linear interpolation.
a.slerp(*b, t)
}

#[inline]
fn blend(inputs: impl Iterator<Item = BlendInput<Self>>) -> Self {
let mut value = Self::IDENTITY;
Expand Down
1 change: 0 additions & 1 deletion crates/bevy_animation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
mod animatable;
mod graph;
mod transition;
mod util;

use std::cell::RefCell;
use std::collections::BTreeMap;
Expand Down
10 changes: 0 additions & 10 deletions crates/bevy_animation/src/util.rs

This file was deleted.

48 changes: 46 additions & 2 deletions crates/bevy_math/src/common_traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Dir2, Dir3, Dir3A, Quat, Vec2, Vec3, Vec3A, Vec4};
use crate::{DVec2, DVec3, DVec4, Dir2, Dir3, Dir3A, Quat, Vec2, Vec3, Vec3A, Vec4};
use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Neg, Sub};

Expand Down Expand Up @@ -216,35 +216,79 @@ pub trait Interpolate: Clone {
}
}

/// Steps between two different discrete values of any type.
/// Returns `a` if `t < 1.0`, otherwise returns `b`.
///
/// This is a common form of interpolation for discrete types.
#[inline]
fn step_unclamped<T>(a: T, b: T, t: f32) -> T {
if t < 1.0 {
a
} else {
b
}
}

impl<V> Interpolate for V
where
V: VectorSpace,
{
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
*self * (1.0 - t) + *other * t
self.lerp(*other, t)
}
}

impl Interpolate for Quat {
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
self.slerp(*other, t)
}
}

impl Interpolate for Dir2 {
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
self.slerp(*other, t)
}
}

impl Interpolate for Dir3 {
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
self.slerp(*other, t)
}
}

impl Interpolate for Dir3A {
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
self.slerp(*other, t)
}
}

/// This macro is for implementing `Interpolate` on non-f32-based vector-space-like entities.
macro_rules! impl_float_interpolate {
($ty: ty, $base: ty) => {
impl Interpolate for $ty {
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
let t = <$base>::from(t);
(*self) * (1.0 - t) + (*other) * t
}
}
};
}

impl_float_interpolate!(f64, f64);
impl_float_interpolate!(DVec2, f64);
impl_float_interpolate!(DVec3, f64);
impl_float_interpolate!(DVec4, f64);

// This is slightly cursed but necessary for unifying with an `Animatable` implementation for `bool`
impl Interpolate for bool {
#[inline]
fn interpolate(&self, other: &Self, t: f32) -> Self {
step_unclamped(*self, *other, t)
}
}
6 changes: 3 additions & 3 deletions crates/bevy_math/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ pub mod prelude {
},
direction::{Dir2, Dir3, Dir3A},
primitives::*,
BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4,
Quat, Ray2d, Ray3d, Rect, Rotation2d, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3,
Vec3Swizzles, Vec4, Vec4Swizzles,
BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Interpolate, Mat2,
Mat3, Mat4, Quat, Ray2d, Ray3d, Rect, Rotation2d, URect, UVec2, UVec3, UVec4, Vec2,
Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles,
};
}

Expand Down
12 changes: 11 additions & 1 deletion crates/bevy_transform/src/components/transform.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::GlobalTransform;
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_math::{Affine3A, Dir3, Mat3, Mat4, Quat, Vec3};
use bevy_math::{Affine3A, Dir3, Interpolate, Mat3, Mat4, Quat, Vec3};
use bevy_reflect::prelude::*;
use bevy_reflect::Reflect;
use std::ops::Mul;
Expand Down Expand Up @@ -559,3 +559,13 @@ impl Mul<Vec3> for Transform {
self.transform_point(value)
}
}

impl Interpolate for Transform {
fn interpolate(&self, other: &Self, t: f32) -> Self {
Transform {
translation: self.translation.interpolate(&other.translation, t),
rotation: self.rotation.interpolate(&other.rotation, t),
scale: self.scale.interpolate(&other.scale, t),
}
}
}
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ Example | Description
[Random Sampling](../examples/math/random_sampling.rs) | Demonstrates how to sample random points from mathematical primitives
[Rendering Primitives](../examples/math/render_primitives.rs) | Shows off rendering for all math primitives as both Meshes and Gizmos
[Sampling Primitives](../examples/math/sampling_primitives.rs) | Demonstrates all the primitives which can be sampled.
[Smooth Follow](../examples/math/smooth_follow.rs) | Demonstrates how to make an entity smoothly follow another using interpolation

## Reflection

Expand Down
Loading

0 comments on commit fd30d04

Please sign in to comment.