Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_animation/src/animation_curves.rs
6595 views
1
//! The [`AnimationCurve`] trait and adaptors that allow curves to implement it.
2
//!
3
//! # Overview
4
//!
5
//! The flow of curves into the animation system generally begins with something that
6
//! implements the [`Curve`] trait. Let's imagine, for example, that we have some
7
//! `Curve<Vec3>` that we want to use to animate something. That could be defined in
8
//! a number of different ways, but let's imagine that we've defined it [using a function]:
9
//!
10
//! # use bevy_math::curve::{Curve, Interval, FunctionCurve};
11
//! # use bevy_math::vec3;
12
//! let wobble_curve = FunctionCurve::new(
13
//! Interval::UNIT,
14
//! |t| { vec3(t.cos(), 0.0, 0.0) },
15
//! );
16
//!
17
//! Okay, so we have a curve, but the animation system also needs to know, in some way,
18
//! how the values from this curve should actually be used. That is, it needs to know what
19
//! to animate! That's what [`AnimationCurve`] is for. In particular, what we need to do
20
//! is take our curve and turn it into an `AnimationCurve` which will be usable by the
21
//! animation system.
22
//!
23
//! For instance, let's imagine that we want to use the `Vec3` output
24
//! from our curve to animate the [translation component of a `Transform`]. For this, there is
25
//! the adaptor [`AnimatableCurve`], which wraps any [`Curve`] and [`AnimatableProperty`] and turns it into an
26
//! [`AnimationCurve`] that will use the given curve to animate the entity's property:
27
//!
28
//! # use bevy_math::curve::{Curve, Interval, FunctionCurve};
29
//! # use bevy_math::vec3;
30
//! # use bevy_transform::components::Transform;
31
//! # use bevy_animation::{animated_field, animation_curves::*};
32
//! # let wobble_curve = FunctionCurve::new(
33
//! # Interval::UNIT,
34
//! # |t| vec3(t.cos(), 0.0, 0.0)
35
//! # );
36
//! let wobble_animation = AnimatableCurve::new(animated_field!(Transform::translation), wobble_curve);
37
//!
38
//! And finally, this [`AnimationCurve`] needs to be added to an [`AnimationClip`] in order to
39
//! actually animate something. This is what that looks like:
40
//!
41
//! # use bevy_math::curve::{Curve, Interval, FunctionCurve};
42
//! # use bevy_animation::{AnimationClip, AnimationTargetId, animated_field, animation_curves::*};
43
//! # use bevy_transform::components::Transform;
44
//! # use bevy_ecs::name::Name;
45
//! # use bevy_math::vec3;
46
//! # let wobble_curve = FunctionCurve::new(
47
//! # Interval::UNIT,
48
//! # |t| { vec3(t.cos(), 0.0, 0.0) },
49
//! # );
50
//! # let wobble_animation = AnimatableCurve::new(animated_field!(Transform::translation), wobble_curve);
51
//! # let animation_target_id = AnimationTargetId::from(&Name::new("Test"));
52
//! let mut animation_clip = AnimationClip::default();
53
//! animation_clip.add_curve_to_target(
54
//! animation_target_id,
55
//! wobble_animation,
56
//! );
57
//!
58
//! # Making animation curves
59
//!
60
//! The overview showed one example, but in general there are a few different ways of going from
61
//! a [`Curve`], which produces time-related data of some kind, to an [`AnimationCurve`], which
62
//! knows how to apply that data to an entity.
63
//!
64
//! ## Animated Fields
65
//!
66
//! The [`animated_field`] macro (which returns an [`AnimatedField`]), in combination with [`AnimatableCurve`]
67
//! is the easiest way to make an animation curve (see the example above).
68
//!
69
//! This will select a field on a component and pass it to a [`Curve`] with a type that matches the field.
70
//!
71
//! ## Animatable Properties
72
//!
73
//! Animation of arbitrary aspects of entities can be accomplished using [`AnimatableProperty`] in
74
//! conjunction with [`AnimatableCurve`]. See the documentation [there] for details.
75
//!
76
//! ## Custom [`AnimationCurve`] and [`AnimationCurveEvaluator`]
77
//!
78
//! This is the lowest-level option with the most control, but it is also the most complicated.
79
//!
80
//! [using a function]: bevy_math::curve::FunctionCurve
81
//! [translation component of a `Transform`]: bevy_transform::prelude::Transform::translation
82
//! [`AnimationClip`]: crate::AnimationClip
83
//! [there]: AnimatableProperty
84
//! [`animated_field`]: crate::animated_field
85
86
use core::{
87
any::TypeId,
88
fmt::{self, Debug, Formatter},
89
marker::PhantomData,
90
};
91
92
use crate::{
93
graph::AnimationNodeIndex,
94
prelude::{Animatable, BlendInput},
95
AnimationEntityMut, AnimationEvaluationError,
96
};
97
use bevy_ecs::component::{Component, Mutable};
98
use bevy_math::curve::{
99
cores::{UnevenCore, UnevenCoreError},
100
iterable::IterableCurve,
101
Curve, Interval,
102
};
103
use bevy_mesh::morph::MorphWeights;
104
use bevy_platform::hash::Hashed;
105
use bevy_reflect::{FromReflect, Reflect, Reflectable, TypeInfo, Typed};
106
use downcast_rs::{impl_downcast, Downcast};
107
108
/// A trait for exposing a value in an entity so that it can be animated.
109
///
110
/// `AnimatableProperty` allows any value contained in an entity to be animated
111
/// as long as it can be obtained by mutable reference. This makes it more
112
/// flexible than [`animated_field`].
113
///
114
/// [`animated_field`]: crate::animated_field
115
///
116
/// Here, `AnimatableProperty` is used to animate a value inside an `Option`,
117
/// returning an error if the option is `None`.
118
///
119
/// # use bevy_animation::{prelude::AnimatableProperty, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId};
120
/// # use bevy_ecs::component::Component;
121
/// # use std::any::TypeId;
122
/// #[derive(Component)]
123
/// struct ExampleComponent {
124
/// power_level: Option<f32>
125
/// }
126
///
127
/// #[derive(Clone)]
128
/// struct PowerLevelProperty;
129
///
130
/// impl AnimatableProperty for PowerLevelProperty {
131
/// type Property = f32;
132
/// fn get_mut<'a>(
133
/// &self,
134
/// entity: &'a mut AnimationEntityMut
135
/// ) -> Result<&'a mut Self::Property, AnimationEvaluationError> {
136
/// let component = entity
137
/// .get_mut::<ExampleComponent>()
138
/// .ok_or(AnimationEvaluationError::ComponentNotPresent(
139
/// TypeId::of::<ExampleComponent>()
140
/// ))?
141
/// .into_inner();
142
/// component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent(
143
/// TypeId::of::<Option<f32>>()
144
/// ))
145
/// }
146
///
147
/// fn evaluator_id(&self) -> EvaluatorId {
148
/// EvaluatorId::Type(TypeId::of::<Self>())
149
/// }
150
/// }
151
///
152
///
153
/// You can then create an [`AnimatableCurve`] to animate this property like so:
154
///
155
/// # use bevy_animation::{VariableCurve, AnimationEntityMut, AnimationEvaluationError, animation_curves::EvaluatorId};
156
/// # use bevy_animation::prelude::{AnimatableProperty, AnimatableKeyframeCurve, AnimatableCurve};
157
/// # use bevy_ecs::{name::Name, component::Component};
158
/// # use std::any::TypeId;
159
/// # #[derive(Component)]
160
/// # struct ExampleComponent { power_level: Option<f32> }
161
/// # #[derive(Clone)]
162
/// # struct PowerLevelProperty;
163
/// # impl AnimatableProperty for PowerLevelProperty {
164
/// # type Property = f32;
165
/// # fn get_mut<'a>(
166
/// # &self,
167
/// # entity: &'a mut AnimationEntityMut
168
/// # ) -> Result<&'a mut Self::Property, AnimationEvaluationError> {
169
/// # let component = entity
170
/// # .get_mut::<ExampleComponent>()
171
/// # .ok_or(AnimationEvaluationError::ComponentNotPresent(
172
/// # TypeId::of::<ExampleComponent>()
173
/// # ))?
174
/// # .into_inner();
175
/// # component.power_level.as_mut().ok_or(AnimationEvaluationError::PropertyNotPresent(
176
/// # TypeId::of::<Option<f32>>()
177
/// # ))
178
/// # }
179
/// # fn evaluator_id(&self) -> EvaluatorId {
180
/// # EvaluatorId::Type(TypeId::of::<Self>())
181
/// # }
182
/// # }
183
/// AnimatableCurve::new(
184
/// PowerLevelProperty,
185
/// AnimatableKeyframeCurve::new([
186
/// (0.0, 0.0),
187
/// (1.0, 9001.0),
188
/// ]).expect("Failed to create power level curve")
189
/// );
190
pub trait AnimatableProperty: Send + Sync + 'static {
191
/// The animated property type.
192
type Property: Animatable;
193
194
/// Retrieves the property from the given `entity`.
195
fn get_mut<'a>(
196
&self,
197
entity: &'a mut AnimationEntityMut,
198
) -> Result<&'a mut Self::Property, AnimationEvaluationError>;
199
200
/// The [`EvaluatorId`] used to look up the [`AnimationCurveEvaluator`] for this [`AnimatableProperty`].
201
/// For a given animated property, this ID should always be the same to allow things like animation blending to occur.
202
fn evaluator_id(&self) -> EvaluatorId<'_>;
203
}
204
205
/// A [`Component`] field that can be animated, defined by a function that reads the component and returns
206
/// the accessed field / property.
207
///
208
/// The best way to create an instance of this type is via the [`animated_field`] macro.
209
///
210
/// `C` is the component being animated, `A` is the type of the [`Animatable`] field on the component, and `F` is an accessor
211
/// function that accepts a reference to `C` and retrieves the field `A`.
212
///
213
/// [`animated_field`]: crate::animated_field
214
#[derive(Clone)]
215
pub struct AnimatedField<C, A, F: Fn(&mut C) -> &mut A> {
216
func: F,
217
/// A pre-hashed (component-type-id, reflected-field-index) pair, uniquely identifying a component field
218
evaluator_id: Hashed<(TypeId, usize)>,
219
marker: PhantomData<(C, A)>,
220
}
221
222
impl<C, A, F> AnimatableProperty for AnimatedField<C, A, F>
223
where
224
C: Component<Mutability = Mutable>,
225
A: Animatable + Clone + Sync + Debug,
226
F: Fn(&mut C) -> &mut A + Send + Sync + 'static,
227
{
228
type Property = A;
229
fn get_mut<'a>(
230
&self,
231
entity: &'a mut AnimationEntityMut,
232
) -> Result<&'a mut A, AnimationEvaluationError> {
233
let c = entity
234
.get_mut::<C>()
235
.ok_or_else(|| AnimationEvaluationError::ComponentNotPresent(TypeId::of::<C>()))?;
236
Ok((self.func)(c.into_inner()))
237
}
238
239
fn evaluator_id(&self) -> EvaluatorId<'_> {
240
EvaluatorId::ComponentField(&self.evaluator_id)
241
}
242
}
243
244
impl<C: Typed, P, F: Fn(&mut C) -> &mut P + 'static> AnimatedField<C, P, F> {
245
/// Creates a new instance of [`AnimatedField`]. This operates under the assumption that
246
/// `C` is a reflect-able struct, and that `field_name` is a valid field on that struct.
247
///
248
/// # Panics
249
/// If the type of `C` is not a struct or if the `field_name` does not exist.
250
pub fn new_unchecked(field_name: &str, func: F) -> Self {
251
let field_index;
252
if let TypeInfo::Struct(struct_info) = C::type_info() {
253
field_index = struct_info
254
.index_of(field_name)
255
.expect("Field name should exist");
256
} else if let TypeInfo::TupleStruct(struct_info) = C::type_info() {
257
field_index = field_name
258
.parse()
259
.expect("Field name should be a valid tuple index");
260
if field_index >= struct_info.field_len() {
261
panic!("Field name should be a valid tuple index");
262
}
263
} else {
264
panic!("Only structs are supported in `AnimatedField::new_unchecked`")
265
}
266
267
Self {
268
func,
269
evaluator_id: Hashed::new((TypeId::of::<C>(), field_index)),
270
marker: PhantomData,
271
}
272
}
273
}
274
275
/// This trait collects the additional requirements on top of [`Curve<T>`] needed for a
276
/// curve to be used as an [`AnimationCurve`].
277
pub trait AnimationCompatibleCurve<T>: Curve<T> + Debug + Clone + Reflectable {}
278
279
impl<T, C> AnimationCompatibleCurve<T> for C where C: Curve<T> + Debug + Clone + Reflectable {}
280
281
/// This type allows the conversion of a [curve] valued in the [property type] of an
282
/// [`AnimatableProperty`] into an [`AnimationCurve`] which animates that property.
283
///
284
/// [curve]: Curve
285
/// [property type]: AnimatableProperty::Property
286
#[derive(Reflect, FromReflect)]
287
#[reflect(from_reflect = false)]
288
pub struct AnimatableCurve<P, C> {
289
/// The property selector, which defines what component to access and how to access
290
/// a property on that component.
291
pub property: P,
292
293
/// The inner [curve] whose values are used to animate the property.
294
///
295
/// [curve]: Curve
296
pub curve: C,
297
}
298
299
/// An [`AnimatableCurveEvaluator`] for [`AnimatableProperty`] instances.
300
///
301
/// You shouldn't ordinarily need to instantiate one of these manually. Bevy
302
/// will automatically do so when you use an [`AnimatableCurve`] instance.
303
#[derive(Reflect)]
304
pub struct AnimatableCurveEvaluator<A: Animatable> {
305
evaluator: BasicAnimationCurveEvaluator<A>,
306
property: Box<dyn AnimatableProperty<Property = A>>,
307
}
308
309
impl<P, C> AnimatableCurve<P, C>
310
where
311
P: AnimatableProperty,
312
C: AnimationCompatibleCurve<P::Property>,
313
{
314
/// Create an [`AnimatableCurve`] (and thus an [`AnimationCurve`]) from a curve
315
/// valued in an [animatable property].
316
///
317
/// [animatable property]: AnimatableProperty::Property
318
pub fn new(property: P, curve: C) -> Self {
319
Self { property, curve }
320
}
321
}
322
323
impl<P, C> Clone for AnimatableCurve<P, C>
324
where
325
C: Clone,
326
P: Clone,
327
{
328
fn clone(&self) -> Self {
329
Self {
330
curve: self.curve.clone(),
331
property: self.property.clone(),
332
}
333
}
334
}
335
336
impl<P, C> Debug for AnimatableCurve<P, C>
337
where
338
C: Debug,
339
{
340
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
341
f.debug_struct("AnimatableCurve")
342
.field("curve", &self.curve)
343
.finish()
344
}
345
}
346
347
impl<P: Send + Sync + 'static, C> AnimationCurve for AnimatableCurve<P, C>
348
where
349
P: AnimatableProperty + Clone,
350
C: AnimationCompatibleCurve<P::Property> + Clone,
351
{
352
fn clone_value(&self) -> Box<dyn AnimationCurve> {
353
Box::new(self.clone())
354
}
355
356
fn domain(&self) -> Interval {
357
self.curve.domain()
358
}
359
360
fn evaluator_id(&self) -> EvaluatorId<'_> {
361
self.property.evaluator_id()
362
}
363
364
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator> {
365
Box::new(AnimatableCurveEvaluator::<P::Property> {
366
evaluator: BasicAnimationCurveEvaluator::default(),
367
property: Box::new(self.property.clone()),
368
})
369
}
370
371
fn apply(
372
&self,
373
curve_evaluator: &mut dyn AnimationCurveEvaluator,
374
t: f32,
375
weight: f32,
376
graph_node: AnimationNodeIndex,
377
) -> Result<(), AnimationEvaluationError> {
378
let curve_evaluator = curve_evaluator
379
.downcast_mut::<AnimatableCurveEvaluator<P::Property>>()
380
.unwrap();
381
let value = self.curve.sample_clamped(t);
382
curve_evaluator
383
.evaluator
384
.stack
385
.push(BasicAnimationCurveEvaluatorStackElement {
386
value,
387
weight,
388
graph_node,
389
});
390
Ok(())
391
}
392
}
393
394
impl<A: Animatable> AnimationCurveEvaluator for AnimatableCurveEvaluator<A> {
395
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
396
self.evaluator.combine(graph_node, /*additive=*/ false)
397
}
398
399
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
400
self.evaluator.combine(graph_node, /*additive=*/ true)
401
}
402
403
fn push_blend_register(
404
&mut self,
405
weight: f32,
406
graph_node: AnimationNodeIndex,
407
) -> Result<(), AnimationEvaluationError> {
408
self.evaluator.push_blend_register(weight, graph_node)
409
}
410
411
fn commit(&mut self, mut entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError> {
412
let property = self.property.get_mut(&mut entity)?;
413
*property = self
414
.evaluator
415
.stack
416
.pop()
417
.ok_or_else(inconsistent::<AnimatableCurveEvaluator<A>>)?
418
.value;
419
Ok(())
420
}
421
}
422
423
/// This type allows an [`IterableCurve`] valued in `f32` to be used as an [`AnimationCurve`]
424
/// that animates [morph weights].
425
///
426
/// [morph weights]: MorphWeights
427
#[derive(Debug, Clone, Reflect, FromReflect)]
428
#[reflect(from_reflect = false)]
429
pub struct WeightsCurve<C>(pub C);
430
431
#[derive(Reflect)]
432
struct WeightsCurveEvaluator {
433
/// The values of the stack, in which each element is a list of morph target
434
/// weights.
435
///
436
/// The stack elements are concatenated and tightly packed together.
437
///
438
/// The number of elements in this stack will always be a multiple of
439
/// [`Self::morph_target_count`].
440
stack_morph_target_weights: Vec<f32>,
441
442
/// The blend weights and graph node indices for each element of the stack.
443
///
444
/// This should have as many elements as there are stack nodes. In other
445
/// words, `Self::stack_morph_target_weights.len() *
446
/// Self::morph_target_counts as usize ==
447
/// Self::stack_blend_weights_and_graph_nodes`.
448
stack_blend_weights_and_graph_nodes: Vec<(f32, AnimationNodeIndex)>,
449
450
/// The morph target weights in the blend register, if any.
451
///
452
/// This field should be ignored if [`Self::blend_register_blend_weight`] is
453
/// `None`. If non-empty, it will always have [`Self::morph_target_count`]
454
/// elements in it.
455
blend_register_morph_target_weights: Vec<f32>,
456
457
/// The weight in the blend register.
458
///
459
/// This will be `None` if the blend register is empty. In that case,
460
/// [`Self::blend_register_morph_target_weights`] will be empty.
461
blend_register_blend_weight: Option<f32>,
462
463
/// The number of morph targets that are to be animated.
464
morph_target_count: Option<u32>,
465
}
466
467
impl<C> AnimationCurve for WeightsCurve<C>
468
where
469
C: IterableCurve<f32> + Debug + Clone + Reflectable,
470
{
471
fn clone_value(&self) -> Box<dyn AnimationCurve> {
472
Box::new(self.clone())
473
}
474
475
fn domain(&self) -> Interval {
476
self.0.domain()
477
}
478
479
fn evaluator_id(&self) -> EvaluatorId<'_> {
480
EvaluatorId::Type(TypeId::of::<WeightsCurveEvaluator>())
481
}
482
483
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator> {
484
Box::new(WeightsCurveEvaluator {
485
stack_morph_target_weights: vec![],
486
stack_blend_weights_and_graph_nodes: vec![],
487
blend_register_morph_target_weights: vec![],
488
blend_register_blend_weight: None,
489
morph_target_count: None,
490
})
491
}
492
493
fn apply(
494
&self,
495
curve_evaluator: &mut dyn AnimationCurveEvaluator,
496
t: f32,
497
weight: f32,
498
graph_node: AnimationNodeIndex,
499
) -> Result<(), AnimationEvaluationError> {
500
let curve_evaluator = curve_evaluator
501
.downcast_mut::<WeightsCurveEvaluator>()
502
.unwrap();
503
504
let prev_morph_target_weights_len = curve_evaluator.stack_morph_target_weights.len();
505
curve_evaluator
506
.stack_morph_target_weights
507
.extend(self.0.sample_iter_clamped(t));
508
curve_evaluator.morph_target_count = Some(
509
(curve_evaluator.stack_morph_target_weights.len() - prev_morph_target_weights_len)
510
as u32,
511
);
512
513
curve_evaluator
514
.stack_blend_weights_and_graph_nodes
515
.push((weight, graph_node));
516
Ok(())
517
}
518
}
519
520
impl WeightsCurveEvaluator {
521
fn combine(
522
&mut self,
523
graph_node: AnimationNodeIndex,
524
additive: bool,
525
) -> Result<(), AnimationEvaluationError> {
526
let Some(&(_, top_graph_node)) = self.stack_blend_weights_and_graph_nodes.last() else {
527
return Ok(());
528
};
529
if top_graph_node != graph_node {
530
return Ok(());
531
}
532
533
let (weight_to_blend, _) = self.stack_blend_weights_and_graph_nodes.pop().unwrap();
534
let stack_iter = self.stack_morph_target_weights.drain(
535
(self.stack_morph_target_weights.len() - self.morph_target_count.unwrap() as usize)..,
536
);
537
538
match self.blend_register_blend_weight {
539
None => {
540
self.blend_register_blend_weight = Some(weight_to_blend);
541
self.blend_register_morph_target_weights.clear();
542
543
// In the additive case, the values pushed onto the blend register need
544
// to be scaled by the weight.
545
if additive {
546
self.blend_register_morph_target_weights
547
.extend(stack_iter.map(|m| m * weight_to_blend));
548
} else {
549
self.blend_register_morph_target_weights.extend(stack_iter);
550
}
551
}
552
553
Some(ref mut current_weight) => {
554
*current_weight += weight_to_blend;
555
for (dest, src) in self
556
.blend_register_morph_target_weights
557
.iter_mut()
558
.zip(stack_iter)
559
{
560
if additive {
561
*dest += src * weight_to_blend;
562
} else {
563
*dest = f32::interpolate(dest, &src, weight_to_blend / *current_weight);
564
}
565
}
566
}
567
}
568
569
Ok(())
570
}
571
}
572
573
impl AnimationCurveEvaluator for WeightsCurveEvaluator {
574
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
575
self.combine(graph_node, /*additive=*/ false)
576
}
577
578
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
579
self.combine(graph_node, /*additive=*/ true)
580
}
581
582
fn push_blend_register(
583
&mut self,
584
weight: f32,
585
graph_node: AnimationNodeIndex,
586
) -> Result<(), AnimationEvaluationError> {
587
if self.blend_register_blend_weight.take().is_some() {
588
self.stack_morph_target_weights
589
.append(&mut self.blend_register_morph_target_weights);
590
self.stack_blend_weights_and_graph_nodes
591
.push((weight, graph_node));
592
}
593
Ok(())
594
}
595
596
fn commit(&mut self, mut entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError> {
597
if self.stack_morph_target_weights.is_empty() {
598
return Ok(());
599
}
600
601
// Compute the index of the first morph target in the last element of
602
// the stack.
603
let index_of_first_morph_target =
604
self.stack_morph_target_weights.len() - self.morph_target_count.unwrap() as usize;
605
606
for (dest, src) in entity
607
.get_mut::<MorphWeights>()
608
.ok_or_else(|| {
609
AnimationEvaluationError::ComponentNotPresent(TypeId::of::<MorphWeights>())
610
})?
611
.weights_mut()
612
.iter_mut()
613
.zip(self.stack_morph_target_weights[index_of_first_morph_target..].iter())
614
{
615
*dest = *src;
616
}
617
self.stack_morph_target_weights.clear();
618
self.stack_blend_weights_and_graph_nodes.clear();
619
Ok(())
620
}
621
}
622
623
#[derive(Reflect)]
624
struct BasicAnimationCurveEvaluator<A>
625
where
626
A: Animatable,
627
{
628
stack: Vec<BasicAnimationCurveEvaluatorStackElement<A>>,
629
blend_register: Option<(A, f32)>,
630
}
631
632
#[derive(Reflect)]
633
struct BasicAnimationCurveEvaluatorStackElement<A>
634
where
635
A: Animatable,
636
{
637
value: A,
638
weight: f32,
639
graph_node: AnimationNodeIndex,
640
}
641
642
impl<A> Default for BasicAnimationCurveEvaluator<A>
643
where
644
A: Animatable,
645
{
646
fn default() -> Self {
647
BasicAnimationCurveEvaluator {
648
stack: vec![],
649
blend_register: None,
650
}
651
}
652
}
653
654
impl<A> BasicAnimationCurveEvaluator<A>
655
where
656
A: Animatable,
657
{
658
fn combine(
659
&mut self,
660
graph_node: AnimationNodeIndex,
661
additive: bool,
662
) -> Result<(), AnimationEvaluationError> {
663
let Some(top) = self.stack.last() else {
664
return Ok(());
665
};
666
if top.graph_node != graph_node {
667
return Ok(());
668
}
669
670
let BasicAnimationCurveEvaluatorStackElement {
671
value: value_to_blend,
672
weight: weight_to_blend,
673
graph_node: _,
674
} = self.stack.pop().unwrap();
675
676
match self.blend_register.take() {
677
None => {
678
self.initialize_blend_register(value_to_blend, weight_to_blend, additive);
679
}
680
Some((mut current_value, mut current_weight)) => {
681
current_weight += weight_to_blend;
682
683
if additive {
684
current_value = A::blend(
685
[
686
BlendInput {
687
weight: 1.0,
688
value: current_value,
689
additive: true,
690
},
691
BlendInput {
692
weight: weight_to_blend,
693
value: value_to_blend,
694
additive: true,
695
},
696
]
697
.into_iter(),
698
);
699
} else {
700
current_value = A::interpolate(
701
&current_value,
702
&value_to_blend,
703
weight_to_blend / current_weight,
704
);
705
}
706
707
self.blend_register = Some((current_value, current_weight));
708
}
709
}
710
711
Ok(())
712
}
713
714
fn initialize_blend_register(&mut self, value: A, weight: f32, additive: bool) {
715
if additive {
716
let scaled_value = A::blend(
717
[BlendInput {
718
weight,
719
value,
720
additive: true,
721
}]
722
.into_iter(),
723
);
724
self.blend_register = Some((scaled_value, weight));
725
} else {
726
self.blend_register = Some((value, weight));
727
}
728
}
729
730
fn push_blend_register(
731
&mut self,
732
weight: f32,
733
graph_node: AnimationNodeIndex,
734
) -> Result<(), AnimationEvaluationError> {
735
if let Some((value, _)) = self.blend_register.take() {
736
self.stack.push(BasicAnimationCurveEvaluatorStackElement {
737
value,
738
weight,
739
graph_node,
740
});
741
}
742
Ok(())
743
}
744
}
745
746
/// A low-level trait that provides control over how curves are actually applied
747
/// to entities by the animation system.
748
///
749
/// Typically, this will not need to be implemented manually, since it is
750
/// automatically implemented by [`AnimatableCurve`] and other curves used by
751
/// the animation system (e.g. those that animate parts of transforms or morph
752
/// weights). However, this can be implemented manually when `AnimatableCurve`
753
/// is not sufficiently expressive.
754
///
755
/// In many respects, this behaves like a type-erased form of [`Curve`], where
756
/// the output type of the curve is remembered only in the components that are
757
/// mutated in the implementation of [`apply`].
758
///
759
/// [`apply`]: AnimationCurve::apply
760
pub trait AnimationCurve: Debug + Send + Sync + 'static {
761
/// Returns a boxed clone of this value.
762
fn clone_value(&self) -> Box<dyn AnimationCurve>;
763
764
/// The range of times for which this animation is defined.
765
fn domain(&self) -> Interval;
766
767
/// Returns the type ID of the [`AnimationCurveEvaluator`].
768
///
769
/// This must match the type returned by [`Self::create_evaluator`]. It must
770
/// be a single type that doesn't depend on the type of the curve.
771
fn evaluator_id(&self) -> EvaluatorId<'_>;
772
773
/// Returns a newly-instantiated [`AnimationCurveEvaluator`] for use with
774
/// this curve.
775
///
776
/// All curve types must return the same type of
777
/// [`AnimationCurveEvaluator`]. The returned value must match the type
778
/// returned by [`Self::evaluator_id`].
779
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator>;
780
781
/// Samples the curve at the given time `t`, and pushes the sampled value
782
/// onto the evaluation stack of the `curve_evaluator`.
783
///
784
/// The `curve_evaluator` parameter points to the value returned by
785
/// [`Self::create_evaluator`], upcast to an `&mut dyn
786
/// AnimationCurveEvaluator`. Typically, implementations of [`Self::apply`]
787
/// will want to downcast the `curve_evaluator` parameter to the concrete
788
/// type [`Self::evaluator_id`] in order to push values of the appropriate
789
/// type onto its evaluation stack.
790
///
791
/// Be sure not to confuse the `t` and `weight` values. The former
792
/// determines the position at which the *curve* is sampled, while `weight`
793
/// ultimately determines how much the *stack values* will be blended
794
/// together (see the definition of [`AnimationCurveEvaluator::blend`]).
795
fn apply(
796
&self,
797
curve_evaluator: &mut dyn AnimationCurveEvaluator,
798
t: f32,
799
weight: f32,
800
graph_node: AnimationNodeIndex,
801
) -> Result<(), AnimationEvaluationError>;
802
}
803
804
/// The [`EvaluatorId`] is used to look up the [`AnimationCurveEvaluator`] for an [`AnimatableProperty`].
805
/// For a given animated property, this ID should always be the same to allow things like animation blending to occur.
806
#[derive(Clone)]
807
pub enum EvaluatorId<'a> {
808
/// Corresponds to a specific field on a specific component type.
809
/// The `TypeId` should correspond to the component type, and the `usize`
810
/// should correspond to the Reflect-ed field index of the field.
811
//
812
// IMPLEMENTATION NOTE: The Hashed<(TypeId, usize) is intentionally cheap to clone, as it will be cloned per frame by the evaluator
813
// Switching the field index `usize` for something like a field name `String` would probably be too expensive to justify
814
ComponentField(&'a Hashed<(TypeId, usize)>),
815
/// Corresponds to a custom property of a given type. This should be the [`TypeId`]
816
/// of the custom [`AnimatableProperty`].
817
Type(TypeId),
818
}
819
820
/// A low-level trait for use in [`VariableCurve`](`crate::VariableCurve`) that provides fine
821
/// control over how animations are evaluated.
822
///
823
/// You can implement this trait when the generic [`AnimatableCurveEvaluator`]
824
/// isn't sufficiently-expressive for your needs. For example, [`MorphWeights`]
825
/// implements this trait instead of using [`AnimatableCurveEvaluator`] because
826
/// it needs to animate arbitrarily many weights at once, which can't be done
827
/// with [`Animatable`] as that works on fixed-size values only.
828
///
829
/// If you implement this trait, you should also implement [`AnimationCurve`] on
830
/// your curve type, as that trait allows creating instances of this one.
831
///
832
/// Implementations of [`AnimatableCurveEvaluator`] should maintain a *stack* of
833
/// (value, weight, node index) triples, as well as a *blend register*, which is
834
/// either a (value, weight) pair or empty. *Value* here refers to an instance
835
/// of the value being animated: for example, [`Vec3`] in the case of
836
/// translation keyframes. The stack stores intermediate values generated while
837
/// evaluating the [`AnimationGraph`](`crate::graph::AnimationGraph`), while the blend register
838
/// stores the result of a blend operation.
839
///
840
/// [`Vec3`]: bevy_math::Vec3
841
pub trait AnimationCurveEvaluator: Downcast + Send + Sync + 'static {
842
/// Blends the top element of the stack with the blend register.
843
///
844
/// The semantics of this method are as follows:
845
///
846
/// 1. Pop the top element of the stack. Call its value vₘ and its weight
847
/// wₘ. If the stack was empty, return success.
848
///
849
/// 2. If the blend register is empty, set the blend register value to vₘ
850
/// and the blend register weight to wₘ; then, return success.
851
///
852
/// 3. If the blend register is nonempty, call its current value vₙ and its
853
/// current weight wₙ. Then, set the value of the blend register to
854
/// `interpolate(vₙ, vₘ, wₘ / (wₘ + wₙ))`, and set the weight of the blend
855
/// register to wₘ + wₙ.
856
///
857
/// 4. Return success.
858
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError>;
859
860
/// Additively blends the top element of the stack with the blend register.
861
///
862
/// The semantics of this method are as follows:
863
///
864
/// 1. Pop the top element of the stack. Call its value vₘ and its weight
865
/// wₘ. If the stack was empty, return success.
866
///
867
/// 2. If the blend register is empty, set the blend register value to vₘ
868
/// and the blend register weight to wₘ; then, return success.
869
///
870
/// 3. If the blend register is nonempty, call its current value vₙ.
871
/// Then, set the value of the blend register to vₙ + vₘwₘ.
872
///
873
/// 4. Return success.
874
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError>;
875
876
/// Pushes the current value of the blend register onto the stack.
877
///
878
/// If the blend register is empty, this method does nothing successfully.
879
/// Otherwise, this method pushes the current value of the blend register
880
/// onto the stack, alongside the weight and graph node supplied to this
881
/// function. The weight present in the blend register is discarded; only
882
/// the weight parameter to this function is pushed onto the stack. The
883
/// blend register is emptied after this process.
884
fn push_blend_register(
885
&mut self,
886
weight: f32,
887
graph_node: AnimationNodeIndex,
888
) -> Result<(), AnimationEvaluationError>;
889
890
/// Pops the top value off the stack and writes it into the appropriate
891
/// component.
892
///
893
/// If the stack is empty, this method does nothing successfully. Otherwise,
894
/// it pops the top value off the stack, fetches the associated component
895
/// from either the `transform` or `entity` values as appropriate, and
896
/// updates the appropriate property with the value popped from the stack.
897
/// The weight and node index associated with the popped stack element are
898
/// discarded. After doing this, the stack is emptied.
899
///
900
/// The property on the component must be overwritten with the value from
901
/// the stack, not blended with it.
902
fn commit(&mut self, entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError>;
903
}
904
905
impl_downcast!(AnimationCurveEvaluator);
906
907
/// A [curve] defined by keyframes with values in an [animatable] type.
908
///
909
/// The keyframes are interpolated using the type's [`Animatable::interpolate`] implementation.
910
///
911
/// [curve]: Curve
912
/// [animatable]: Animatable
913
#[derive(Debug, Clone, Reflect)]
914
pub struct AnimatableKeyframeCurve<T> {
915
core: UnevenCore<T>,
916
}
917
918
impl<T> Curve<T> for AnimatableKeyframeCurve<T>
919
where
920
T: Animatable + Clone,
921
{
922
#[inline]
923
fn domain(&self) -> Interval {
924
self.core.domain()
925
}
926
927
#[inline]
928
fn sample_clamped(&self, t: f32) -> T {
929
// `UnevenCore::sample_with` is implicitly clamped.
930
self.core.sample_with(t, <T as Animatable>::interpolate)
931
}
932
933
#[inline]
934
fn sample_unchecked(&self, t: f32) -> T {
935
self.sample_clamped(t)
936
}
937
}
938
939
impl<T> AnimatableKeyframeCurve<T>
940
where
941
T: Animatable,
942
{
943
/// Create a new [`AnimatableKeyframeCurve`] from the given `keyframes`. The values of this
944
/// curve are interpolated from the keyframes using the output type's implementation of
945
/// [`Animatable::interpolate`].
946
///
947
/// There must be at least two samples in order for this method to succeed.
948
pub fn new(keyframes: impl IntoIterator<Item = (f32, T)>) -> Result<Self, UnevenCoreError> {
949
Ok(Self {
950
core: UnevenCore::new(keyframes)?,
951
})
952
}
953
}
954
955
fn inconsistent<P>() -> AnimationEvaluationError
956
where
957
P: 'static + ?Sized,
958
{
959
AnimationEvaluationError::InconsistentEvaluatorImplementation(TypeId::of::<P>())
960
}
961
962
/// Returns an [`AnimatedField`] with a given `$component` and `$field`.
963
///
964
/// This can be used in the following way:
965
///
966
/// ```
967
/// # use bevy_animation::{animation_curves::AnimatedField, animated_field};
968
/// # use bevy_color::Srgba;
969
/// # use bevy_ecs::component::Component;
970
/// # use bevy_math::Vec3;
971
/// # use bevy_reflect::Reflect;
972
/// #[derive(Component, Reflect)]
973
/// struct Transform {
974
/// translation: Vec3,
975
/// }
976
///
977
/// let field = animated_field!(Transform::translation);
978
///
979
/// #[derive(Component, Reflect)]
980
/// struct Color(Srgba);
981
///
982
/// let tuple_field = animated_field!(Color::0);
983
/// ```
984
#[macro_export]
985
macro_rules! animated_field {
986
($component:ident::$field:tt) => {
987
AnimatedField::new_unchecked(stringify!($field), |component: &mut $component| {
988
&mut component.$field
989
})
990
};
991
}
992
993
#[cfg(test)]
994
mod tests {
995
use super::*;
996
997
#[test]
998
fn test_animated_field_tuple_struct_simple_uses() {
999
#[derive(Clone, Debug, Component, Reflect)]
1000
struct A(f32);
1001
let _ = AnimatedField::new_unchecked("0", |a: &mut A| &mut a.0);
1002
1003
#[derive(Clone, Debug, Component, Reflect)]
1004
struct B(f32, f64, f32);
1005
let _ = AnimatedField::new_unchecked("0", |b: &mut B| &mut b.0);
1006
let _ = AnimatedField::new_unchecked("1", |b: &mut B| &mut b.1);
1007
let _ = AnimatedField::new_unchecked("2", |b: &mut B| &mut b.2);
1008
}
1009
}
1010
1011