[Bf-blender-cvs] [ee43cf57224] master: Fix T66751: Symmetrizing armature does not symmetrize constraints.

Sebastian Parborg noreply at git.blender.org
Tue Apr 7 13:54:27 CEST 2020


Commit: ee43cf572247d3ac158da8e284e0afeb78437a7f
Author: Sebastian Parborg
Date:   Tue Apr 7 13:50:57 2020 +0200
Branches: master
https://developer.blender.org/rBee43cf572247d3ac158da8e284e0afeb78437a7f

Fix T66751: Symmetrizing armature does not symmetrize constraints.

The symmetrize operator now tries to make sure that the armature
constraints are correctly mirrored.

Before it would only mirror the subtargets for the constraints (and that
failed too in some cases).

Reviewed By: Sybren

Differential Revision: http://developer.blender.org/D6009

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

M	source/blender/blenkernel/intern/action.c
M	source/blender/editors/armature/armature_add.c
M	source/blender/editors/armature/armature_intern.h

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

diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 478609f2f3f..ba77538bfb6 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -925,6 +925,7 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
 
   if (pchan->prop) {
     IDP_FreeProperty(pchan->prop);
+    pchan->prop = NULL;
   }
 
   /* Cached data, for new draw manager rendering code. */
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 0bc405a9c67..3fce2376b40 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -22,6 +22,7 @@
  * \ingroup edarmature
  */
 
+#include "DNA_anim_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_object_types.h"
@@ -38,8 +39,12 @@
 #include "BKE_constraint.h"
 #include "BKE_context.h"
 #include "BKE_deform.h"
+#include "BKE_fcurve.h"
 #include "BKE_idprop.h"
 #include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -375,25 +380,20 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
   BLI_ghash_free(name_map, NULL, NULL);
 }
 
-/*
- * Note: When duplicating cross objects, editbones here is the list of bones
- * from the SOURCE object but ob is the DESTINATION object
- * */
-void updateDuplicateSubtargetObjects(EditBone *dupBone,
+static void updateDuplicateSubtarget(EditBone *dup_bone,
                                      ListBase *editbones,
-                                     Object *src_ob,
-                                     Object *dst_ob)
+                                     Object *ob,
+                                     bool lookup_mirror_subtarget)
 {
-  /* If an edit bone has been duplicated, lets
-   * update it's constraints if the subtarget
-   * they point to has also been duplicated
+  /* If an edit bone has been duplicated, lets update it's constraints if the
+   * subtarget they point to has also been duplicated.
    */
   EditBone *oldtarget, *newtarget;
   bPoseChannel *pchan;
   bConstraint *curcon;
   ListBase *conlist;
 
-  if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
+  if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name))) {
     if ((conlist = &pchan->constraints)) {
       for (curcon = conlist->first; curcon; curcon = curcon->next) {
         /* does this constraint have a subtarget in
@@ -407,8 +407,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
           cti->get_constraint_targets(curcon, &targets);
 
           for (ct = targets.first; ct; ct = ct->next) {
-            if ((ct->tar == src_ob) && (ct->subtarget[0])) {
-              ct->tar = dst_ob; /* update target */
+            if ((ct->tar == ob) && (ct->subtarget[0])) {
               oldtarget = get_named_editbone(editbones, ct->subtarget);
               if (oldtarget) {
                 /* was the subtarget bone duplicated too? If
@@ -419,6 +418,17 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
                   newtarget = oldtarget->temp.ebone;
                   BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
                 }
+                else if (lookup_mirror_subtarget) {
+                  /* The subtarget was not selected for duplication, try to see if a mirror bone of
+                   * the current target exists */
+                  char name_flip[MAXBONENAME];
+
+                  BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip));
+                  newtarget = get_named_editbone(editbones, name_flip);
+                  if (newtarget) {
+                    BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+                  }
+                }
               }
             }
           }
@@ -432,32 +442,435 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
   }
 }
 
-void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+static void updateDuplicateActionConstraintSettings(EditBone *dup_bone,
+                                                    EditBone *orig_bone,
+                                                    Object *ob,
+                                                    bConstraint *curcon)
 {
-  updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+  bActionConstraint *act_con = (bActionConstraint *)curcon->data;
+  bAction *act = (bAction *)act_con->act;
+
+  float mat[4][4];
+
+  unit_m4(mat);
+  bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
+  BKE_constraint_mat_convertspace(
+      ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+  float max_axis_val = 0;
+  int max_axis = 0;
+  /* Which axis represents X now. IE, which axis defines the mirror plane. */
+  for (int i = 0; i < 3; i++) {
+    float cur_val = fabsf(mat[0][i]);
+    if (cur_val > max_axis_val) {
+      max_axis = i;
+      max_axis_val = cur_val;
+    }
+  }
+
+  /* data->type is mapped as follows for backwards compatibility:
+   * 00,01,02 - rotation (it used to be like this)
+   * 10,11,12 - scaling
+   * 20,21,22 - location
+   */
+  /* Mirror the target range */
+  if (act_con->type < 10 && act_con->type != max_axis) {
+    /* Y or Z rotation */
+    act_con->min = -act_con->min;
+    act_con->max = -act_con->max;
+  }
+  else if (act_con->type == max_axis + 10) {
+    /* X scaling */
+  }
+  else if (act_con->type == max_axis + 20) {
+    /* X location */
+    float imat[4][4];
+
+    invert_m4_m4(imat, mat);
+
+    float min_vec[3], max_vec[3];
+
+    zero_v3(min_vec);
+    zero_v3(max_vec);
+
+    min_vec[0] = act_con->min;
+    max_vec[0] = act_con->max;
+
+    /* convert values into local object space */
+    mul_m4_v3(mat, min_vec);
+    mul_m4_v3(mat, max_vec);
+
+    min_vec[0] *= -1;
+    max_vec[0] *= -1;
+
+    /* convert back to the settings space */
+    mul_m4_v3(imat, min_vec);
+    mul_m4_v3(imat, max_vec);
+
+    act_con->min = min_vec[0];
+    act_con->max = max_vec[0];
+  }
+
+  /* See if there is any channels that uses this bone */
+  ListBase ani_curves;
+  BLI_listbase_clear(&ani_curves);
+  if (list_find_data_fcurves(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) {
+    /* Create a copy and mirror the animation */
+    for (LinkData *ld = ani_curves.first; ld; ld = ld->next) {
+      FCurve *old_curve = ld->data;
+      FCurve *new_curve = copy_fcurve(old_curve);
+      bActionGroup *agrp;
+
+      char *old_path = new_curve->rna_path;
+
+      new_curve->rna_path = BLI_str_replaceN(old_path, orig_bone->name, dup_bone->name);
+      MEM_freeN(old_path);
+
+      /* Flip the animation */
+      int i;
+      BezTriple *bezt;
+      for (i = 0, bezt = new_curve->bezt; i < new_curve->totvert; i++, bezt++) {
+        const size_t slength = strlen(new_curve->rna_path);
+        bool flip = false;
+        if (BLI_strn_endswith(new_curve->rna_path, "location", slength) &&
+            new_curve->array_index == 0) {
+          flip = true;
+        }
+        else if (BLI_strn_endswith(new_curve->rna_path, "rotation_quaternion", slength) &&
+                 ELEM(new_curve->array_index, 2, 3)) {
+          flip = true;
+        }
+        else if (BLI_strn_endswith(new_curve->rna_path, "rotation_euler", slength) &&
+                 ELEM(new_curve->array_index, 1, 2)) {
+          flip = true;
+        }
+        else if (BLI_strn_endswith(new_curve->rna_path, "rotation_axis_angle", slength) &&
+                 ELEM(new_curve->array_index, 2, 3)) {
+          flip = true;
+        }
+
+        if (flip) {
+          bezt->vec[0][1] *= -1;
+          bezt->vec[1][1] *= -1;
+          bezt->vec[2][1] *= -1;
+        }
+      }
+
+      /* Make sure that a action group name for the new bone exists */
+      agrp = BKE_action_group_find_name(act, dup_bone->name);
+
+      if (agrp == NULL) {
+        agrp = action_groups_add_new(act, dup_bone->name);
+      }
+      BLI_assert(agrp != NULL);
+      action_groups_add_channel(act, agrp, new_curve);
+    }
+  }
+  BLI_freelistN(&ani_curves);
+
+  /* Make deps graph aware of our changes */
+  DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH);
 }
 
-EditBone *duplicateEditBoneObjects(
-    EditBone *curBone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+static void updateDuplicateKinematicConstraintSettings(bConstraint *curcon)
 {
-  EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+  /* IK constraint */
+  bKinematicConstraint *ik = (bKinematicConstraint *)curcon->data;
+  ik->poleangle = -M_PI - ik->poleangle;
+  /* Wrap the angle to the +/-180.0f range (default soft limit of the input boxes). */
+  ik->poleangle = angle_wrap_rad(ik->poleangle);
+}
 
-  /* Copy data from old bone to new bone */
-  memcpy(eBone, curBone, sizeof(EditBone));
+static void updateDuplicateLocRotConstraintSettings(Object *ob,
+                                                    bPoseChannel *pchan,
+                                                    bConstraint *curcon)
+{
+  /* This code assumes that bRotLimitConstraint and bLocLimitConstraint have the same fields in
+   * the same memory locations. */
+  BLI_assert(sizeof(bLocLimitConstraint) == sizeof(bRotLimitConstraint));
 
-  curBone->temp.ebone = eBone;
-  eBone->temp.ebone = curBone;
+  bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data;
+  float local_mat[4][4], imat[4][4];
 
-  if (name != NULL) {
-    BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+  float min_vec[3], max_vec[3];
+
+  min_vec[0] = limit->xmin;
+  min_vec[1] = limit->ymin;
+  min_vec[2] = limit->zmin;
+
+  max_vec[0] = limit->xmax;
+  max_vec[1] = limit->ymax;
+  max_vec[2] = limit->zmax;
+
+  unit_m4(local_mat);
+
+  BKE_constraint_mat_convertspace(
+      ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+  if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+    /* Zero out any location translation */
+    local_mat[3][0] = local_mat[3][1] = local_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list