[Bf-blender-cvs] [f4a6b5db570] temp-angavrilov-constraints: Copy Transforms: implement Invert, Fix Shear and more Mix options.

Alexander Gavrilov noreply at git.blender.org
Wed Jan 13 15:36:14 CET 2021


Commit: f4a6b5db570ad1b6df6ad43145ea4dfc2841ce67
Author: Alexander Gavrilov
Date:   Wed Nov 4 19:29:27 2020 +0300
Branches: temp-angavrilov-constraints
https://developer.blender.org/rBf4a6b5db570ad1b6df6ad43145ea4dfc2841ce67

Copy Transforms: implement Invert, Fix Shear and more Mix options.

This constraint can be naturally viewed as a prototype for a future
4x4 matrix math node (or subset thereof), since its basic semantics
already is matrix assignment. Thus it makes sense to add math options
to this constraint to increase flexibility in the meantime.

This patch adds support for several operations that would be useful:

- An option to fix shear in the incoming target matrix.
- An option to invert the target matrix.
- More ways to combine target and owner matrix.

Shear is known to cause issues for various mathematical operations,
so an option to remove it at key points is useful. In the future node
system this would be a separate operation, but due to the limits of
the constraint stack it has to be built in for now.

Inverting a matrix is also an operation that can be useful to have.
For some uses it may be useful to invert components separately, so
implement this by checking the Mix mode setting to avoid UI options.

Finally, add two more ways to combine the matrices (multiplied by
two due to the necessity for the Before/After choice). Now there
are three combine modes:

Full implements regular matrix multiplication as the most basic option.

Split Channels combines location, rotation and scale separately.
Looking at D7547 there is demand for such a mode in some cases,
and even with nodes it's cumbersome to rig manually every time.

Finally, Aligned emulates the 'anti-shear' Aligned Inherit Scale mode,
and basically uses Full for location, and Split for rotation/scale.

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

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

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/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 11ecd2068b3..9d28ca9e1ca 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -505,6 +505,8 @@ class ConstraintButtonsPanel(Panel):
 
         self.target_template(layout, con)
 
+        layout.prop(con, "fix_target_shear")
+        layout.prop(con, "invert")
         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 825ce09c75c..51ffbf7feb8 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -2232,17 +2232,62 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
   bConstraintTarget *ct = targets->first;
 
   if (VALID_CONS_TARGET(ct)) {
+    float target_mat[4][4];
+
+    copy_m4_m4(target_mat, ct->matrix);
+
+    /* Fix the shear of the target matrix if enabled.
+     * Use Y as the axis since it's the natural default for bones. */
+    if (data->flag & TRANSLIKE_FIX_TARGET_SHEAR) {
+      orthogonalize_m4_stable(target_mat, 1, false);
+    }
+
+    /* Invert the transformation. */
+    if (data->flag & TRANSLIKE_INVERT) {
+      /* For modes that split channels, split during invert too. */
+      if (ELEM(data->mix_mode,
+               TRANSLIKE_MIX_BEFORE,
+               TRANSLIKE_MIX_AFTER,
+               TRANSLIKE_MIX_BEFORE_SPLIT,
+               TRANSLIKE_MIX_AFTER_SPLIT)) {
+        invert_m4_m4_split_channels(target_mat, target_mat);
+      }
+      else {
+        invert_m4(target_mat);
+      }
+    }
+
+    /* Finally, combine the matrices. */
     switch (data->mix_mode) {
       case TRANSLIKE_MIX_REPLACE:
-        copy_m4_m4(cob->matrix, ct->matrix);
+        copy_m4_m4(cob->matrix, target_mat);
         break;
 
+      /* Simple matrix multiplication. */
+      case TRANSLIKE_MIX_BEFORE_FULL:
+        mul_m4_m4m4(cob->matrix, target_mat, cob->matrix);
+        break;
+
+      case TRANSLIKE_MIX_AFTER_FULL:
+        mul_m4_m4m4(cob->matrix, cob->matrix, target_mat);
+        break;
+
+      /* Aligned Inherit Scale emulation. */
       case TRANSLIKE_MIX_BEFORE:
-        mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
+        mul_m4_m4m4_aligned_scale(cob->matrix, target_mat, cob->matrix);
         break;
 
       case TRANSLIKE_MIX_AFTER:
-        mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
+        mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, target_mat);
+        break;
+
+      /* Fully separate handling of channels. */
+      case TRANSLIKE_MIX_BEFORE_SPLIT:
+        mul_m4_m4m4_split_channels(cob->matrix, target_mat, cob->matrix);
+        break;
+
+      case TRANSLIKE_MIX_AFTER_SPLIT:
+        mul_m4_m4m4_split_channels(cob->matrix, cob->matrix, target_mat);
         break;
 
       default:
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index d971f48c4cf..d4ee3c24f91 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -211,6 +211,7 @@ void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
 void mul_m3_v3_double(const float M[3][3], double r[3]);
 
 void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
+void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]);
 
 void mul_m3_fl(float R[3][3], float f);
 void mul_m4_fl(float R[4][4], float f);
@@ -229,6 +230,8 @@ bool invert_m4(float R[4][4]);
 bool invert_m4_m4(float R[4][4], const float A[4][4]);
 bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
 
+bool invert_m4_m4_split_channels(float R[4][4], const float A[4][4]);
+
 /* double arithmetic (mixed float/double) */
 void mul_m4_v4d(const float M[4][4], double r[4]);
 void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 6b5efc3f8c4..64f9794b613 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1286,10 +1286,32 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
 #endif
 }
 
+/**
+ * Separately inverts location, rotation and scale of the input matrix.
+ *
+ * This produces a true inversion for mul_m4_m4m4_split_channels.
+ */
+bool invert_m4_m4_split_channels(float R[4][4], const float A[4][4])
+{
+  float loc[3], rot[3][3], size[3];
+
+  mat4_to_loc_rot_size(loc, rot, size, A);
+
+  negate_v3(loc);
+  bool success = invert_m3(rot);
+  invert_v3(size);
+
+  loc_rot_size_to_mat4(R, loc, rot, size);
+  return success;
+}
+
 /**
  * Combines transformations, handling scale separately in a manner equivalent
  * to the Aligned Inherit Scale mode, in order to avoid creating shear.
  * If A scale is uniform, the result is equivalent to ordinary multiplication.
+ *
+ * Note: this effectively takes output location from simple multiplication,
+ *       and uses mul_m4_m4m4_split_channels for rotation and scale.
  */
 void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
 {
@@ -1307,6 +1329,25 @@ void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B
   loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
 }
 
+/**
+ * Separately combines location, rotation and scale of the input matrices.
+ */
+void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4])
+{
+  float loc_a[3], rot_a[3][3], size_a[3];
+  float loc_b[3], rot_b[3][3], size_b[3];
+  float loc_r[3], rot_r[3][3], size_r[3];
+
+  mat4_to_loc_rot_size(loc_a, rot_a, size_a, A);
+  mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
+
+  add_v3_v3v3(loc_r, loc_a, loc_b);
+  mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
+  mul_v3_v3v3(size_r, size_a, size_b);
+
+  loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
+}
+
 /****************************** Linear Algebra *******************************/
 
 void transpose_m3(float R[3][3])
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index fb365da6b43..fc9d991d86b 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -815,10 +815,13 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
           /* Copy Transforms constraint only does this in the Before mode. */
           bTransLikeConstraint *data = (bTransLikeConstraint *)con->data;
 
-          if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE) &&
+          if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE, TRANSLIKE_MIX_BEFORE_FULL) &&
               ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) {
             return true;
           }
+          if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE_SPLIT) && ELEM(t->mode, TFM_ROTATION)) {
+            return true;
+          }
         }
         else if (con->type == CONSTRAINT_TYPE_ACTION) {
           /* The Action constraint only does this in the Before mode. */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 20b60a52077..86544fb51fc 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -318,8 +318,9 @@ typedef struct bSameVolumeConstraint {
 /* Copy Transform Constraint */
 typedef struct bTransLikeConstraint {
   struct Object *tar;
+  int flag;
   char mix_mode;
-  char _pad[7];
+  char _pad[3];
   /** MAX_ID_NAME-2. */
   char subtarget[64];
 } bTransLikeConstraint;
@@ -814,6 +815,14 @@ typedef enum eCopyScale_Flags {
   SIZELIKE_UNIFORM = (1 << 5),
 } eCopyScale_Flags;
 
+/* bTransLikeConstraint.flag */
+typedef enum eCopyTransforms_Flags {
+  /* Invert the transformation matrix. */
+  TRANSLIKE_INVERT = (1 << 0),
+  /* Remove shear from the target matrix. */
+  TRANSLIKE_FIX_TARGET_SHEAR = (1 << 1),
+} eCopyTransforms_Flags;
+
 /* bTransLikeConstraint.mix_mode */
 typedef enum eCopyTransforms_MixMode {
   /* Replace rotation channel values. */
@@ -822,6 +831,14 @@ typedef enum eCopyTransforms_MixMode {
   TRANSLIKE_MIX_BEFORE = 1,
   /* Multiply the copied transformation on the right, with anti-shear scale handling. */
   TRANSLIKE_MIX_AFTER = 2,
+  /* Multiply the copied transformation on the left, handling loc/rot/scale separately. */
+  TRANSLIKE_MIX_BEFORE_SPLIT = 3,
+  /* Multiply the copied transformation on the right, handling loc/rot/scale separately. */
+  TRANSLIKE_MIX_AFTER_SPLIT = 4,
+  /* Multiply the copied transformation on the left, using simple matrix multiplication. */
+  TRANSLIKE_MIX_BEFORE_FULL = 5,
+  /* Multiply the copied transformation on the right, using simple matrix multiplication. */
+  TRANSLIKE_MIX_AFTER_FULL = 6,
 } eCopyTransforms_MixMode;
 
 /* bTransformConstraint.to/from */
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index eeed8d2f9b3..059b170296a 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -1629,18 +1629,48 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
        0,
        "Replace",
        "Replace the original transformation with copied"},
+      {0, "", 0, NULL, NULL},
+      {TRANSLIKE_MIX_BEFORE_FULL,
+       "BEFORE_FULL",
+       0,
+       "Before Original (Full)",
+       "Apply copied transformation before original, using simple matrix multiplication as if "
+       "the constraint target is a parent in Full Inherit Scale mode. "
+       "Will create shear when combining rotation and non-uniform scale"},
       {TRANSLIKE_MIX_BEFORE,
        "BEFORE",
        0,
-       "Before Original",
-       "Apply copied transformation before original, as if the constraint target is a parent. "
-       "Scale is handled specially to avoid creating shear"},
+       "Before Original (Aligned)",
+       "Apply cop

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list