From 6a209f173dd2ed6025cbc2baca6bb4faa62b5592 Mon Sep 17 00:00:00 2001 From: james7132 Date: Fri, 15 Apr 2022 05:22:02 -0700 Subject: [PATCH 01/16] Add Animatable trait --- crates/bevy_animation/src/animatable.rs | 221 ++++++++++++++++++++++++ crates/bevy_animation/src/lib.rs | 6 +- crates/bevy_animation/src/util.rs | 28 +++ 3 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_animation/src/animatable.rs create mode 100644 crates/bevy_animation/src/util.rs diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs new file mode 100644 index 0000000000000..4971e407de780 --- /dev/null +++ b/crates/bevy_animation/src/animatable.rs @@ -0,0 +1,221 @@ +use crate::util; +use bevy_asset::{Asset, Assets, Handle, HandleId}; +use bevy_core::FloatOrd; +use bevy_ecs::world::World; +use bevy_math::*; +use bevy_reflect::Reflect; +use bevy_transform::prelude::Transform; + +/// An individual input for [`Animatable::blend`]. +pub struct BlendInput { + /// The individual item's weight. This may not be bound to the range `[0.0, 1.0]`. + pub weight: f32, + /// The input value to be blended. + pub value: T, + /// Whether or not to additively blend this input into the final result. + pub additive: bool, +} + +/// An animatable value type. +pub trait Animatable: Reflect + Sized + Send + Sync + 'static { + /// Interpolates between two values of. + /// + /// The `time` parameter here may not be clamped to the range `[0.0, 1.0]`. + fn interpolate(a: &Self, b: &Self, time: f32) -> Self; + + /// Blends one or more values together. + /// + /// Implementors should return a default value when no inputs are provided here. + fn blend(inputs: impl Iterator>) -> Self; + + /// Post-processes the value using resources in the [`World`]. + /// Most animatable types do not need to implement this. + /// + /// # Safety + /// All concrete implementors of this function can only read + /// into the resources stored in the World. Mutation of any state, + /// or reading any component or [`NonSend`] resource data may cause + /// undefined behavior or data races. + /// + /// [`NonSend`]: bevy_ecs::system::NonSend + unsafe fn post_process(&mut self, _world: &World) {} +} + +macro_rules! impl_float_animatable { + ($ty: ty, $base: ty) => { + impl Animatable for $ty { + #[inline(always)] + fn interpolate(a: &Self, b: &Self, t: f32) -> Self { + let t = <$base>::from(t); + (*a) * (1.0 - t) + (*b) * t + } + + #[inline(always)] + fn blend(inputs: impl Iterator>) -> Self { + let mut value = Default::default(); + for input in inputs { + if input.additive { + value += <$base>::from(input.weight) * input.value; + } else { + value = Self::interpolate(&value, &input.value, input.weight); + } + } + value + } + } + }; +} + +impl_float_animatable!(f32, f32); +impl_float_animatable!(Vec2, f32); +impl_float_animatable!(Vec3A, f32); +impl_float_animatable!(Vec4, f32); + +impl_float_animatable!(f64, f64); +impl_float_animatable!(DVec2, f64); +impl_float_animatable!(DVec3, f64); +impl_float_animatable!(DVec4, f64); + +// Vec3 is special cased to use Vec3A internally for blending +impl Animatable for Vec3 { + #[inline(always)] + fn interpolate(a: &Self, b: &Self, t: f32) -> Self { + (*a) * (1.0 - t) + (*b) * t + } + + #[inline(always)] + fn blend(inputs: impl Iterator>) -> Self { + let mut value = Vec3A::ZERO; + for input in inputs { + if input.additive { + value += input.weight * Vec3A::from(input.value); + } else { + value = Vec3A::interpolate(&value, &Vec3A::from(input.value), input.weight); + } + } + Self::from(value) + } +} + +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>) -> Self { + inputs + .max_by(|a, b| FloatOrd(a.weight).cmp(&FloatOrd(b.weight))) + .map(|input| input.value) + .unwrap_or(false) + } +} + +impl Animatable for HandleId { + #[inline] + fn interpolate(a: &Self, b: &Self, t: f32) -> Self { + util::step_unclamped(*a, *b, t) + } + + #[inline] + fn blend(inputs: impl Iterator>) -> Self { + inputs + .max_by(|a, b| FloatOrd(a.weight).cmp(&FloatOrd(b.weight))) + .map(|input| input.value) + .expect("Attempted to blend HandleId with zero inputs.") + } +} + +impl Animatable for Handle { + #[inline] + fn interpolate(a: &Self, b: &Self, t: f32) -> Self { + util::step_unclamped(a.clone_weak(), b.clone_weak(), t) + } + + #[inline] + fn blend(inputs: impl Iterator>) -> Self { + inputs + .max_by(|a, b| FloatOrd(a.weight).cmp(&FloatOrd(b.weight))) + .map(|input| input.value) + .expect("Attempted to blend Handle with zero inputs.") + } + + // SAFE: This implementation only reads resources from the provided + // World. + unsafe fn post_process(&mut self, world: &World) { + // Upgrade weak handles into strong ones. + if self.is_strong() { + return; + } + *self = world + .get_resource::>() + .expect( + "Attempted to animate a Handle without the corresponding Assets resource.", + ) + .get_handle(self.id); + } +} + +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>) -> Self { + let mut translation = Vec3A::ZERO; + let mut scale = Vec3A::ZERO; + let mut rotation = Quat::IDENTITY; + + for input in inputs { + if input.additive { + translation += input.weight * Vec3A::from(input.value.translation); + scale += input.weight * Vec3A::from(input.value.scale); + rotation = (input.value.rotation * input.weight) * rotation; + } else { + translation = Vec3A::interpolate( + &translation, + &Vec3A::from(input.value.translation), + input.weight, + ); + scale = Vec3A::interpolate(&scale, &Vec3A::from(input.value.scale), input.weight); + rotation = Quat::interpolate(&rotation, &input.value.rotation, input.weight); + } + } + + Self { + translation: Vec3::from(translation), + rotation, + scale: Vec3::from(scale), + } + } +} + +impl Animatable for Quat { + /// Performs an nlerp, because it's cheaper and easier to combine with other animations, + /// reference: + #[inline] + fn interpolate(a: &Self, b: &Self, t: f32) -> Self { + // Make sure is always the short path, look at this: https://github.com/mgeier/quaternion-nursery + let b = if a.dot(*b) < 0.0 { -*b } else { *b }; + + let a: Vec4 = (*a).into(); + let b: Vec4 = b.into(); + let rot = Vec4::interpolate(&a, &b, t); + let inv_mag = util::approx_rsqrt(rot.dot(rot)); + Quat::from_vec4(rot * inv_mag) + } + + #[inline] + fn blend(inputs: impl Iterator>) -> Self { + let mut value = Self::IDENTITY; + for input in inputs { + value = Self::interpolate(&value, &input.value, input.weight); + } + value + } +} diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index 1989516334297..8757adb94b49d 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -2,6 +2,9 @@ #![warn(missing_docs)] +mod animatable; +mod util; + use std::ops::Deref; use bevy_app::{App, CoreStage, Plugin}; @@ -25,7 +28,8 @@ use bevy_utils::{tracing::warn, HashMap}; pub mod prelude { #[doc(hidden)] pub use crate::{ - AnimationClip, AnimationPlayer, AnimationPlugin, EntityPath, Keyframes, VariableCurve, + animatable::*, AnimationClip, AnimationPlayer, AnimationPlugin, EntityPath, Keyframes, + VariableCurve, }; } diff --git a/crates/bevy_animation/src/util.rs b/crates/bevy_animation/src/util.rs new file mode 100644 index 0000000000000..770fbe697dfa8 --- /dev/null +++ b/crates/bevy_animation/src/util.rs @@ -0,0 +1,28 @@ +/// Fast approximated reciprocal square root. +#[inline] +pub(crate) fn approx_rsqrt(x: f32) -> f32 { + // Fall back to Quake 3 fast inverse sqrt, is has a higher error + // but still good enough and faster than `.sqrt().recip()`, + // implementation borrowed from Piston under the MIT License: + // [https://github.com/PistonDevelopers/skeletal_animation] + let x2: f32 = x * 0.5; + let mut y: f32 = x; + + let mut i: i32 = y.to_bits() as i32; + i = 0x5f3759df - (i >> 1); + y = f32::from_bits(i as u32); + + y = y * (1.5 - (x2 * y * y)); + y +} + +/// Steps between two different discrete values of any clonable type. +/// Returns a copy of `b` if `t >= 1.0`, otherwise returns a copy of `b`. +#[inline] +pub(crate) fn step_unclamped(a: T, b: T, t: f32) -> T { + if t >= 1.0 { + a + } else { + b + } +} From ef0963f4319dcebfbd666db1155cedefe93c4084 Mon Sep 17 00:00:00 2001 From: James Liu Date: Fri, 15 Apr 2022 15:43:30 -0700 Subject: [PATCH 02/16] more accurate approx_sqrt Co-authored-by: Kirillov Kirill --- crates/bevy_animation/src/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_animation/src/util.rs b/crates/bevy_animation/src/util.rs index 770fbe697dfa8..45443cb1ca969 100644 --- a/crates/bevy_animation/src/util.rs +++ b/crates/bevy_animation/src/util.rs @@ -9,10 +9,10 @@ pub(crate) fn approx_rsqrt(x: f32) -> f32 { let mut y: f32 = x; let mut i: i32 = y.to_bits() as i32; - i = 0x5f3759df - (i >> 1); + i = 0x5f1ffff9 - (i >> 1); y = f32::from_bits(i as u32); - y = y * (1.5 - (x2 * y * y)); + y = 0.703952253 * y * (2.38924456 - (x2 * y * y)); y } From bec4c6d0ee5f0f246248754138510ffeff91efc8 Mon Sep 17 00:00:00 2001 From: james7132 Date: Wed, 27 Apr 2022 17:56:57 -0700 Subject: [PATCH 03/16] Update comment about implementation, appease clippy --- crates/bevy_animation/src/util.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/bevy_animation/src/util.rs b/crates/bevy_animation/src/util.rs index 45443cb1ca969..30a47186fe8e7 100644 --- a/crates/bevy_animation/src/util.rs +++ b/crates/bevy_animation/src/util.rs @@ -1,10 +1,14 @@ /// Fast approximated reciprocal square root. #[inline] pub(crate) fn approx_rsqrt(x: f32) -> f32 { - // Fall back to Quake 3 fast inverse sqrt, is has a higher error - // but still good enough and faster than `.sqrt().recip()`, - // implementation borrowed from Piston under the MIT License: + // Quake 3 fast inverse sqrt, has a higher error but still good + // enough and faster than `.sqrt().recip()`, implementation + // borrowed from Piston under the MIT License: // [https://github.com/PistonDevelopers/skeletal_animation] + // + // Includes a refinement seen in [http://rrrola.wz.cz/inv_sqrt.html] + // that improves overall accuracy by 2.7x while maintaining the same + // performance characteristics. let x2: f32 = x * 0.5; let mut y: f32 = x; @@ -12,7 +16,7 @@ pub(crate) fn approx_rsqrt(x: f32) -> f32 { i = 0x5f1ffff9 - (i >> 1); y = f32::from_bits(i as u32); - y = 0.703952253 * y * (2.38924456 - (x2 * y * y)); + y = 0.70395225 * y * (2.3892446 - (x2 * y * y)); y } From acddae357b2fc576beefc289fc6055f06ce31eb1 Mon Sep 17 00:00:00 2001 From: james7132 Date: Mon, 7 Nov 2022 01:55:14 -0800 Subject: [PATCH 04/16] Make post_process safe --- crates/bevy_animation/src/animatable.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index 4971e407de780..3895d35bfc468 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -30,15 +30,7 @@ pub trait Animatable: Reflect + Sized + Send + Sync + 'static { /// Post-processes the value using resources in the [`World`]. /// Most animatable types do not need to implement this. - /// - /// # Safety - /// All concrete implementors of this function can only read - /// into the resources stored in the World. Mutation of any state, - /// or reading any component or [`NonSend`] resource data may cause - /// undefined behavior or data races. - /// - /// [`NonSend`]: bevy_ecs::system::NonSend - unsafe fn post_process(&mut self, _world: &World) {} + fn post_process(&mut self, _world: &World) {} } macro_rules! impl_float_animatable { From 77eb93fe5707bb5dba29e8030af20dfbc6dc37b7 Mon Sep 17 00:00:00 2001 From: james7132 Date: Mon, 7 Nov 2022 01:57:42 -0800 Subject: [PATCH 05/16] Remove the inline(always) that are unnecessary --- crates/bevy_animation/src/animatable.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index 3895d35bfc468..7ce9803ae8fe7 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -18,7 +18,7 @@ pub struct BlendInput { /// An animatable value type. pub trait Animatable: Reflect + Sized + Send + Sync + 'static { - /// Interpolates between two values of. + /// 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; @@ -70,12 +70,12 @@ impl_float_animatable!(DVec4, f64); // Vec3 is special cased to use Vec3A internally for blending impl Animatable for Vec3 { - #[inline(always)] + #[inline] fn interpolate(a: &Self, b: &Self, t: f32) -> Self { (*a) * (1.0 - t) + (*b) * t } - #[inline(always)] + #[inline] fn blend(inputs: impl Iterator>) -> Self { let mut value = Vec3A::ZERO; for input in inputs { From 08fe08abc8585d0becb9e57a9cb5290a1d44f885 Mon Sep 17 00:00:00 2001 From: james7132 Date: Mon, 7 Nov 2022 02:07:36 -0800 Subject: [PATCH 06/16] Fix CI --- crates/bevy_animation/src/animatable.rs | 10 ++++------ crates/bevy_animation/src/util.rs | 22 ---------------------- crates/bevy_math/src/lib.rs | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index 7ce9803ae8fe7..af271a0e6465d 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -1,10 +1,10 @@ use crate::util; use bevy_asset::{Asset, Assets, Handle, HandleId}; -use bevy_core::FloatOrd; use bevy_ecs::world::World; use bevy_math::*; use bevy_reflect::Reflect; use bevy_transform::prelude::Transform; +use bevy_utils::FloatOrd; /// An individual input for [`Animatable::blend`]. pub struct BlendInput { @@ -133,9 +133,7 @@ impl Animatable for Handle { .expect("Attempted to blend Handle with zero inputs.") } - // SAFE: This implementation only reads resources from the provided - // World. - unsafe fn post_process(&mut self, world: &World) { + fn post_process(&mut self, world: &World) { // Upgrade weak handles into strong ones. if self.is_strong() { return; @@ -145,7 +143,7 @@ impl Animatable for Handle { .expect( "Attempted to animate a Handle without the corresponding Assets resource.", ) - .get_handle(self.id); + .get_handle(self.id()); } } @@ -198,7 +196,7 @@ impl Animatable for Quat { let a: Vec4 = (*a).into(); let b: Vec4 = b.into(); let rot = Vec4::interpolate(&a, &b, t); - let inv_mag = util::approx_rsqrt(rot.dot(rot)); + let inv_mag = bevy_math::approx_rsqrt(rot.dot(rot)); Quat::from_vec4(rot * inv_mag) } diff --git a/crates/bevy_animation/src/util.rs b/crates/bevy_animation/src/util.rs index 30a47186fe8e7..da4bfec960b12 100644 --- a/crates/bevy_animation/src/util.rs +++ b/crates/bevy_animation/src/util.rs @@ -1,25 +1,3 @@ -/// Fast approximated reciprocal square root. -#[inline] -pub(crate) fn approx_rsqrt(x: f32) -> f32 { - // Quake 3 fast inverse sqrt, has a higher error but still good - // enough and faster than `.sqrt().recip()`, implementation - // borrowed from Piston under the MIT License: - // [https://github.com/PistonDevelopers/skeletal_animation] - // - // Includes a refinement seen in [http://rrrola.wz.cz/inv_sqrt.html] - // that improves overall accuracy by 2.7x while maintaining the same - // performance characteristics. - let x2: f32 = x * 0.5; - let mut y: f32 = x; - - let mut i: i32 = y.to_bits() as i32; - i = 0x5f1ffff9 - (i >> 1); - y = f32::from_bits(i as u32); - - y = 0.70395225 * y * (2.3892446 - (x2 * y * y)); - y -} - /// Steps between two different discrete values of any clonable type. /// Returns a copy of `b` if `t >= 1.0`, otherwise returns a copy of `b`. #[inline] diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 3e397536f8c4c..8da81fafe88bd 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -22,3 +22,25 @@ pub mod prelude { } pub use glam::*; + +/// Fast approximated reciprocal square root. +#[inline] +pub fn approx_rsqrt(x: f32) -> f32 { + // Quake 3 fast inverse sqrt, has a higher error but still good + // enough and faster than `.sqrt().recip()`, implementation + // borrowed from Piston under the MIT License: + // [https://github.com/PistonDevelopers/skeletal_animation] + // + // Includes a refinement seen in [http://rrrola.wz.cz/inv_sqrt.html] + // that improves overall accuracy by 2.7x while maintaining the same + // performance characteristics. + let x2: f32 = x * 0.5; + let mut y: f32 = x; + + let mut i: i32 = y.to_bits() as i32; + i = 0x5f1ffff9 - (i >> 1); + y = f32::from_bits(i as u32); + + y = 0.70395225 * y * (2.3892446 - (x2 * y * y)); + y +} From 8e69ca9940e642e503209d39ae83db27c5687ae0 Mon Sep 17 00:00:00 2001 From: James Liu Date: Mon, 7 Nov 2022 02:50:46 -0800 Subject: [PATCH 07/16] Fix docs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François --- crates/bevy_animation/src/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_animation/src/util.rs b/crates/bevy_animation/src/util.rs index da4bfec960b12..cf72be3f8bd25 100644 --- a/crates/bevy_animation/src/util.rs +++ b/crates/bevy_animation/src/util.rs @@ -1,5 +1,5 @@ /// Steps between two different discrete values of any clonable type. -/// Returns a copy of `b` if `t >= 1.0`, otherwise returns a copy of `b`. +/// Returns a copy of `b` if `t >= 1.0`, otherwise returns a copy of `a`. #[inline] pub(crate) fn step_unclamped(a: T, b: T, t: f32) -> T { if t >= 1.0 { From 37eaee7738ca8bbe44f4532d3e9ed19bed394773 Mon Sep 17 00:00:00 2001 From: James Liu Date: Sat, 19 Nov 2022 05:14:51 -0800 Subject: [PATCH 08/16] Remove "always" from inline. Co-authored-by: Kirillov Kirill --- crates/bevy_animation/src/animatable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index af271a0e6465d..0b670014e0a74 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -42,7 +42,7 @@ macro_rules! impl_float_animatable { (*a) * (1.0 - t) + (*b) * t } - #[inline(always)] + #[inline] fn blend(inputs: impl Iterator>) -> Self { let mut value = Default::default(); for input in inputs { From dccb45974b989bd6d34f765608c147d71a6e605f Mon Sep 17 00:00:00 2001 From: James Liu Date: Sat, 19 Nov 2022 05:14:58 -0800 Subject: [PATCH 09/16] Remove "always" from inline. Co-authored-by: Kirillov Kirill --- crates/bevy_animation/src/animatable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index 0b670014e0a74..80577563b6d3b 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -36,7 +36,7 @@ pub trait Animatable: Reflect + Sized + Send + Sync + 'static { macro_rules! impl_float_animatable { ($ty: ty, $base: ty) => { impl Animatable for $ty { - #[inline(always)] + #[inline] fn interpolate(a: &Self, b: &Self, t: f32) -> Self { let t = <$base>::from(t); (*a) * (1.0 - t) + (*b) * t From dd649101ce8ffee2a8c85b984c93ae44806cbb0b Mon Sep 17 00:00:00 2001 From: James Liu Date: Sat, 23 Dec 2023 08:25:46 -0800 Subject: [PATCH 10/16] Fix step_unclamped Co-authored-by: irate --- crates/bevy_animation/src/util.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_animation/src/util.rs b/crates/bevy_animation/src/util.rs index cf72be3f8bd25..67aaf8116e365 100644 --- a/crates/bevy_animation/src/util.rs +++ b/crates/bevy_animation/src/util.rs @@ -1,8 +1,8 @@ -/// Steps between two different discrete values of any clonable type. -/// Returns a copy of `b` if `t >= 1.0`, otherwise returns a copy of `a`. +/// Steps between two different discrete values of any type. +/// Returns `a` if `t < 1.0`, otherwise returns `b`. #[inline] pub(crate) fn step_unclamped(a: T, b: T, t: f32) -> T { - if t >= 1.0 { + if t < 1.0 { a } else { b From 9236d4bca6be855087d43642414cdb6da7fde1ae Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 11 Jan 2024 15:50:18 -0500 Subject: [PATCH 11/16] Remove impl Animatible for HandleID (removed) --- crates/bevy_animation/src/animatable.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index 80577563b6d3b..fb1a51185d55d 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -1,5 +1,5 @@ use crate::util; -use bevy_asset::{Asset, Assets, Handle, HandleId}; +use bevy_asset::{Asset, Assets, Handle}; use bevy_ecs::world::World; use bevy_math::*; use bevy_reflect::Reflect; @@ -104,21 +104,6 @@ impl Animatable for bool { } } -impl Animatable for HandleId { - #[inline] - fn interpolate(a: &Self, b: &Self, t: f32) -> Self { - util::step_unclamped(*a, *b, t) - } - - #[inline] - fn blend(inputs: impl Iterator>) -> Self { - inputs - .max_by(|a, b| FloatOrd(a.weight).cmp(&FloatOrd(b.weight))) - .map(|input| input.value) - .expect("Attempted to blend HandleId with zero inputs.") - } -} - impl Animatable for Handle { #[inline] fn interpolate(a: &Self, b: &Self, t: f32) -> Self { From f1120d6cdc75f2fbd4c124fd5bc91c7d8596513f Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 11 Jan 2024 16:05:59 -0500 Subject: [PATCH 12/16] Remove Animatible for Handle --- crates/bevy_animation/src/animatable.rs | 29 ------------------------- 1 file changed, 29 deletions(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index fb1a51185d55d..853f9b3872e66 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -1,5 +1,4 @@ use crate::util; -use bevy_asset::{Asset, Assets, Handle}; use bevy_ecs::world::World; use bevy_math::*; use bevy_reflect::Reflect; @@ -104,34 +103,6 @@ impl Animatable for bool { } } -impl Animatable for Handle { - #[inline] - fn interpolate(a: &Self, b: &Self, t: f32) -> Self { - util::step_unclamped(a.clone_weak(), b.clone_weak(), t) - } - - #[inline] - fn blend(inputs: impl Iterator>) -> Self { - inputs - .max_by(|a, b| FloatOrd(a.weight).cmp(&FloatOrd(b.weight))) - .map(|input| input.value) - .expect("Attempted to blend Handle with zero inputs.") - } - - fn post_process(&mut self, world: &World) { - // Upgrade weak handles into strong ones. - if self.is_strong() { - return; - } - *self = world - .get_resource::>() - .expect( - "Attempted to animate a Handle without the corresponding Assets resource.", - ) - .get_handle(self.id()); - } -} - impl Animatable for Transform { fn interpolate(a: &Self, b: &Self, t: f32) -> Self { Self { From 13fc8387ed832244d6895a77f4b824766769b71d Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 11 Jan 2024 16:46:02 -0500 Subject: [PATCH 13/16] Use slerp rather than a handrolled lerp for Quats --- crates/bevy_animation/src/animatable.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index 853f9b3872e66..c9ec74e8cac30 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -146,14 +146,9 @@ impl Animatable for Quat { /// reference: #[inline] fn interpolate(a: &Self, b: &Self, t: f32) -> Self { - // Make sure is always the short path, look at this: https://github.com/mgeier/quaternion-nursery - let b = if a.dot(*b) < 0.0 { -*b } else { *b }; - - let a: Vec4 = (*a).into(); - let b: Vec4 = b.into(); - let rot = Vec4::interpolate(&a, &b, t); - let inv_mag = bevy_math::approx_rsqrt(rot.dot(rot)); - Quat::from_vec4(rot * inv_mag) + // 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] From 195e8303d8ffb5316182187e4e755e74e973e3c3 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 11 Jan 2024 16:51:01 -0500 Subject: [PATCH 14/16] Use slerp for additive Transform blending --- crates/bevy_animation/src/animatable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_animation/src/animatable.rs b/crates/bevy_animation/src/animatable.rs index c9ec74e8cac30..24b90316faa35 100644 --- a/crates/bevy_animation/src/animatable.rs +++ b/crates/bevy_animation/src/animatable.rs @@ -121,7 +121,7 @@ impl Animatable for Transform { if input.additive { translation += input.weight * Vec3A::from(input.value.translation); scale += input.weight * Vec3A::from(input.value.scale); - rotation = (input.value.rotation * input.weight) * rotation; + rotation = rotation.slerp(input.value.rotation, input.weight); } else { translation = Vec3A::interpolate( &translation, From a7e464a9928c070a7489505dc3b9a65ac36640ab Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 11 Jan 2024 16:53:53 -0500 Subject: [PATCH 15/16] Remove handrolled inverse sqrt --- crates/bevy_math/src/lib.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index a75c5d60bc508..f38ba56166716 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -34,25 +34,3 @@ pub mod prelude { } pub use glam::*; - -/// Fast approximated reciprocal square root. -#[inline] -pub fn approx_rsqrt(x: f32) -> f32 { - // Quake 3 fast inverse sqrt, has a higher error but still good - // enough and faster than `.sqrt().recip()`, implementation - // borrowed from Piston under the MIT License: - // [https://github.com/PistonDevelopers/skeletal_animation] - // - // Includes a refinement seen in [http://rrrola.wz.cz/inv_sqrt.html] - // that improves overall accuracy by 2.7x while maintaining the same - // performance characteristics. - let x2: f32 = x * 0.5; - let mut y: f32 = x; - - let mut i: i32 = y.to_bits() as i32; - i = 0x5f1ffff9 - (i >> 1); - y = f32::from_bits(i as u32); - - y = 0.70395225 * y * (2.3892446 - (x2 * y * y)); - y -} From da5f7a9cdb85db330516c3fa6d690eef7be02ba6 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 2 Feb 2024 16:06:52 -0500 Subject: [PATCH 16/16] Cargo fmt --- crates/bevy_animation/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index eef115f6aab2b..43d66fd2d81bb 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -24,8 +24,8 @@ use bevy_utils::{tracing::warn, HashMap}; pub mod prelude { #[doc(hidden)] pub use crate::{ - animatable::*, AnimationClip, AnimationPlayer, AnimationPlugin, EntityPath, Interpolation, Keyframes, - VariableCurve, + animatable::*, AnimationClip, AnimationPlayer, AnimationPlugin, EntityPath, Interpolation, + Keyframes, VariableCurve, }; }