diff --git a/crates/bevy_animation/src/graph.rs b/crates/bevy_animation/src/graph.rs index 45144aa4cd1cd..da910c93b5420 100644 --- a/crates/bevy_animation/src/graph.rs +++ b/crates/bevy_animation/src/graph.rs @@ -148,8 +148,9 @@ pub type AnimationDiGraph = DiGraph; /// The index of either an animation or blend node in the animation graph. /// -/// These indices are the way that [`crate::AnimationPlayer`]s identify -/// particular animations. +/// These indices are the way that [animation players] identify each animation. +/// +/// [animation players]: crate::AnimationPlayer pub type AnimationNodeIndex = NodeIndex; /// An individual node within an animation graph. @@ -157,9 +158,7 @@ pub type AnimationNodeIndex = NodeIndex; /// The [`AnimationGraphNode::node_type`] field specifies the type of node: one /// of a *clip node*, a *blend node*, or an *add node*. Clip nodes, the leaves /// of the graph, contain animation clips to play. Blend and add nodes describe -/// how to combine their children to produce a final animation. The difference -/// between blend nodes and add nodes is that blend nodes normalize the weights -/// of their children to 1.0, while add nodes don't. +/// how to combine their children to produce a final animation. #[derive(Clone, Reflect, Debug)] pub struct AnimationGraphNode { /// Animation node data specific to the type of node (clip, blend, or add). @@ -176,11 +175,24 @@ pub struct AnimationGraphNode { /// this node and its descendants *cannot* animate mask group N. pub mask: AnimationMask, - /// The weight of this node. + /// The weight of this node, which signifies its contribution in blending. + /// + /// Note that this does not propagate down the graph hierarchy; rather, + /// each [Blend] and [Add] node uses the weights of its children to determine + /// the total animation that is accumulated at that node. The parent node's + /// weight is used only to determine the contribution of that total animation + /// in *further* blending. + /// + /// In other words, it is as if the blend node is replaced by a single clip + /// node consisting of the blended animation with the weight specified at the + /// blend node. + /// + /// For animation clips, this weight is also multiplied by the [active animation weight] + /// before being applied. /// - /// Weights are propagated down to descendants. Thus if an animation clip - /// has weight 0.3 and its parent blend node has effective weight 0.6, the - /// computed weight of the animation clip is 0.18. + /// [Blend]: AnimationNodeType::Blend + /// [Add]: AnimationNodeType::Add + /// [active animation weight]: crate::ActiveAnimation::weight pub weight: f32, } @@ -201,11 +213,13 @@ pub enum AnimationNodeType { #[default] Blend, - /// An *additive blend node*, which combines the animations of its children, - /// scaled by their weights. + /// An *additive blend node*, which combines the animations of its children + /// additively. /// /// The weights of all the children of this node are *not* normalized to - /// 1.0. + /// 1.0. Rather, the first child is used as a base, ignoring its weight, + /// while the others are multiplied by their respective weights and then + /// added in sequence to the base. /// /// Add nodes are primarily useful for superimposing an animation for a /// portion of a rig on top of the main animation. For example, an add node diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index c1b8f36bba3aa..fa86e82b9e415 100755 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -84,7 +84,7 @@ use crate::{ /// [UUID namespace]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based) pub static ANIMATION_TARGET_NAMESPACE: Uuid = Uuid::from_u128(0x3179f519d9274ff2b5966fd077023911); -/// Contains an [animation curve] which is used to animate entities. +/// Contains an [animation curve] which is used to animate a property of an entity. /// /// [animation curve]: AnimationCurve #[derive(Debug, TypePath)] @@ -422,6 +422,20 @@ impl AnimationClip { /// If the curve extends beyond the current duration of this clip, this /// method lengthens this clip to include the entire time span that the /// curve covers. + /// + /// More specifically: + /// - This clip will be sampled on the interval `[0, duration]`. + /// - Each curve in the clip is sampled by first clamping the sample time to its [domain]. + /// - Curves that extend forever never contribute to the duration. + /// + /// For example, a curve with domain `[2, 5]` will extend the clip to cover `[0, 5]` + /// when added and will produce the same output on the entire interval `[0, 2]` because + /// these time values all get clamped to `2`. + /// + /// By contrast, a curve with domain `[-10, ∞]` will never extend the clip duration when + /// added and will be sampled only on `[0, duration]`, ignoring all negative time values. + /// + /// [domain]: AnimationCurve::domain pub fn add_curve_to_target( &mut self, target_id: AnimationTargetId,