[Bf-blender-cvs] [f4056e9ec3a] master: Copy Rotation: implement new mixing modes that actually work.

Alexander Gavrilov noreply at git.blender.org
Fri Sep 6 07:18:51 CEST 2019


Commit: f4056e9ec3a89afbc592af3e3d169d2d584a9937
Author: Alexander Gavrilov
Date:   Wed Sep 4 12:06:59 2019 +0300
Branches: master
https://developer.blender.org/rBf4056e9ec3a89afbc592af3e3d169d2d584a9937

Copy Rotation: implement new mixing modes that actually work.

Upon close inspection, the way the Offset mode works in the
Copy Rotation constraint makes no sense, and in fact, destroys
the rotation of its owner unless either it's single axis, or
the order is set specifically to `ZYX Euler`.

Since it can't simply be changed because of backward compatibility
concerns, replace the checkbox with a dropdown that provides a set
of new modes that actually make sense.

Specifically, add a mode that simply adds Euler components together,
and two options that use matrix multiplication in different order.

The Python use_offset property is replaced with compatibility stubs.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D5640

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

M	release/scripts/startup/bl_ui/properties_constraint.py
M	source/blender/blenkernel/intern/constraint.c
M	source/blender/blenlib/BLI_math_matrix.h
M	source/blender/blenlib/intern/math_matrix.c
M	source/blender/blenloader/intern/versioning_280.c
M	source/blender/editors/transform/transform_convert.c
M	source/blender/makesdna/DNA_constraint_types.h
M	source/blender/makesrna/intern/rna_constraint.c

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

diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 0ba9fd0630c..ac1ebedeba4 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -392,7 +392,7 @@ class ConstraintButtonsPanel:
         sub.active = con.use_z
         sub.prop(con, "invert_z", text="Invert")
 
-        layout.prop(con, "use_offset")
+        layout.prop(con, "mix_mode", text="Mix")
 
         self.space_template(layout, con)
 
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index ccacb85651c..803aae76422 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -1802,12 +1802,10 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
   bConstraintTarget *ct = targets->first;
 
   if (VALID_CONS_TARGET(ct)) {
-    float loc[3];
-    float eul[3], obeul[3];
-    float size[3];
+    float loc[3], size[3], oldrot[3][3], newrot[3][3];
+    float eul[3], obeul[3], defeul[3];
 
-    copy_v3_v3(loc, cob->matrix[3]);
-    mat4_to_size(size, cob->matrix);
+    mat4_to_loc_rot_size(loc, oldrot, size, cob->matrix);
 
     /* Select the Euler rotation order, defaulting to the owner. */
     short rot_order = cob->rotOrder;
@@ -1822,11 +1820,28 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
      * some of them can be modified below (see bug T21875). */
     mat4_to_compatible_eulO(eul, obeul, rot_order, ct->matrix);
 
+    /* Prepare the copied euler rotation. */
+    bool legacy_offset = false;
+
+    switch (data->mix_mode) {
+      case ROTLIKE_MIX_OFFSET:
+        legacy_offset = true;
+        copy_v3_v3(defeul, obeul);
+        break;
+
+      case ROTLIKE_MIX_REPLACE:
+        copy_v3_v3(defeul, obeul);
+        break;
+
+      default:
+        zero_v3(defeul);
+    }
+
     if ((data->flag & ROTLIKE_X) == 0) {
-      eul[0] = obeul[0];
+      eul[0] = defeul[0];
     }
     else {
-      if (data->flag & ROTLIKE_OFFSET) {
+      if (legacy_offset) {
         rotate_eulO(eul, rot_order, 'X', obeul[0]);
       }
 
@@ -1836,10 +1851,10 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
     }
 
     if ((data->flag & ROTLIKE_Y) == 0) {
-      eul[1] = obeul[1];
+      eul[1] = defeul[1];
     }
     else {
-      if (data->flag & ROTLIKE_OFFSET) {
+      if (legacy_offset) {
         rotate_eulO(eul, rot_order, 'Y', obeul[1]);
       }
 
@@ -1849,10 +1864,10 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
     }
 
     if ((data->flag & ROTLIKE_Z) == 0) {
-      eul[2] = obeul[2];
+      eul[2] = defeul[2];
     }
     else {
-      if (data->flag & ROTLIKE_OFFSET) {
+      if (legacy_offset) {
         rotate_eulO(eul, rot_order, 'Z', obeul[2]);
       }
 
@@ -1861,10 +1876,36 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
       }
     }
 
+    /* Add the euler components together if needed. */
+    if (data->mix_mode == ROTLIKE_MIX_ADD) {
+      add_v3_v3(eul, obeul);
+    }
+
     /* Good to make eulers compatible again,
      * since we don't know how much they were changed above. */
     compatible_eul(eul, obeul);
-    loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order);
+    eulO_to_mat3(newrot, eul, rot_order);
+
+    /* Mix the rotation matrices: */
+    switch (data->mix_mode) {
+      case ROTLIKE_MIX_REPLACE:
+      case ROTLIKE_MIX_OFFSET:
+      case ROTLIKE_MIX_ADD:
+        break;
+
+      case ROTLIKE_MIX_BEFORE:
+        mul_m3_m3m3(newrot, newrot, oldrot);
+        break;
+
+      case ROTLIKE_MIX_AFTER:
+        mul_m3_m3m3(newrot, oldrot, newrot);
+        break;
+
+      default:
+        BLI_assert(false);
+    }
+
+    loc_rot_size_to_mat4(cob->matrix, loc, newrot, size);
   }
 }
 
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 00c301a01bc..814b13fa47f 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -310,7 +310,7 @@ void mat4_to_size_fix_shear(float r[3], const float M[4][4]);
 
 void translate_m4(float mat[4][4], float tx, float ty, float tz);
 void rotate_m4(float mat[4][4], const char axis, const float angle);
-void rescale_m4(float mat[4][4], float scale[3]);
+void rescale_m4(float mat[4][4], const float scale[3]);
 void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
 
 void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
@@ -320,6 +320,10 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
 
 void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
 
+void loc_rot_size_to_mat4(float R[4][4],
+                          const float loc[3],
+                          const float rot[3][3],
+                          const float size[3]);
 void loc_eul_size_to_mat4(float R[4][4],
                           const float loc[3],
                           const float eul[3],
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 7c1b44978e2..e9d196ccdbb 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2164,7 +2164,7 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
 }
 
 /** Scale a matrix in-place. */
-void rescale_m4(float mat[4][4], float scale[3])
+void rescale_m4(float mat[4][4], const float scale[3])
 {
   mul_v3_fl(mat[0], scale[0]);
   mul_v3_fl(mat[1], scale[1]);
@@ -2356,6 +2356,20 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
           equals_v4v4(mat1[2], mat2[2]) && equals_v4v4(mat1[3], mat2[3]));
 }
 
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
+void loc_rot_size_to_mat4(float mat[4][4],
+                          const float loc[3],
+                          const float rot[3][3],
+                          const float size[3])
+{
+  copy_m4_m3(mat, rot);
+  rescale_m4(mat, size);
+  copy_v3_v3(mat[3], loc);
+}
+
 /**
  * Make a 4x4 matrix out of 3 transform components.
  * Matrices are made in the order: `scale * rot * loc`
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 54d2bd8499f..0d108704b4e 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -727,6 +727,17 @@ static void do_version_constraints_copy_scale_power(ListBase *lb)
   }
 }
 
+static void do_version_constraints_copy_rotation_mix_mode(ListBase *lb)
+{
+  for (bConstraint *con = lb->first; con; con = con->next) {
+    if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+      bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
+      data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE;
+      data->flag &= ~ROTLIKE_OFFSET;
+    }
+  }
+}
+
 static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase)
 {
   for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
@@ -3797,5 +3808,17 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
         do_version_bones_inherit_scale(&arm->bonebase);
       }
     }
+
+    /* Convert the Offset flag to the mix mode enum. */
+    if (!DNA_struct_elem_find(fd->filesdna, "bRotateLikeConstraint", "char", "mix_mode")) {
+      LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+        do_version_constraints_copy_rotation_mix_mode(&ob->constraints);
+        if (ob->pose) {
+          LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+            do_version_constraints_copy_rotation_mix_mode(&pchan->constraints);
+          }
+        }
+      }
+    }
   }
 }
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 69bc6afd23f..14eee2318cd 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -1330,7 +1330,8 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
           /* CopyRot constraint only does this when rotating, and offset is on */
           bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
 
-          if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION)) {
+          if (ELEM(data->mix_mode, ROTLIKE_MIX_OFFSET, ROTLIKE_MIX_BEFORE) &&
+              ELEM(t->mode, TFM_ROTATION)) {
             return true;
           }
         }
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 42d58cb34d0..a7f900ddc9b 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -272,7 +272,8 @@ typedef struct bRotateLikeConstraint {
   struct Object *tar;
   int flag;
   char euler_order;
-  char _pad[3];
+  char mix_mode;
+  char _pad[2];
   /** MAX_ID_NAME-2. */
   char subtarget[64];
 } bRotateLikeConstraint;
@@ -747,9 +748,25 @@ typedef enum eCopyRotation_Flags {
   ROTLIKE_X_INVERT = (1 << 4),
   ROTLIKE_Y_INVERT = (1 << 5),
   ROTLIKE_Z_INVERT = (1 << 6),
+#ifdef DNA_DEPRECATED
   ROTLIKE_OFFSET = (1 << 7),
+#endif
 } eCopyRotation_Flags;
 
+/* bRotateLikeConstraint.mix_mode */
+typedef enum eCopyRotation_MixMode {
+  /* Replace rotation channel values. */
+  ROTLIKE_MIX_REPLACE = 0,
+  /* Legacy Offset mode - don't use. */
+  ROTLIKE_MIX_OFFSET,
+  /* Add Euler components together. */
+  ROTLIKE_MIX_ADD,
+  /* Multiply the copied rotation on the left. */
+  ROTLIKE_MIX_BEFORE,
+  /* Multiply the copied rotation on the right. */
+  ROTLIKE_MIX_AFTER,
+} eCopyRotation_MixMode;
+
 /* bLocateLikeConstraint.flag */
 typedef enum eCopyLocation_Flags {
   LOCLIKE_X = (1 << 0),
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 05154dcc20e..79e38717569 100644
--- a/

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list