[Bf-blender-cvs] [cfa7e581dae] temp-nla-strip-alignment: -some early WIP for strip alignment:

Wayde Moss noreply at git.blender.org
Thu Dec 10 06:13:36 CET 2020


Commit: cfa7e581daed790ef63afdfa91b1f7a266ad19e0
Author: Wayde Moss
Date:   Sat Oct 31 16:04:27 2020 -0400
Branches: temp-nla-strip-alignment
https://developer.blender.org/rBcfa7e581daed790ef63afdfa91b1f7a266ad19e0

-some early WIP for strip alignment:

Overall Need:
UI:
-ability to add NlaStrip preblend transform elements using UI
-add, remove, clear
-bone_name from selection, from active
-ability to copy bone targets between strips

UI:
-visualization of traversal bone for general alignment,
similar to motion paths but without the need for an accurate world
transform. It should update as preblend xform changes. Ideally this
path is grabbale and transformable like any other object.
Would require making own transform_convert_stripPreBlendTransform
code... (opportunity to make Python API for it?)

Core algorithm implementation:
-instead of blending strips as their value obtained, we need to
get all raw values. Then apply preblend xform, then we can blend the
whole snapshot. For efficiency, we can allocate the relevant NlaEvalChannels
for bones right after creating NlaEvalData.

===================================================================

M	source/blender/blenkernel/intern/anim_sys.c
M	source/blender/editors/space_nla/nla_buttons.c
M	source/blender/makesdna/DNA_anim_types.h
M	source/blender/makesrna/intern/rna_nla.c

===================================================================

diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index bd9eaae3323..53c3ef66c84 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -3476,6 +3476,81 @@ static bool animsys_evaluate_nla_for_flush(NlaEvalData *echannels,
                       true);
   }
 
+  /** If alignment strips exist, then overwrite object transform without blending */
+  {
+    ListBase alignment_strips = {NULL, NULL};
+    for (nes = estrips.first; nes; nes = nes->next) {
+      NlaStrip *strip = nes->strip;
+      if ((strip->flag & NLASTRIP_FLAG_ALIGNED) == 0) {
+        continue;
+      }
+      LinkData *ld = MEM_callocN(sizeof(LinkData), __func__);
+      ld->data = strip;
+      BLI_addtail(&alignment_strips, ld);
+    }
+
+    if (alignment_strips.first) {
+      NlaStrip *left_most_strip = (NlaStrip *)((LinkData *)alignment_strips.first)->data;
+      LinkData *ld_strip;
+      /** Use Leftmost strip. If mul are left most, then use lower one. */
+      for (ld_strip = alignment_strips.first; ld_strip; ld_strip = ld_strip->next) {
+        NlaStrip *strip = (NlaStrip *)ld_strip->data;
+
+        // if full replace, we just take upper.
+        if (strip->blendmode == NLASTRIP_MODE_REPLACE && IS_EQF(strip->influence,1)) {
+          left_most_strip = strip;
+          continue; 
+        }
+
+        //otherwise, take leftmost
+        if (strip->start < left_most_strip->start) {
+          left_most_strip = strip;
+        }
+        // take top strip's alignment if it starts on lower's end since lower doesn't eval.
+        if (abs(strip->start - left_most_strip->end) < .001f) {
+          left_most_strip = strip;
+        }
+      }
+
+      if (left_most_strip) {
+        NlaEvalChannel *nec;
+        NlaEvalChannelSnapshot *nec_snapshot;
+
+        nec = nlaevalchan_verify(ptr, echannels, "location");
+        nec_snapshot = nlaeval_snapshot_ensure_channel(&echannels->eval_snapshot, nec);
+        BLI_bitmap_set_all(nec->domain.ptr, true, 3);
+        nec_snapshot->values[0] = left_most_strip->location_alignment[0];
+        nec_snapshot->values[1] = left_most_strip->location_alignment[1];
+        nec_snapshot->values[2] = left_most_strip->location_alignment[2];
+        // animsys_write_orig_anim_rna(ptr, "location", 0, left_most_strip->location_alignment[0]);
+        // animsys_write_orig_anim_rna(ptr, "location", 1, left_most_strip->location_alignment[1]);
+        // animsys_write_orig_anim_rna(ptr, "location", 2, left_most_strip->location_alignment[2]);
+
+        nec = nlaevalchan_verify(ptr, echannels, "rotation_euler");
+        nec_snapshot = nlaeval_snapshot_ensure_channel(&echannels->eval_snapshot, nec);
+        BLI_bitmap_set_all(nec->domain.ptr, true, 3);
+        nec_snapshot->values[0] = left_most_strip->euler_alignment[0];
+        nec_snapshot->values[1] = left_most_strip->euler_alignment[1];
+        nec_snapshot->values[2] = left_most_strip->euler_alignment[2];
+        // animsys_write_orig_anim_rna(ptr, "rotation_euler", 0,
+        // left_most_strip->euler_alignment[0]); animsys_write_orig_anim_rna(ptr, "rotation_euler",
+        // 1, left_most_strip->euler_alignment[1]); animsys_write_orig_anim_rna(ptr,
+        // "rotation_euler", 2, left_most_strip->euler_alignment[2]);
+
+        nec = nlaevalchan_verify(ptr, echannels, "scale");
+        nec_snapshot = nlaeval_snapshot_ensure_channel(&echannels->eval_snapshot, nec);
+        BLI_bitmap_set_all(nec->domain.ptr, true, 3);
+        nec_snapshot->values[0] = left_most_strip->scale_alignment[0];
+        nec_snapshot->values[1] = left_most_strip->scale_alignment[1];
+        nec_snapshot->values[2] = left_most_strip->scale_alignment[2];
+        // animsys_write_orig_anim_rna(ptr, "scale", 0, left_most_strip->scale_alignment[0]);
+        // animsys_write_orig_anim_rna(ptr, "scale", 1, left_most_strip->scale_alignment[1]);
+        // animsys_write_orig_anim_rna(ptr, "scale", 2, left_most_strip->scale_alignment[2]);
+      }
+    }
+    BLI_freelistN(&alignment_strips);
+  }
+
   /* Free temporary evaluation data that's not used elsewhere. */
   BLI_freelistN(&estrips);
   return true;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 083fd641dc1..0a7c2471d0f 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -535,6 +535,51 @@ static void nla_panel_animated_strip_time(const bContext *C, Panel *panel)
   uiItemR(layout, &strip_ptr, "strip_time", 0, NULL, ICON_NONE);
 }
 
+static void nla_panel_alignment_header(const bContext *C, Panel *panel)
+{
+  PointerRNA strip_ptr;
+  uiLayout *layout = panel->layout;
+  uiLayout *col;
+  uiBlock *block;
+
+  /* check context and also validity of pointer */
+  if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
+    return;
+  }
+  block = uiLayoutGetBlock(layout);
+  UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
+
+  // col = uiLayoutColumnWithHeading(layout, true, IFACE_("Alignment"));
+
+  col = uiLayoutColumn(layout, true);
+  uiItemR(col, &strip_ptr, "use_alignment", 0, "", ICON_NONE);
+}
+
+static void nla_panel_alignment(const bContext *C, Panel *panel)
+{
+  PointerRNA strip_ptr;
+  uiLayout *layout = panel->layout;
+  uiBlock *block;
+  uiLayout *column;
+
+  /* check context and also validity of pointer */
+  if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
+    return;
+  }
+
+  block = uiLayoutGetBlock(layout);
+  UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
+  uiLayoutSetPropSep(layout, true);
+
+  uiLayoutSetEnabled(layout, RNA_boolean_get(&strip_ptr, "use_alignment"));
+
+  
+  column = uiLayoutColumn(layout, false);
+  uiItemR(column, &strip_ptr, "location_alignment", 0, NULL, ICON_NONE);
+  uiItemR(column, &strip_ptr, "euler_alignment", 0, NULL, ICON_NONE);
+  uiItemR(column, &strip_ptr, "scale_alignment", 0, NULL, ICON_NONE);
+}
+
 /* F-Modifiers for active NLA-Strip */
 static void nla_panel_modifiers(const bContext *C, Panel *panel)
 {
@@ -650,6 +695,20 @@ void nla_buttons_register(ARegionType *art)
   BLI_addtail(&pt_properties->children, BLI_genericNodeN(pt));
   BLI_addtail(&art->paneltypes, pt);
 
+  pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel alignment");
+  strcpy(pt->idname, "NLA_PT_alignment");
+  strcpy(pt->parent_id, "NLA_PT_properties");
+  strcpy(pt->label, N_("Alignment"));
+  strcpy(pt->category, "Strip");
+  strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+  pt->draw = nla_panel_alignment;
+  pt->draw_header = nla_panel_alignment_header;
+  pt->parent = pt_properties;
+  pt->flag = PNL_DEFAULT_CLOSED;
+  pt->poll = nla_strip_eval_panel_poll;
+  BLI_addtail(&pt_properties->children, BLI_genericNodeN(pt));
+  BLI_addtail(&art->paneltypes, pt);
+
   pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
   strcpy(pt->idname, "NLA_PT_modifiers");
   strcpy(pt->label, N_("Modifiers"));
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 033b671343a..7a475b9eff3 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -696,6 +696,33 @@ typedef enum eFCurve_Smoothing {
 
 /* NLA Strips ------------------------------------- */
 
+typedef struct NlaStripPreBlendTransform {
+  /** Used for Strip Alignment of bones: This applies a transform to strip bone channels before
+   * blending. This allows the animator to align traversal bones (like root bone) so that blending
+   * will occur in the proper blend space. Otherwise, blending a Run midway through a Walk cycle,
+   * where the root travels, results in the root blending to Run frame0, where the root is at zero.
+   */
+  float location[3];
+  float euler[3];
+  float scale[3];
+  float _pad;
+  // char transform_target;
+  // char _pad0[3];
+
+  /*Element: NlaStripPreBlendTransform_BoneName*/
+  ListBase bones;
+} NlaStripPreBlendTransform;
+
+typedef struct NlaStripPreBlendTransform_BoneName {
+  char name[MAX_ID_NAME];
+} NlaStripPreBlendTransform_BoneName;
+
+/* NlaStripPreBlendTransform Flags */
+typedef enum eNlaStripPreBlendTransform_Target {
+  NLASTRIP_XFORM_OBJECT = 0,
+  NLASTRIP_XFORM_BONES = 1,
+} eNlaStrip_Blend_Mode;
+
 /**
  * NLA Strip (strip)
  *
@@ -755,6 +782,9 @@ typedef struct NlaStrip {
   /* Pointer to an original NLA strip. */
   struct NlaStrip *orig_strip;
 
+  /*Element: NlaStripPreBlendTransform */
+  ListBase preblend_transforms;
+
   void *_pad3;
 } NlaStrip;
 
@@ -797,6 +827,7 @@ typedef enum eNlaStrip_Flag {
   NLASTRIP_FLAG_USR_INFLUENCE = (1 << 5),
   NLASTRIP_FLAG_USR_TIME = (1 << 6),
   NLASTRIP_FLAG_USR_TIME_CYCLIC = (1 << 7),
+  NLASTRIP_FLAG_ALIGNED = (1 << 8),
 
   /** NLA strip length is synced to the length of the referenced action */
   NLASTRIP_FLAG_SYNC_LENGTH = (1 << 9),
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index d3ac455fc2b..c427b279cf7 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -144,6 +144,91 @@ static char *rna_NlaStrip_path(PointerRNA *ptr)
   return BLI_strdup("");
 }
 
+static char *rna_NlaStripPreBlendTransform_path(PointerRNA *ptr)
+{
+  NlaStripPreBlendTransform *preblend_xform = (NlaStripPreBlendTransform *)ptr->data;
+  AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
+
+  /* if we're attached to AnimData, try to resolve path back to AnimData */
+  if (adt) {
+    NlaTrack *nlt;
+    NlaStrip *nls;
+
+    int pbxform_index;
+    for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+      for (nls = nlt->strips.first; nls; nls = nls->next) {
+        pbxform_index = 0;
+        for (pbxform = nls->pbxform.first; pbxform; pbxform = pbxform->next, pbxform_index++) {
+          if (nls->preblend_transforms == preblend_xform) {
+            /* XXX but if we animate like this, the control will never work... */
+            char name_esc_nlt[sizeof(nlt->name) * 2];
+            char name_esc_strip[sizeof(strip->name) * 2];
+
+            BLI_strescape(name_esc_nlt, nlt->name, si

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list