Skip to content

Commit df899d2

Browse files
A-WalrusnicopapCGMossa
authored
Fix morph interpolation (#9927)
# Objective Fixes: #9898 ## Solution Make morph behave like other keyframes, lerping first between start and end, and then between the current state and the result. ## Changelog Fixed jerky morph targets --------- Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com> Co-authored-by: CGMossa <cgmossa@gmail.com>
1 parent 7a507fa commit df899d2

File tree

1 file changed

+26
-12
lines changed
  • crates/bevy_animation/src

1 file changed

+26
-12
lines changed

crates/bevy_animation/src/lib.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,16 @@ fn run_animation_player(
565565
}
566566
}
567567

568-
/// Update `weights` based on weights in `keyframes` at index `key_index`
569-
/// with a linear interpolation on `key_lerp`.
568+
/// Update `weights` based on weights in `keyframe` with a linear interpolation
569+
/// on `key_lerp`.
570+
fn lerp_morph_weights(weights: &mut [f32], keyframe: impl Iterator<Item = f32>, key_lerp: f32) {
571+
let zipped = weights.iter_mut().zip(keyframe);
572+
for (morph_weight, keyframe) in zipped {
573+
*morph_weight += (keyframe - *morph_weight) * key_lerp;
574+
}
575+
}
576+
577+
/// Extract a keyframe from a list of keyframes by index.
570578
///
571579
/// # Panics
572580
///
@@ -575,16 +583,10 @@ fn run_animation_player(
575583
/// This happens when `keyframes` is not formatted as described in
576584
/// [`Keyframes::Weights`]. A possible cause is [`AnimationClip`] not being
577585
/// meant to be used for the [`MorphWeights`] of the entity it's being applied to.
578-
fn lerp_morph_weights(weights: &mut [f32], key_lerp: f32, keyframes: &[f32], key_index: usize) {
579-
let target_count = weights.len();
586+
fn get_keyframe(target_count: usize, keyframes: &[f32], key_index: usize) -> &[f32] {
580587
let start = target_count * key_index;
581588
let end = target_count * (key_index + 1);
582-
583-
let zipped = weights.iter_mut().zip(&keyframes[start..end]);
584-
for (morph_weight, keyframe) in zipped {
585-
let minus_lerp = 1.0 - key_lerp;
586-
*morph_weight = (*morph_weight * minus_lerp) + (keyframe * key_lerp);
587-
}
589+
&keyframes[start..end]
588590
}
589591

590592
#[allow(clippy::too_many_arguments)]
@@ -657,7 +659,12 @@ fn apply_animation(
657659
}
658660
Keyframes::Weights(keyframes) => {
659661
if let Ok(morphs) = &mut morphs {
660-
lerp_morph_weights(morphs.weights_mut(), weight, keyframes, 0);
662+
let target_count = morphs.weights().len();
663+
lerp_morph_weights(
664+
morphs.weights_mut(),
665+
get_keyframe(target_count, keyframes, 0).iter().copied(),
666+
weight,
667+
);
661668
}
662669
}
663670
}
@@ -707,7 +714,14 @@ fn apply_animation(
707714
}
708715
Keyframes::Weights(keyframes) => {
709716
if let Ok(morphs) = &mut morphs {
710-
lerp_morph_weights(morphs.weights_mut(), weight, keyframes, step_start);
717+
let target_count = morphs.weights().len();
718+
let morph_start = get_keyframe(target_count, keyframes, step_start);
719+
let morph_end = get_keyframe(target_count, keyframes, step_start + 1);
720+
let result = morph_start
721+
.iter()
722+
.zip(morph_end)
723+
.map(|(a, b)| *a + lerp * (*b - *a));
724+
lerp_morph_weights(morphs.weights_mut(), result, weight);
711725
}
712726
}
713727
}

0 commit comments

Comments
 (0)