Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWayde Moss <wbmoss_dev@yahoo.com>2022-04-14 12:38:36 +0300
committerSybren A. Stüvel <sybren@blender.org>2022-04-14 12:55:08 +0300
commit3acbe2d1e933db12dea4894c111de7394bc82551 (patch)
treec807a7d7e0f59da1d2af28ad9f66809003fd486f /source/blender/editors
parentb0dc3aff2c73f2a1b65406dcb7fe73c95b9485ed (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')
-rw-r--r--source/blender/editors/animation/keyframing.c238
-rw-r--r--source/blender/editors/space_nla/nla_edit.c15
2 files changed, 174 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) {
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 79bfaa92f80..2aa9b347ed7 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -98,6 +98,7 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
int filter;
const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
+ const bool use_upper_stack_evaluation = RNA_boolean_get(op->ptr, "use_upper_stack_evaluation");
bool ok = false;
/* get editor data */
@@ -119,6 +120,13 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ale->data;
+ if (use_upper_stack_evaluation) {
+ adt->flag |= ADT_NLA_EVAL_UPPER_TRACKS;
+ }
+ else {
+ adt->flag &= ~ADT_NLA_EVAL_UPPER_TRACKS;
+ }
+
/* Try entering tweak-mode if valid. */
ok |= BKE_nla_tweakmode_enter(adt);
@@ -181,6 +189,13 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
"Enable 'solo' on the NLA Track containing the active strip, "
"to edit it without seeing the effects of the NLA stack");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna,
+ "use_upper_stack_evaluation",
+ false,
+ "Evaluate Upper Stack",
+ "In tweak mode, display the effects of the tracks above the tweak strip");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */