Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_animation/src/morph.rs
7219 views
1
use crate::{
2
animatable::Animatable,
3
animation_curves::{AnimationCurve, AnimationCurveEvaluator, EvaluatorId},
4
graph::AnimationNodeIndex,
5
AnimationEntityMut, AnimationEvaluationError,
6
};
7
use bevy_math::curve::{iterable::IterableCurve, Interval};
8
use bevy_mesh::morph::MorphWeights;
9
use bevy_reflect::{FromReflect, Reflect, Reflectable};
10
use core::{any::TypeId, fmt::Debug};
11
12
/// This type allows an [`IterableCurve`] valued in `f32` to be used as an [`AnimationCurve`]
13
/// that animates [morph weights].
14
///
15
/// [morph weights]: MorphWeights
16
#[derive(Debug, Clone, Reflect, FromReflect)]
17
#[reflect(from_reflect = false)]
18
pub struct WeightsCurve<C>(pub C);
19
20
#[derive(Reflect)]
21
struct WeightsCurveEvaluator {
22
/// The values of the stack, in which each element is a list of morph target
23
/// weights.
24
///
25
/// The stack elements are concatenated and tightly packed together.
26
///
27
/// The number of elements in this stack will always be a multiple of
28
/// [`Self::morph_target_count`].
29
stack_morph_target_weights: Vec<f32>,
30
31
/// The blend weights and graph node indices for each element of the stack.
32
///
33
/// This should have as many elements as there are stack nodes. In other
34
/// words, `Self::stack_morph_target_weights.len() *
35
/// Self::morph_target_counts as usize ==
36
/// Self::stack_blend_weights_and_graph_nodes`.
37
stack_blend_weights_and_graph_nodes: Vec<(f32, AnimationNodeIndex)>,
38
39
/// The morph target weights in the blend register, if any.
40
///
41
/// This field should be ignored if [`Self::blend_register_blend_weight`] is
42
/// `None`. If non-empty, it will always have [`Self::morph_target_count`]
43
/// elements in it.
44
blend_register_morph_target_weights: Vec<f32>,
45
46
/// The weight in the blend register.
47
///
48
/// This will be `None` if the blend register is empty. In that case,
49
/// [`Self::blend_register_morph_target_weights`] will be empty.
50
blend_register_blend_weight: Option<f32>,
51
52
/// The number of morph targets that are to be animated.
53
morph_target_count: Option<u32>,
54
}
55
56
impl<C> AnimationCurve for WeightsCurve<C>
57
where
58
C: IterableCurve<f32> + Debug + Clone + Reflectable,
59
{
60
fn clone_value(&self) -> Box<dyn AnimationCurve> {
61
Box::new(self.clone())
62
}
63
64
fn domain(&self) -> Interval {
65
self.0.domain()
66
}
67
68
fn evaluator_id(&self) -> EvaluatorId<'_> {
69
EvaluatorId::Type(TypeId::of::<WeightsCurveEvaluator>())
70
}
71
72
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator> {
73
Box::new(WeightsCurveEvaluator {
74
stack_morph_target_weights: vec![],
75
stack_blend_weights_and_graph_nodes: vec![],
76
blend_register_morph_target_weights: vec![],
77
blend_register_blend_weight: None,
78
morph_target_count: None,
79
})
80
}
81
82
fn apply(
83
&self,
84
curve_evaluator: &mut dyn AnimationCurveEvaluator,
85
t: f32,
86
weight: f32,
87
graph_node: AnimationNodeIndex,
88
) -> Result<(), AnimationEvaluationError> {
89
let curve_evaluator = curve_evaluator
90
.downcast_mut::<WeightsCurveEvaluator>()
91
.unwrap();
92
93
let prev_morph_target_weights_len = curve_evaluator.stack_morph_target_weights.len();
94
curve_evaluator
95
.stack_morph_target_weights
96
.extend(self.0.sample_iter_clamped(t));
97
curve_evaluator.morph_target_count = Some(
98
(curve_evaluator.stack_morph_target_weights.len() - prev_morph_target_weights_len)
99
as u32,
100
);
101
102
curve_evaluator
103
.stack_blend_weights_and_graph_nodes
104
.push((weight, graph_node));
105
Ok(())
106
}
107
}
108
109
impl WeightsCurveEvaluator {
110
fn combine(
111
&mut self,
112
graph_node: AnimationNodeIndex,
113
additive: bool,
114
) -> Result<(), AnimationEvaluationError> {
115
let Some(&(_, top_graph_node)) = self.stack_blend_weights_and_graph_nodes.last() else {
116
return Ok(());
117
};
118
if top_graph_node != graph_node {
119
return Ok(());
120
}
121
122
let (weight_to_blend, _) = self.stack_blend_weights_and_graph_nodes.pop().unwrap();
123
let stack_iter = self.stack_morph_target_weights.drain(
124
(self.stack_morph_target_weights.len() - self.morph_target_count.unwrap() as usize)..,
125
);
126
127
match self.blend_register_blend_weight {
128
None => {
129
self.blend_register_blend_weight = Some(weight_to_blend);
130
self.blend_register_morph_target_weights.clear();
131
132
// In the additive case, the values pushed onto the blend register need
133
// to be scaled by the weight.
134
if additive {
135
self.blend_register_morph_target_weights
136
.extend(stack_iter.map(|m| m * weight_to_blend));
137
} else {
138
self.blend_register_morph_target_weights.extend(stack_iter);
139
}
140
}
141
142
Some(ref mut current_weight) => {
143
*current_weight += weight_to_blend;
144
for (dest, src) in self
145
.blend_register_morph_target_weights
146
.iter_mut()
147
.zip(stack_iter)
148
{
149
if additive {
150
*dest += src * weight_to_blend;
151
} else {
152
*dest = f32::interpolate(dest, &src, weight_to_blend / *current_weight);
153
}
154
}
155
}
156
}
157
158
Ok(())
159
}
160
}
161
162
impl AnimationCurveEvaluator for WeightsCurveEvaluator {
163
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
164
self.combine(graph_node, /*additive=*/ false)
165
}
166
167
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
168
self.combine(graph_node, /*additive=*/ true)
169
}
170
171
fn push_blend_register(
172
&mut self,
173
weight: f32,
174
graph_node: AnimationNodeIndex,
175
) -> Result<(), AnimationEvaluationError> {
176
if self.blend_register_blend_weight.take().is_some() {
177
self.stack_morph_target_weights
178
.append(&mut self.blend_register_morph_target_weights);
179
self.stack_blend_weights_and_graph_nodes
180
.push((weight, graph_node));
181
}
182
Ok(())
183
}
184
185
fn commit(&mut self, mut entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError> {
186
if self.stack_morph_target_weights.is_empty() {
187
return Ok(());
188
}
189
190
// Compute the index of the first morph target in the last element of
191
// the stack.
192
let index_of_first_morph_target =
193
self.stack_morph_target_weights.len() - self.morph_target_count.unwrap() as usize;
194
195
for (dest, src) in entity
196
.get_mut::<MorphWeights>()
197
.ok_or_else(|| {
198
AnimationEvaluationError::ComponentNotPresent(TypeId::of::<MorphWeights>())
199
})?
200
.weights_mut()
201
.iter_mut()
202
.zip(self.stack_morph_target_weights[index_of_first_morph_target..].iter())
203
{
204
*dest = *src;
205
}
206
self.stack_morph_target_weights.clear();
207
self.stack_blend_weights_and_graph_nodes.clear();
208
Ok(())
209
}
210
}
211
212