Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_animation/src/graph.rs
9353 views
1
//! The animation graph, which allows animations to be blended together.
2
3
use core::{
4
fmt::Write,
5
iter,
6
ops::{Index, IndexMut, Range},
7
};
8
use std::io;
9
10
use bevy_asset::{
11
io::Reader, Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets, Handle, LoadContext,
12
};
13
use bevy_derive::{Deref, DerefMut};
14
use bevy_ecs::{
15
component::Component,
16
message::MessageReader,
17
reflect::ReflectComponent,
18
resource::Resource,
19
system::{Res, ResMut},
20
};
21
use bevy_platform::collections::HashMap;
22
use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
23
use derive_more::derive::From;
24
use petgraph::{
25
graph::{DiGraph, NodeIndex},
26
Direction,
27
};
28
use ron::de::SpannedError;
29
use serde::{Deserialize, Serialize};
30
use smallvec::SmallVec;
31
use thiserror::Error;
32
33
use crate::{AnimationClip, AnimationTargetId};
34
35
/// A graph structure that describes how animation clips are to be blended
36
/// together.
37
///
38
/// Applications frequently want to be able to play multiple animations at once
39
/// and to fine-tune the influence that animations have on a skinned mesh. Bevy
40
/// uses an *animation graph* to store this information. Animation graphs are a
41
/// directed acyclic graph (DAG) that describes how animations are to be
42
/// weighted and combined together. Every frame, Bevy evaluates the graph from
43
/// the root and blends the animations together in a bottom-up fashion to
44
/// produce the final pose.
45
///
46
/// There are three types of nodes: *blend nodes*, *add nodes*, and *clip
47
/// nodes*, all of which can have an associated weight. Blend nodes and add
48
/// nodes have no associated animation clip and combine the animations of their
49
/// children according to those children's weights. Clip nodes specify an
50
/// animation clip to play. When a graph is created, it starts with only a
51
/// single blend node, the root node.
52
///
53
/// For example, consider the following graph:
54
///
55
/// ```text
56
/// ┌────────────┐
57
/// │ │
58
/// │ Idle ├─────────────────────┐
59
/// │ │ │
60
/// └────────────┘ │
61
/// │
62
/// ┌────────────┐ │ ┌────────────┐
63
/// │ │ │ │ │
64
/// │ Run ├──┐ ├──┤ Root │
65
/// │ │ │ ┌────────────┐ │ │ │
66
/// └────────────┘ │ │ Blend │ │ └────────────┘
67
/// ├──┤ ├──┘
68
/// ┌────────────┐ │ │ 0.5 │
69
/// │ │ │ └────────────┘
70
/// │ Walk ├──┘
71
/// │ │
72
/// └────────────┘
73
/// ```
74
///
75
/// In this case, assuming that Idle, Run, and Walk are all playing with weight
76
/// 1.0, the Run and Walk animations will be equally blended together, then
77
/// their weights will be halved and finally blended with the Idle animation.
78
/// Thus the weight of Run and Walk are effectively half of the weight of Idle.
79
///
80
/// Nodes can optionally have a *mask*, a bitfield that restricts the set of
81
/// animation targets that the node and its descendants affect. Each bit in the
82
/// mask corresponds to a *mask group*, which is a set of animation targets
83
/// (bones). An animation target can belong to any number of mask groups within
84
/// the context of an animation graph.
85
///
86
/// When the appropriate bit is set in a node's mask, neither the node nor its
87
/// descendants will animate any animation targets belonging to that mask group.
88
/// That is, setting a mask bit to 1 *disables* the animation targets in that
89
/// group. If an animation target belongs to multiple mask groups, masking any
90
/// one of the mask groups that it belongs to will mask that animation target.
91
/// (Thus an animation target will only be animated if *all* of its mask groups
92
/// are unmasked.)
93
///
94
/// A common use of masks is to allow characters to hold objects. For this, the
95
/// typical workflow is to assign each character's hand to a mask group. Then,
96
/// when the character picks up an object, the application masks out the hand
97
/// that the object is held in for the character's animation set, then positions
98
/// the hand's digits as necessary to grasp the object. The character's
99
/// animations will continue to play but will not affect the hand, which will
100
/// continue to be depicted as holding the object.
101
///
102
/// Animation graphs are assets and can be serialized to and loaded from [RON]
103
/// files. Canonically, such files have an `.animgraph.ron` extension.
104
///
105
/// The animation graph implements [RFC 51]. See that document for more
106
/// information.
107
///
108
/// [RON]: https://github.com/ron-rs/ron
109
///
110
/// [RFC 51]: https://github.com/bevyengine/rfcs/blob/main/rfcs/51-animation-composition.md
111
#[derive(Asset, Reflect, Clone, Debug)]
112
#[reflect(Debug, Clone)]
113
pub struct AnimationGraph {
114
/// The `petgraph` data structure that defines the animation graph.
115
pub graph: AnimationDiGraph,
116
117
/// The index of the root node in the animation graph.
118
pub root: NodeIndex,
119
120
/// The mask groups that each animation target (bone) belongs to.
121
///
122
/// Each value in this map is a bitfield, in which 0 in bit position N
123
/// indicates that the animation target doesn't belong to mask group N, and
124
/// a 1 in position N indicates that the animation target does belong to
125
/// mask group N.
126
///
127
/// Animation targets not in this collection are treated as though they
128
/// don't belong to any mask groups.
129
pub mask_groups: HashMap<AnimationTargetId, AnimationMask>,
130
}
131
132
/// A [`Handle`] to the [`AnimationGraph`] to be used by the [`AnimationPlayer`](crate::AnimationPlayer) on the same entity.
133
#[derive(Component, Clone, Debug, Default, Deref, DerefMut, Reflect, PartialEq, Eq, From)]
134
#[reflect(Component, Default, Clone)]
135
pub struct AnimationGraphHandle(pub Handle<AnimationGraph>);
136
137
impl From<AnimationGraphHandle> for AssetId<AnimationGraph> {
138
fn from(handle: AnimationGraphHandle) -> Self {
139
handle.id()
140
}
141
}
142
143
impl From<&AnimationGraphHandle> for AssetId<AnimationGraph> {
144
fn from(handle: &AnimationGraphHandle) -> Self {
145
handle.id()
146
}
147
}
148
149
/// A type alias for the `petgraph` data structure that defines the animation
150
/// graph.
151
pub type AnimationDiGraph = DiGraph<AnimationGraphNode, (), u32>;
152
153
/// The index of either an animation or blend node in the animation graph.
154
///
155
/// These indices are the way that [animation players] identify each animation.
156
///
157
/// [animation players]: crate::AnimationPlayer
158
pub type AnimationNodeIndex = NodeIndex<u32>;
159
160
/// An individual node within an animation graph.
161
///
162
/// The [`AnimationGraphNode::node_type`] field specifies the type of node: one
163
/// of a *clip node*, a *blend node*, or an *add node*. Clip nodes, the leaves
164
/// of the graph, contain animation clips to play. Blend and add nodes describe
165
/// how to combine their children to produce a final animation.
166
#[derive(Clone, Reflect, Debug)]
167
#[reflect(Clone)]
168
pub struct AnimationGraphNode {
169
/// Animation node data specific to the type of node (clip, blend, or add).
170
///
171
/// In the case of clip nodes, this contains the actual animation clip
172
/// associated with the node.
173
pub node_type: AnimationNodeType,
174
175
/// A bitfield specifying the mask groups that this node and its descendants
176
/// will not affect.
177
///
178
/// A 0 in bit N indicates that this node and its descendants *can* animate
179
/// animation targets in mask group N, while a 1 in bit N indicates that
180
/// this node and its descendants *cannot* animate mask group N.
181
pub mask: AnimationMask,
182
183
/// The weight of this node, which signifies its contribution in blending.
184
///
185
/// Note that this does not propagate down the graph hierarchy; rather,
186
/// each [Blend] and [Add] node uses the weights of its children to determine
187
/// the total animation that is accumulated at that node. The parent node's
188
/// weight is used only to determine the contribution of that total animation
189
/// in *further* blending.
190
///
191
/// In other words, it is as if the blend node is replaced by a single clip
192
/// node consisting of the blended animation with the weight specified at the
193
/// blend node.
194
///
195
/// For animation clips, this weight is also multiplied by the [active animation weight]
196
/// before being applied.
197
///
198
/// [Blend]: AnimationNodeType::Blend
199
/// [Add]: AnimationNodeType::Add
200
/// [active animation weight]: crate::ActiveAnimation::weight
201
pub weight: f32,
202
}
203
204
/// Animation node data specific to the type of node (clip, blend, or add).
205
///
206
/// In the case of clip nodes, this contains the actual animation clip
207
/// associated with the node.
208
#[derive(Clone, Default, Reflect, Debug)]
209
#[reflect(Clone)]
210
pub enum AnimationNodeType {
211
/// A *clip node*, which plays an animation clip.
212
///
213
/// These are always the leaves of the graph.
214
Clip(Handle<AnimationClip>),
215
216
/// A *blend node*, which blends its children according to their weights.
217
///
218
/// The weights of all the children of this node are normalized to 1.0.
219
#[default]
220
Blend,
221
222
/// An *additive blend node*, which combines the animations of its children
223
/// additively.
224
///
225
/// The weights of all the children of this node are *not* normalized to
226
/// 1.0. Rather, each child is multiplied by its respective weight and
227
/// added in sequence.
228
///
229
/// Add nodes are primarily useful for superimposing an animation for a
230
/// portion of a rig on top of the main animation. For example, an add node
231
/// could superimpose a weapon attack animation for a character's limb on
232
/// top of a running animation to produce an animation of a character
233
/// attacking while running.
234
Add,
235
}
236
237
/// An [`AssetLoader`] that can load [`AnimationGraph`]s as assets.
238
///
239
/// The canonical extension for [`AnimationGraph`]s is `.animgraph.ron`. Plain
240
/// `.animgraph` is supported as well.
241
#[derive(Default, TypePath)]
242
pub struct AnimationGraphAssetLoader;
243
244
/// Errors that can occur when serializing animation graphs to RON.
245
#[derive(Error, Debug)]
246
pub enum AnimationGraphSaveError {
247
/// An I/O error occurred.
248
#[error(transparent)]
249
Io(#[from] io::Error),
250
/// An error occurred in RON serialization.
251
#[error(transparent)]
252
Ron(#[from] ron::Error),
253
/// An error occurred converting the graph to its serialization form.
254
#[error(transparent)]
255
ConvertToSerialized(#[from] NonPathHandleError),
256
}
257
258
/// Errors that can occur when deserializing animation graphs from RON.
259
#[derive(Error, Debug)]
260
pub enum AnimationGraphLoadError {
261
/// An I/O error occurred.
262
#[error(transparent)]
263
Io(#[from] io::Error),
264
/// An error occurred in RON deserialization.
265
#[error(transparent)]
266
Ron(#[from] ron::Error),
267
/// An error occurred in RON deserialization, and the location of the error
268
/// is supplied.
269
#[error(transparent)]
270
SpannedRon(#[from] SpannedError),
271
/// The deserialized graph contained legacy data that we no longer support.
272
#[error(
273
"The deserialized AnimationGraph contained an AnimationClip referenced by an AssetId, \
274
which is no longer supported. Consider manually deserializing the SerializedAnimationGraph \
275
type and determine how to migrate any SerializedAnimationClip::AssetId animation clips"
276
)]
277
GraphContainsLegacyAssetId,
278
}
279
280
/// Acceleration structures for animation graphs that allows Bevy to evaluate
281
/// them quickly.
282
///
283
/// These are kept up to date as [`AnimationGraph`] instances are added,
284
/// modified, and removed.
285
#[derive(Default, Reflect, Resource)]
286
pub struct ThreadedAnimationGraphs(
287
pub(crate) HashMap<AssetId<AnimationGraph>, ThreadedAnimationGraph>,
288
);
289
290
/// An acceleration structure for an animation graph that allows Bevy to
291
/// evaluate it quickly.
292
///
293
/// This is kept up to date as the associated [`AnimationGraph`] instance is
294
/// added, modified, or removed.
295
#[derive(Default, Reflect)]
296
pub struct ThreadedAnimationGraph {
297
/// A cached postorder traversal of the graph.
298
///
299
/// The node indices here are stored in postorder. Siblings are stored in
300
/// descending order. This is because the
301
/// [`AnimationCurveEvaluator`](`crate::animation_curves::AnimationCurveEvaluator`) uses a stack for
302
/// evaluation. Consider this graph:
303
///
304
/// ```text
305
/// ┌─────┐
306
/// │ │
307
/// │ 1 │
308
/// │ │
309
/// └──┬──┘
310
/// │
311
/// ┌───────┼───────┐
312
/// │ │ │
313
/// ▼ ▼ ▼
314
/// ┌─────┐ ┌─────┐ ┌─────┐
315
/// │ │ │ │ │ │
316
/// │ 2 │ │ 3 │ │ 4 │
317
/// │ │ │ │ │ │
318
/// └──┬──┘ └─────┘ └─────┘
319
/// │
320
/// ┌───┴───┐
321
/// │ │
322
/// ▼ ▼
323
/// ┌─────┐ ┌─────┐
324
/// │ │ │ │
325
/// │ 5 │ │ 6 │
326
/// │ │ │ │
327
/// └─────┘ └─────┘
328
/// ```
329
///
330
/// The postorder traversal in this case will be (4, 3, 6, 5, 2, 1).
331
///
332
/// The fact that the children of each node are sorted in reverse ensures
333
/// that, at each level, the order of blending proceeds in ascending order
334
/// by node index, as we guarantee. To illustrate this, consider the way
335
/// the graph above is evaluated. (Interpolation is represented with the ⊕
336
/// symbol.)
337
///
338
/// | Step | Node | Operation | Stack (after operation) | Blend Register |
339
/// | ---- | ---- | ---------- | ----------------------- | -------------- |
340
/// | 1 | 4 | Push | 4 | |
341
/// | 2 | 3 | Push | 4 3 | |
342
/// | 3 | 6 | Push | 4 3 6 | |
343
/// | 4 | 5 | Push | 4 3 6 5 | |
344
/// | 5 | 2 | Blend 5 | 4 3 6 | 5 |
345
/// | 6 | 2 | Blend 6 | 4 3 | 5 ⊕ 6 |
346
/// | 7 | 2 | Push Blend | 4 3 2 | |
347
/// | 8 | 1 | Blend 2 | 4 3 | 2 |
348
/// | 9 | 1 | Blend 3 | 4 | 2 ⊕ 3 |
349
/// | 10 | 1 | Blend 4 | | 2 ⊕ 3 ⊕ 4 |
350
/// | 11 | 1 | Push Blend | 1 | |
351
/// | 12 | | Commit | | |
352
pub threaded_graph: Vec<AnimationNodeIndex>,
353
354
/// A mapping from each parent node index to the range within
355
/// [`Self::sorted_edges`].
356
///
357
/// This allows for quick lookup of the children of each node, sorted in
358
/// ascending order of node index, without having to sort the result of the
359
/// `petgraph` traversal functions every frame.
360
pub sorted_edge_ranges: Vec<Range<u32>>,
361
362
/// A list of the children of each node, sorted in ascending order.
363
pub sorted_edges: Vec<AnimationNodeIndex>,
364
365
/// A mapping from node index to a bitfield specifying the mask groups that
366
/// this node masks *out* (i.e. doesn't animate).
367
///
368
/// A 1 in bit position N indicates that this node doesn't animate any
369
/// targets of mask group N.
370
pub computed_masks: Vec<u64>,
371
}
372
373
/// A version of [`AnimationGraph`] suitable for serializing as an asset.
374
///
375
/// Animation nodes can refer to external animation clips, and the [`AssetId`]
376
/// is typically not sufficient to identify the clips, since the
377
/// [`bevy_asset::AssetServer`] assigns IDs in unpredictable ways. That fact
378
/// motivates this type, which replaces the `Handle<AnimationClip>` with an
379
/// asset path. Loading an animation graph via the [`bevy_asset::AssetServer`]
380
/// actually loads a serialized instance of this type, as does serializing an
381
/// [`AnimationGraph`] through `serde`.
382
#[derive(Serialize, Deserialize)]
383
pub struct SerializedAnimationGraph {
384
/// Corresponds to the `graph` field on [`AnimationGraph`].
385
pub graph: DiGraph<SerializedAnimationGraphNode, (), u32>,
386
/// Corresponds to the `root` field on [`AnimationGraph`].
387
pub root: NodeIndex,
388
/// Corresponds to the `mask_groups` field on [`AnimationGraph`].
389
pub mask_groups: HashMap<AnimationTargetId, AnimationMask>,
390
}
391
392
/// A version of [`AnimationGraphNode`] suitable for serializing as an asset.
393
///
394
/// See the comments in [`SerializedAnimationGraph`] for more information.
395
#[derive(Serialize, Deserialize)]
396
pub struct SerializedAnimationGraphNode {
397
/// Corresponds to the `node_type` field on [`AnimationGraphNode`].
398
pub node_type: SerializedAnimationNodeType,
399
/// Corresponds to the `mask` field on [`AnimationGraphNode`].
400
pub mask: AnimationMask,
401
/// Corresponds to the `weight` field on [`AnimationGraphNode`].
402
pub weight: f32,
403
}
404
405
/// A version of [`AnimationNodeType`] suitable for serializing as part of a
406
/// [`SerializedAnimationGraphNode`] asset.
407
#[derive(Serialize, Deserialize)]
408
pub enum SerializedAnimationNodeType {
409
/// Corresponds to [`AnimationNodeType::Clip`].
410
Clip(AssetPath<'static>),
411
/// Corresponds to [`AnimationNodeType::Blend`].
412
Blend,
413
/// Corresponds to [`AnimationNodeType::Add`].
414
Add,
415
}
416
417
/// The type of an animation mask bitfield.
418
///
419
/// Bit N corresponds to mask group N.
420
///
421
/// Because this is a 64-bit value, there is currently a limitation of 64 mask
422
/// groups per animation graph.
423
pub type AnimationMask = u64;
424
425
impl AnimationGraph {
426
/// Creates a new animation graph with a root node and no other nodes.
427
pub fn new() -> Self {
428
let mut graph = DiGraph::default();
429
let root = graph.add_node(AnimationGraphNode::default());
430
Self {
431
graph,
432
root,
433
mask_groups: HashMap::default(),
434
}
435
}
436
437
/// A convenience function for creating an [`AnimationGraph`] from a single
438
/// [`AnimationClip`].
439
///
440
/// The clip will be a direct child of the root with weight 1.0. Both the
441
/// graph and the index of the added node are returned as a tuple.
442
pub fn from_clip(clip: Handle<AnimationClip>) -> (Self, AnimationNodeIndex) {
443
let mut graph = Self::new();
444
let node_index = graph.add_clip(clip, 1.0, graph.root);
445
(graph, node_index)
446
}
447
448
/// A convenience method to create an [`AnimationGraph`]s with an iterator
449
/// of clips.
450
///
451
/// All of the animation clips will be direct children of the root with
452
/// weight 1.0.
453
///
454
/// Returns the graph and indices of the new nodes.
455
pub fn from_clips<'a, I>(clips: I) -> (Self, Vec<AnimationNodeIndex>)
456
where
457
I: IntoIterator<Item = Handle<AnimationClip>>,
458
<I as IntoIterator>::IntoIter: 'a,
459
{
460
let mut graph = Self::new();
461
let indices = graph.add_clips(clips, 1.0, graph.root).collect();
462
(graph, indices)
463
}
464
465
/// Adds an [`AnimationClip`] to the animation graph with the given weight
466
/// and returns its index.
467
///
468
/// The animation clip will be the child of the given parent. The resulting
469
/// node will have no mask.
470
pub fn add_clip(
471
&mut self,
472
clip: Handle<AnimationClip>,
473
weight: f32,
474
parent: AnimationNodeIndex,
475
) -> AnimationNodeIndex {
476
let node_index = self.graph.add_node(AnimationGraphNode {
477
node_type: AnimationNodeType::Clip(clip),
478
mask: 0,
479
weight,
480
});
481
self.graph.add_edge(parent, node_index, ());
482
node_index
483
}
484
485
/// Adds an [`AnimationClip`] to the animation graph with the given weight
486
/// and mask, and returns its index.
487
///
488
/// The animation clip will be the child of the given parent.
489
pub fn add_clip_with_mask(
490
&mut self,
491
clip: Handle<AnimationClip>,
492
mask: AnimationMask,
493
weight: f32,
494
parent: AnimationNodeIndex,
495
) -> AnimationNodeIndex {
496
let node_index = self.graph.add_node(AnimationGraphNode {
497
node_type: AnimationNodeType::Clip(clip),
498
mask,
499
weight,
500
});
501
self.graph.add_edge(parent, node_index, ());
502
node_index
503
}
504
505
/// A convenience method to add multiple [`AnimationClip`]s to the animation
506
/// graph.
507
///
508
/// All of the animation clips will have the same weight and will be
509
/// parented to the same node.
510
///
511
/// Returns the indices of the new nodes.
512
pub fn add_clips<'a, I>(
513
&'a mut self,
514
clips: I,
515
weight: f32,
516
parent: AnimationNodeIndex,
517
) -> impl Iterator<Item = AnimationNodeIndex> + 'a
518
where
519
I: IntoIterator<Item = Handle<AnimationClip>>,
520
<I as IntoIterator>::IntoIter: 'a,
521
{
522
clips
523
.into_iter()
524
.map(move |clip| self.add_clip(clip, weight, parent))
525
}
526
527
/// Adds a blend node to the animation graph with the given weight and
528
/// returns its index.
529
///
530
/// The blend node will be placed under the supplied `parent` node. During
531
/// animation evaluation, the descendants of this blend node will have their
532
/// weights multiplied by the weight of the blend. The blend node will have
533
/// no mask.
534
pub fn add_blend(&mut self, weight: f32, parent: AnimationNodeIndex) -> AnimationNodeIndex {
535
let node_index = self.graph.add_node(AnimationGraphNode {
536
node_type: AnimationNodeType::Blend,
537
mask: 0,
538
weight,
539
});
540
self.graph.add_edge(parent, node_index, ());
541
node_index
542
}
543
544
/// Adds a blend node to the animation graph with the given weight and
545
/// returns its index.
546
///
547
/// The blend node will be placed under the supplied `parent` node. During
548
/// animation evaluation, the descendants of this blend node will have their
549
/// weights multiplied by the weight of the blend. Neither this node nor its
550
/// descendants will affect animation targets that belong to mask groups not
551
/// in the given `mask`.
552
pub fn add_blend_with_mask(
553
&mut self,
554
mask: AnimationMask,
555
weight: f32,
556
parent: AnimationNodeIndex,
557
) -> AnimationNodeIndex {
558
let node_index = self.graph.add_node(AnimationGraphNode {
559
node_type: AnimationNodeType::Blend,
560
mask,
561
weight,
562
});
563
self.graph.add_edge(parent, node_index, ());
564
node_index
565
}
566
567
/// Adds a blend node to the animation graph with the given weight and
568
/// returns its index.
569
///
570
/// The blend node will be placed under the supplied `parent` node. During
571
/// animation evaluation, the descendants of this blend node will have their
572
/// weights multiplied by the weight of the blend. The blend node will have
573
/// no mask.
574
pub fn add_additive_blend(
575
&mut self,
576
weight: f32,
577
parent: AnimationNodeIndex,
578
) -> AnimationNodeIndex {
579
let node_index = self.graph.add_node(AnimationGraphNode {
580
node_type: AnimationNodeType::Add,
581
mask: 0,
582
weight,
583
});
584
self.graph.add_edge(parent, node_index, ());
585
node_index
586
}
587
588
/// Adds a blend node to the animation graph with the given weight and
589
/// returns its index.
590
///
591
/// The blend node will be placed under the supplied `parent` node. During
592
/// animation evaluation, the descendants of this blend node will have their
593
/// weights multiplied by the weight of the blend. Neither this node nor its
594
/// descendants will affect animation targets that belong to mask groups not
595
/// in the given `mask`.
596
pub fn add_additive_blend_with_mask(
597
&mut self,
598
mask: AnimationMask,
599
weight: f32,
600
parent: AnimationNodeIndex,
601
) -> AnimationNodeIndex {
602
let node_index = self.graph.add_node(AnimationGraphNode {
603
node_type: AnimationNodeType::Add,
604
mask,
605
weight,
606
});
607
self.graph.add_edge(parent, node_index, ());
608
node_index
609
}
610
611
/// Adds an edge from the edge `from` to `to`, making `to` a child of
612
/// `from`.
613
///
614
/// The behavior is unspecified if adding this produces a cycle in the
615
/// graph.
616
pub fn add_edge(&mut self, from: NodeIndex, to: NodeIndex) {
617
self.graph.add_edge(from, to, ());
618
}
619
620
/// Removes an edge between `from` and `to` if it exists.
621
///
622
/// Returns true if the edge was successfully removed or false if no such
623
/// edge existed.
624
pub fn remove_edge(&mut self, from: NodeIndex, to: NodeIndex) -> bool {
625
self.graph
626
.find_edge(from, to)
627
.map(|edge| self.graph.remove_edge(edge))
628
.is_some()
629
}
630
631
/// Returns the [`AnimationGraphNode`] associated with the given index.
632
///
633
/// If no node with the given index exists, returns `None`.
634
pub fn get(&self, animation: AnimationNodeIndex) -> Option<&AnimationGraphNode> {
635
self.graph.node_weight(animation)
636
}
637
638
/// Returns a mutable reference to the [`AnimationGraphNode`] associated
639
/// with the given index.
640
///
641
/// If no node with the given index exists, returns `None`.
642
pub fn get_mut(&mut self, animation: AnimationNodeIndex) -> Option<&mut AnimationGraphNode> {
643
self.graph.node_weight_mut(animation)
644
}
645
646
/// Returns an iterator over the [`AnimationGraphNode`]s in this graph.
647
pub fn nodes(&self) -> impl Iterator<Item = AnimationNodeIndex> {
648
self.graph.node_indices()
649
}
650
651
/// Serializes the animation graph to the given [`Write`]r in RON format.
652
///
653
/// If writing to a file, it can later be loaded with the
654
/// [`AnimationGraphAssetLoader`] to reconstruct the graph.
655
pub fn save<W>(&self, writer: &mut W) -> Result<(), AnimationGraphSaveError>
656
where
657
W: Write,
658
{
659
let mut ron_serializer = ron::ser::Serializer::new(writer, None)?;
660
let serialized_graph: SerializedAnimationGraph = self.clone().try_into()?;
661
Ok(serialized_graph.serialize(&mut ron_serializer)?)
662
}
663
664
/// Adds an animation target (bone) to the mask group with the given ID.
665
///
666
/// Calling this method multiple times with the same animation target but
667
/// different mask groups will result in that target being added to all of
668
/// the specified groups.
669
pub fn add_target_to_mask_group(&mut self, target: AnimationTargetId, mask_group: u32) {
670
*self.mask_groups.entry(target).or_default() |= 1 << mask_group;
671
}
672
}
673
674
impl AnimationGraphNode {
675
/// Masks out the mask groups specified by the given `mask` bitfield.
676
///
677
/// A 1 in bit position N causes this function to mask out mask group N, and
678
/// thus neither this node nor its descendants will animate any animation
679
/// targets that belong to group N.
680
pub fn add_mask(&mut self, mask: AnimationMask) -> &mut Self {
681
self.mask |= mask;
682
self
683
}
684
685
/// Unmasks the mask groups specified by the given `mask` bitfield.
686
///
687
/// A 1 in bit position N causes this function to unmask mask group N, and
688
/// thus this node and its descendants will be allowed to animate animation
689
/// targets that belong to group N, unless another mask masks those targets
690
/// out.
691
pub fn remove_mask(&mut self, mask: AnimationMask) -> &mut Self {
692
self.mask &= !mask;
693
self
694
}
695
696
/// Masks out the single mask group specified by `group`.
697
///
698
/// After calling this function, neither this node nor its descendants will
699
/// animate any animation targets that belong to the given `group`.
700
pub fn add_mask_group(&mut self, group: u32) -> &mut Self {
701
self.add_mask(1 << group)
702
}
703
704
/// Unmasks the single mask group specified by `group`.
705
///
706
/// After calling this function, this node and its descendants will be
707
/// allowed to animate animation targets that belong to the given `group`,
708
/// unless another mask masks those targets out.
709
pub fn remove_mask_group(&mut self, group: u32) -> &mut Self {
710
self.remove_mask(1 << group)
711
}
712
}
713
714
impl Index<AnimationNodeIndex> for AnimationGraph {
715
type Output = AnimationGraphNode;
716
717
fn index(&self, index: AnimationNodeIndex) -> &Self::Output {
718
&self.graph[index]
719
}
720
}
721
722
impl IndexMut<AnimationNodeIndex> for AnimationGraph {
723
fn index_mut(&mut self, index: AnimationNodeIndex) -> &mut Self::Output {
724
&mut self.graph[index]
725
}
726
}
727
728
impl Default for AnimationGraphNode {
729
fn default() -> Self {
730
Self {
731
node_type: Default::default(),
732
mask: 0,
733
weight: 1.0,
734
}
735
}
736
}
737
738
impl Default for AnimationGraph {
739
fn default() -> Self {
740
Self::new()
741
}
742
}
743
744
impl AssetLoader for AnimationGraphAssetLoader {
745
type Asset = AnimationGraph;
746
747
type Settings = ();
748
749
type Error = AnimationGraphLoadError;
750
751
async fn load(
752
&self,
753
reader: &mut dyn Reader,
754
_: &Self::Settings,
755
load_context: &mut LoadContext<'_>,
756
) -> Result<Self::Asset, Self::Error> {
757
let mut bytes = Vec::new();
758
reader.read_to_end(&mut bytes).await?;
759
760
// Deserialize a `SerializedAnimationGraph` directly, so that we can
761
// get the list of the animation clips it refers to and load them.
762
let mut deserializer = ron::de::Deserializer::from_bytes(&bytes)?;
763
let serialized_animation_graph = SerializedAnimationGraph::deserialize(&mut deserializer)
764
.map_err(|err| deserializer.span_error(err))?;
765
766
// Load all `AssetPath`s to convert from a `SerializedAnimationGraph` to a real
767
// `AnimationGraph`. This is effectively a `DiGraph::map`, but this allows us to return
768
// errors.
769
let mut animation_graph = DiGraph::with_capacity(
770
serialized_animation_graph.graph.node_count(),
771
serialized_animation_graph.graph.edge_count(),
772
);
773
774
for serialized_node in serialized_animation_graph.graph.node_weights() {
775
animation_graph.add_node(AnimationGraphNode {
776
node_type: match serialized_node.node_type {
777
SerializedAnimationNodeType::Clip(ref path) => {
778
AnimationNodeType::Clip(load_context.load(path.clone()))
779
}
780
SerializedAnimationNodeType::Blend => AnimationNodeType::Blend,
781
SerializedAnimationNodeType::Add => AnimationNodeType::Add,
782
},
783
mask: serialized_node.mask,
784
weight: serialized_node.weight,
785
});
786
}
787
for edge in serialized_animation_graph.graph.raw_edges() {
788
animation_graph.add_edge(edge.source(), edge.target(), ());
789
}
790
Ok(AnimationGraph {
791
graph: animation_graph,
792
root: serialized_animation_graph.root,
793
mask_groups: serialized_animation_graph.mask_groups,
794
})
795
}
796
797
fn extensions(&self) -> &[&str] {
798
&["animgraph", "animgraph.ron"]
799
}
800
}
801
802
impl TryFrom<AnimationGraph> for SerializedAnimationGraph {
803
type Error = NonPathHandleError;
804
805
fn try_from(animation_graph: AnimationGraph) -> Result<Self, NonPathHandleError> {
806
// Convert all the `Handle<AnimationClip>` to AssetPath, so that
807
// `AnimationGraphAssetLoader` can load them. This is effectively just doing a
808
// `DiGraph::map`, except we need to return an error if any handles aren't associated to a
809
// path.
810
let mut serialized_graph = DiGraph::with_capacity(
811
animation_graph.graph.node_count(),
812
animation_graph.graph.edge_count(),
813
);
814
for node in animation_graph.graph.node_weights() {
815
serialized_graph.add_node(SerializedAnimationGraphNode {
816
weight: node.weight,
817
mask: node.mask,
818
node_type: match node.node_type {
819
AnimationNodeType::Clip(ref clip) => match clip.path() {
820
Some(path) => SerializedAnimationNodeType::Clip(path.clone()),
821
None => return Err(NonPathHandleError),
822
},
823
AnimationNodeType::Blend => SerializedAnimationNodeType::Blend,
824
AnimationNodeType::Add => SerializedAnimationNodeType::Add,
825
},
826
});
827
}
828
for edge in animation_graph.graph.raw_edges() {
829
serialized_graph.add_edge(edge.source(), edge.target(), ());
830
}
831
Ok(Self {
832
graph: serialized_graph,
833
root: animation_graph.root,
834
mask_groups: animation_graph.mask_groups,
835
})
836
}
837
}
838
839
/// Error for when only path [`Handle`]s are supported.
840
#[derive(Error, Debug)]
841
#[error("AnimationGraph contains a handle to an AnimationClip that does not correspond to an asset path")]
842
pub struct NonPathHandleError;
843
844
/// A system that creates, updates, and removes [`ThreadedAnimationGraph`]
845
/// structures for every changed [`AnimationGraph`].
846
///
847
/// The [`ThreadedAnimationGraph`] contains acceleration structures that allow
848
/// for quick evaluation of that graph's animations.
849
pub(crate) fn thread_animation_graphs(
850
mut threaded_animation_graphs: ResMut<ThreadedAnimationGraphs>,
851
animation_graphs: Res<Assets<AnimationGraph>>,
852
mut animation_graph_asset_events: MessageReader<AssetEvent<AnimationGraph>>,
853
) {
854
for animation_graph_asset_event in animation_graph_asset_events.read() {
855
match *animation_graph_asset_event {
856
AssetEvent::Added { id }
857
| AssetEvent::Modified { id }
858
| AssetEvent::LoadedWithDependencies { id } => {
859
// Fetch the animation graph.
860
let Some(animation_graph) = animation_graphs.get(id) else {
861
continue;
862
};
863
864
// Reuse the allocation if possible.
865
let mut threaded_animation_graph =
866
threaded_animation_graphs.0.remove(&id).unwrap_or_default();
867
threaded_animation_graph.clear();
868
869
// Recursively thread the graph in postorder.
870
threaded_animation_graph.init(animation_graph);
871
threaded_animation_graph.build_from(
872
&animation_graph.graph,
873
animation_graph.root,
874
0,
875
);
876
877
// Write in the threaded graph.
878
threaded_animation_graphs
879
.0
880
.insert(id, threaded_animation_graph);
881
}
882
883
AssetEvent::Removed { id } => {
884
threaded_animation_graphs.0.remove(&id);
885
}
886
AssetEvent::Unused { .. } => {}
887
}
888
}
889
}
890
891
impl ThreadedAnimationGraph {
892
/// Removes all the data in this [`ThreadedAnimationGraph`], keeping the
893
/// memory around for later reuse.
894
fn clear(&mut self) {
895
self.threaded_graph.clear();
896
self.sorted_edge_ranges.clear();
897
self.sorted_edges.clear();
898
}
899
900
/// Prepares the [`ThreadedAnimationGraph`] for recursion.
901
fn init(&mut self, animation_graph: &AnimationGraph) {
902
let node_count = animation_graph.graph.node_count();
903
let edge_count = animation_graph.graph.edge_count();
904
905
self.threaded_graph.reserve(node_count);
906
self.sorted_edges.reserve(edge_count);
907
908
self.sorted_edge_ranges.clear();
909
self.sorted_edge_ranges
910
.extend(iter::repeat_n(0..0, node_count));
911
912
self.computed_masks.clear();
913
self.computed_masks.extend(iter::repeat_n(0, node_count));
914
}
915
916
/// Recursively constructs the [`ThreadedAnimationGraph`] for the subtree
917
/// rooted at the given node.
918
///
919
/// `mask` specifies the computed mask of the parent node. (It could be
920
/// fetched from the [`Self::computed_masks`] field, but we pass it
921
/// explicitly as a micro-optimization.)
922
fn build_from(
923
&mut self,
924
graph: &AnimationDiGraph,
925
node_index: AnimationNodeIndex,
926
mut mask: u64,
927
) {
928
// Accumulate the mask.
929
mask |= graph.node_weight(node_index).unwrap().mask;
930
self.computed_masks[node_index.index()] = mask;
931
932
// Gather up the indices of our children, and sort them.
933
let mut kids: SmallVec<[AnimationNodeIndex; 8]> = graph
934
.neighbors_directed(node_index, Direction::Outgoing)
935
.collect();
936
kids.sort_unstable();
937
938
// Write in the list of kids.
939
self.sorted_edge_ranges[node_index.index()] =
940
(self.sorted_edges.len() as u32)..((self.sorted_edges.len() + kids.len()) as u32);
941
self.sorted_edges.extend_from_slice(&kids);
942
943
// Recurse. (This is a postorder traversal.)
944
for kid in kids.into_iter().rev() {
945
self.build_from(graph, kid, mask);
946
}
947
948
// Finally, push our index.
949
self.threaded_graph.push(node_index);
950
}
951
}
952
953