diff options
author | Wayde Moss <wbmoss_dev@yahoo.com> | 2022-04-14 12:38:36 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@blender.org> | 2022-04-14 12:55:08 +0300 |
commit | 3acbe2d1e933db12dea4894c111de7394bc82551 (patch) | |
tree | c807a7d7e0f59da1d2af28ad9f66809003fd486f /source/blender/editors/animation/keyframing.c | |
parent | b0dc3aff2c73f2a1b65406dcb7fe73c95b9485ed (diff) |
NLA: Keyframe Remap Through Upper Strips
Add a new operator, "Start Tweaking Strip Actions (Full Stack)", which
allows you to insert keyframes and preserve the pose that you visually
keyed while upper strips are evaluating,
The old operator has been renamed from "Start Tweaking Strip Actions" to
"Start Tweaking Strip Actions (Lower Stack)" and remains the default for
the hotkey {key TAB}.
**Limitations, Keyframe Remapping Failure Cases**:
1. For *transitions* above the tweaked strip, keyframe remapping will
fail for channel values that are affected by the transition. A work
around is to tweak the active strip without evaluating the upper NLA
stack.
It's not supported because it's non-trivial and I couldn't figure it
out for all transition combinations of blend modes. In the future, it
would be nice if transitions (and metas) supported nested tracks
instead of using the left/right strips for the transitions. That
would allow the transitioned strips to overlap in time. It would also
allow N strips to be part of the (previously) left and right strips,
or perhaps even N strips being transitioned in sequence (similar to a
blend tree). Proper keyframe remapping through all that is currently
beyond my mathematical ability. And even if I could figure it out,
would it make sense to keyframe remap through a transition?
//This case is reported to the user for failed keyframe insertions.//
2. Full replace upper strip that contains the keyed channels.
//This case is reported to the user for failed keyframe insertions.//
3. When the same action clip occurs multiple times (colored Red to
denote it's a linked strip) and vertically overlaps the tweaked
strip, then the remapping will generally fail and is expected to
fail.
I don't plan on adding support for this case as it's also non-trivial
and (hopefully) not a common or expected use case so it shouldn't be
much of an issue to lack support here.
For anyone curious on the cases that would work, it works when the
linked strips aren't time-aligned and when we can insert a keyframe
into the tweaked strip without modifying the current frame output of
the other linked strips. Having all frames sampled and the strip
non-time aligned leads to a working case. But if all key handles are
AUTO, then it's likely to fail.
//This case is not reported to the user for failed keyframe
insertions.//
4. When using Quaternions and a small strip influence on the tweaked
Combine strip. This was an existing failure case before this patch
too but worth a mention in case it causes confusion. D10504 has an
example file with instructions.
//This case is not reported to the user for failed keyframe insertions. //
5. When an upper Replace strip with high influence and animator keys to
Quaternion Combine (Replace is fine). This case is similar to (4)
where Quaternion 180 degree rotation limitations prevent a solution.
//This case is not reported to the user for failed keyframe insertions.//
Reviewed By: sybren, RiggingDojo
Differential Revision: https://developer.blender.org/D10504
Diffstat (limited to 'source/blender/editors/animation/keyframing.c')
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 238 |
1 files changed, 159 insertions, 79 deletions
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 0d0d13e2f74..d42efcd81e5 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -14,6 +14,7 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_dynstr.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -1109,9 +1110,62 @@ static float *visualkey_get_values( /* ------------------------- Insert Key API ------------------------- */ +/* Check indices that were intended to be remapped and report any failed remaps. */ +static void get_keyframe_values_create_reports(ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + const int index, + const int count, + const bool force_all, + const BLI_bitmap *successful_remaps) +{ + + DynStr *ds_failed_indices = BLI_dynstr_new(); + + int total_failed = 0; + for (int i = 0; i < count; i++) { + const bool cur_index_evaluated = ELEM(index, i, -1) || force_all; + if (!cur_index_evaluated) { + /* values[i] was never intended to be remapped. */ + continue; + } + + if (BLI_BITMAP_TEST_BOOL(successful_remaps, i)) { + /* values[i] succesfully remapped. */ + continue; + } + + total_failed++; + /* Report that values[i] were intended to be remapped but failed remapping process. */ + BLI_dynstr_appendf(ds_failed_indices, "%d, ", i); + } + + if (total_failed == 0) { + BLI_dynstr_free(ds_failed_indices); + return; + } + + char *str_failed_indices = BLI_dynstr_get_cstring(ds_failed_indices); + BLI_dynstr_free(ds_failed_indices); + + BKE_reportf(reports, + RPT_WARNING, + "Could not insert %i keyframe(s) due to zero NLA influence, base value, or value " + "remapping failed: %s.%s for indices [%s]", + total_failed, + ptr.owner_id->name, + RNA_property_ui_name(prop), + str_failed_indices); + + MEM_freeN(str_failed_indices); +} + /** * Retrieve current property values to keyframe, * possibly applying NLA correction when necessary. + * + * \param r_successful_remaps: Enables bits for indices which are both intended to be remapped and + * were successfully remapped. Bitmap allocated so it must be freed afterward. */ static float *get_keyframe_values(ReportList *reports, PointerRNA ptr, @@ -1121,8 +1175,10 @@ static float *get_keyframe_values(ReportList *reports, eInsertKeyFlags flag, float *buffer, int buffer_size, + const struct AnimationEvalContext *anim_eval_context, int *r_count, - bool *r_force_all) + bool *r_force_all, + BLI_bitmap **r_successful_remaps) { float *values; @@ -1138,17 +1194,20 @@ static float *get_keyframe_values(ReportList *reports, values = setting_get_rna_values(&ptr, prop, buffer, buffer_size, r_count); } - /* adjust the value for NLA factors */ - if (!BKE_animsys_nla_remap_keyframe_values( - nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { - BKE_report( - reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); + *r_successful_remaps = BLI_BITMAP_NEW(*r_count, __func__); - if (values != buffer) { - MEM_freeN(values); - } - return NULL; - } + /* adjust the value for NLA factors */ + BKE_animsys_nla_remap_keyframe_values(nla_context, + &ptr, + prop, + values, + *r_count, + index, + anim_eval_context, + r_force_all, + *r_successful_remaps); + get_keyframe_values_create_reports( + reports, ptr, prop, index, *r_count, *r_force_all, *r_successful_remaps); return values; } @@ -1284,6 +1343,7 @@ bool insert_keyframe_direct(ReportList *reports, int value_count; int index = fcu->array_index; + BLI_bitmap *successful_remaps = NULL; float *values = get_keyframe_values(reports, ptr, prop, @@ -1292,13 +1352,10 @@ bool insert_keyframe_direct(ReportList *reports, flag, value_buffer, RNA_MAX_ARRAY_LENGTH, + anim_eval_context, &value_count, - NULL); - - if (values == NULL) { - /* This happens if NLA rejects this insertion. */ - return false; - } + NULL, + &successful_remaps); if (index >= 0 && index < value_count) { curval = values[index]; @@ -1308,6 +1365,14 @@ bool insert_keyframe_direct(ReportList *reports, MEM_freeN(values); } + const bool curval_valid = BLI_BITMAP_TEST_BOOL(successful_remaps, index); + MEM_freeN(successful_remaps); + + /* This happens if NLA rejects this insertion. */ + if (!curval_valid) { + return false; + } + return insert_keyframe_value(reports, &ptr, prop, fcu, anim_eval_context, curval, keytype, flag); } @@ -1461,6 +1526,7 @@ int insert_keyframe(Main *bmain, int value_count; bool force_all; + BLI_bitmap *successful_remaps = NULL; float *values = get_keyframe_values(reports, ptr, prop, @@ -1469,77 +1535,72 @@ int insert_keyframe(Main *bmain, flag, value_buffer, RNA_MAX_ARRAY_LENGTH, + anim_eval_context, &value_count, - &force_all); + &force_all, + &successful_remaps); - if (values != NULL) { - /* Key the entire array. */ - if (array_index == -1 || force_all) { - /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ - if (force_all && (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) != 0) { - int exclude = -1; + /* Key the entire array. */ + if (array_index == -1 || force_all) { + /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ + if (force_all && (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) != 0) { + int exclude = -1; - for (array_index = 0; array_index < value_count; array_index++) { - if (insert_keyframe_fcurve_value(bmain, - reports, - &ptr, - prop, - act, - group, - rna_path, - array_index, - &remapped_context, - values[array_index], - keytype, - flag)) { - ret++; - exclude = array_index; - break; - } + for (array_index = 0; array_index < value_count; array_index++) { + if (!BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + continue; } - if (exclude != -1) { - flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE); - - for (array_index = 0; array_index < value_count; array_index++) { - if (array_index != exclude) { - ret += insert_keyframe_fcurve_value(bmain, - reports, - &ptr, - prop, - act, - group, - rna_path, - array_index, - &remapped_context, - values[array_index], - keytype, - flag); - } - } + if (insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + &remapped_context, + values[array_index], + keytype, + flag)) { + ret++; + exclude = array_index; + break; } } - /* Simply insert all channels. */ - else { + + if (exclude != -1) { + flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE); + for (array_index = 0; array_index < value_count; array_index++) { - ret += insert_keyframe_fcurve_value(bmain, - reports, - &ptr, - prop, - act, - group, - rna_path, - array_index, - &remapped_context, - values[array_index], - keytype, - flag); + if (!BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + continue; + } + + if (array_index != exclude) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + &remapped_context, + values[array_index], + keytype, + flag); + } } } } - /* Key a single index. */ + /* Simply insert all channels. */ else { - if (array_index >= 0 && array_index < value_count) { + for (array_index = 0; array_index < value_count; array_index++) { + if (!BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + continue; + } + ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, @@ -1554,12 +1615,31 @@ int insert_keyframe(Main *bmain, flag); } } - - if (values != value_buffer) { - MEM_freeN(values); + } + /* Key a single index. */ + else { + if (array_index >= 0 && array_index < value_count && + BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + &remapped_context, + values[array_index], + keytype, + flag); } } + if (values != value_buffer) { + MEM_freeN(values); + } + + MEM_freeN(successful_remaps); BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); if (ret) { |