Fix #1534 Flip Animation is missing starting keyframe

Improve smooth keyframe validation, closes #1542
This commit is contained in:
JannisX11 2022-08-27 14:53:11 +02:00
parent 1024a4b008
commit 9f1061f305
3 changed files with 58 additions and 19 deletions

View File

@ -1012,17 +1012,34 @@ BARS.defineActions(function() {
opposite_animator = Animation.selected.getBoneAnimator(opposite_bone);
}
let center_keyframe;
if (formResult.offset && !kfs.find(kf => Math.epsilon(kf.time, Timeline.snapTime(Animation.selected.length/2), 0.004))) {
center_keyframe = animator.createKeyframe(null, Timeline.snapTime(Animation.selected.length/2), channel, false, false);
kfs.push(center_keyframe);
}
kfs.sort((a, b) => a.time - b.time);
let occupied_times = [];
kfs.forEach(old_kf => {
let time = old_kf.time;
if (formResult.offset) {
time = (time + Animation.selected.length/2) % (Animation.selected.length + 0.001);
}
let new_kf = opposite_animator.createKeyframe(old_kf, Timeline.snapTime(time), channel, false, false)
time = Timeline.snapTime(time);
if (occupied_times.includes(time)) return;
occupied_times.push(time);
let new_kf = opposite_animator.createKeyframe(old_kf, time, channel, false, false)
if (new_kf) {
new_kf.flip(0);
new_keyframes.push(new_kf);
}
})
if (formResult.offset && !occupied_times.includes(0)) {
let new_kf = opposite_animator.createKeyframe(new_keyframes.last(), 0, channel, false, false)
if (new_kf) {
new_keyframes.push(new_kf);
}
}
if (center_keyframe) center_keyframe.remove();
})
if (formResult.show_in_timeline && opposite_animator) {
opposite_animator.addToTimeline();

View File

@ -189,6 +189,16 @@ new ValidatorCheck('catmullrom_keyframes', {
condition: {features: ['animation_files']},
update_triggers: ['update_keyframe_selection'],
run() {
function getButtons(kf) {
return [{
name: 'Reveal Keyframe',
icon: 'icon-keyframe',
click() {
Dialog.open.close();
kf.showInTimeline();
}
}]
}
Animation.all.forEach(animation => {
for (let key in animation.animators) {
let animator = animation.animators[key];
@ -201,30 +211,42 @@ new ValidatorCheck('catmullrom_keyframes', {
if (kf.interpolation == 'catmullrom') {
if (kf.data_points.find(dp => isNaN(dp.x) || isNaN(dp.y) || isNaN(dp.z))) {
this.fail({
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" contains non-numeric value. Smooth keyframes cannot contain math expressions.`,
buttons: [{
name: 'Reveal Keyframe',
icon: 'icon-keyframe',
click() {
Dialog.open.close();
kf.showInTimeline();
}
}]
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" contains non-numeric values. Smooth keyframes cannot contain math expressions.`,
buttons: getButtons(kf)
})
}
if ((!keyframes[i-1] || keyframes[i-1].interpolation != 'catmullrom') && (!keyframes[i+1] || keyframes[i+1].interpolation != 'catmullrom')) {
this.warn({
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" is not surrounded by smooth keyframes. Multiple smooth keyframes are required to create a smooth spline.`,
buttons: [{
name: 'Reveal Keyframe',
icon: 'icon-keyframe',
click() {
Dialog.open.close();
kf.showInTimeline();
}
}]
buttons: getButtons(kf)
})
} else if (!keyframes[i+1] && animation.length && (kf.time+0.01) < animation.length && kf.data_points.find(dp => parseFloat(dp.x) || parseFloat(dp.y) || parseFloat(dp.z))) {
this.warn({
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" is the last smooth keyframe, but does not line up with the end of the animation. The last keyframe should either be linear, or line up with the animation end.`,
buttons: getButtons(kf)
})
}
} else if (keyframes[i+1] && keyframes[i+1].interpolation == 'catmullrom' && kf.data_points.find(dp => isNaN(dp.x) || isNaN(dp.y) || isNaN(dp.z))) {
this.fail({
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" contains non-numeric values. Keyframes that are adjacent to smooth keyframes cannot contain math expressions.`,
buttons: getButtons(kf)
})
} else if (keyframes[i-1] && keyframes[i-1].interpolation == 'catmullrom' && kf.data_points.find(dp => isNaN(dp.x) || isNaN(dp.y) || isNaN(dp.z))) {
this.fail({
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" contains non-numeric values. Keyframes that are adjacent to smooth keyframes cannot contain math expressions.`,
buttons: getButtons(kf)
})
} else if (keyframes[i-2] && keyframes[i-2].interpolation == 'catmullrom' && kf.data_points.find(dp => isNaN(dp.x) || isNaN(dp.y) || isNaN(dp.z))) {
this.warn({
message: `${animator.channels[channel].name} keyframe at ${kf.time.toFixed(2)} on "${animator.name}" in "${animation.name}" contains non-numeric values. Keyframes that are adjacent to smooth keyframes cannot contain math expressions.`,
buttons: getButtons(kf)
})
}
})
}

View File

@ -1603,7 +1603,7 @@
"menu.animation.properties": "Properties...",
"menu.animation.file": "File",
"menu.animation.snapping": "Snapping",
"menu.animation.open_location": "Open File Location",
"menu.animation.open_location": "Show in File Explorer",
"menu.animation.unload": "Unload",
"menu.animation.flip_keyframes": "Flip Keyframes",