Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 73 additions & 7 deletions crates/bevy_animation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,8 @@ fn apply_animation(
// SAFETY: As above, there can't be other AnimationPlayers with this target so this fetch can't alias
let mut morphs = unsafe { morphs.get_unchecked(target) }.ok();
for curve in curves {
let len = curve.keyframe_timestamps.len();

// Some curves have only one keyframe used to set a transform
if curve.keyframe_timestamps.len() == 1 {
match &curve.keyframes {
Expand Down Expand Up @@ -707,16 +709,47 @@ fn apply_animation(
continue;
}

// Find the current keyframe
// Attempt to find the keyframe at or before the current time
// An Ok(keyframe_index) result means an exact result was found by binary search
// An Err result means the keyframe was not found, and the index is the keyframe
// PERF: finding the current keyframe can be optimised
let step_start = match curve
let index = curve
.keyframe_timestamps
.binary_search_by(|probe| probe.partial_cmp(&animation.seek_time).unwrap())
{
Ok(n) if n >= curve.keyframe_timestamps.len() - 1 => continue, // this curve is finished
.binary_search_by(|probe| probe.partial_cmp(&animation.seek_time).unwrap());

// Find the keyframe that our animation starts from
let step_start = match index {
// We could find an exact match,
// and the match was the last or second last keyframe
Ok(i) if i >= curve.keyframe_timestamps.len() - 1 => {
set_transform_to_keyframe(
curve,
&mut transform,
weight,
&mut morphs,
len - 1,
);
continue;
}
// We could find an exact match,
// and the match was not the last or second last keyframe
Ok(i) => i,
Err(0) => continue, // this curve isn't started yet
Err(n) if n > curve.keyframe_timestamps.len() - 1 => continue, // this curve is finished
// The animation was not started yet
Err(0) => continue,
// We could not find an exact match,
// and the timestamp was after the last keyframe
Err(i) if i > curve.keyframe_timestamps.len() - 1 => {
set_transform_to_keyframe(
curve,
&mut transform,
weight,
&mut morphs,
len - 1,
);
continue;
}
// We could not find an exact match,
// But we are
Err(i) => i - 1,
};
let ts_start = curve.keyframe_timestamps[step_start];
Expand All @@ -741,6 +774,39 @@ fn apply_animation(
}
}

/// Sets the [`Transform`] value to exactly the value it has at the provided keyframe.
fn set_transform_to_keyframe(
curve: &VariableCurve,
transform: &mut Mut<'_, Transform>,
weight: f32,
morphs: &mut Option<Mut<'_, MorphWeights>>,
keyframe: usize,
) {
match &curve.keyframes {
Keyframes::Rotation(keyframes) => {
transform.rotation = transform.rotation.slerp(keyframes[keyframe], weight);
}
Keyframes::Translation(keyframes) => {
transform.translation = transform.translation.lerp(keyframes[keyframe], weight);
}
Keyframes::Scale(keyframes) => {
transform.scale = transform.scale.lerp(keyframes[keyframe], weight);
}
Keyframes::Weights(keyframes) => {
if let Some(morphs) = morphs {
let target_count = morphs.weights().len();
lerp_morph_weights(
morphs.weights_mut(),
get_keyframe(target_count, keyframes, keyframe)
.iter()
.copied(),
weight,
);
}
}
}
}

#[inline(always)]
fn apply_keyframe(
curve: &VariableCurve,
Expand Down