[Bf-blender-cvs] [ec39d8de4ad] master: Transform: Correct Mirror for Object Mode along arbitrary axis

Henrik Dick noreply at git.blender.org
Wed Dec 2 13:29:15 CET 2020


Commit: ec39d8de4adf46161d81fb525a73278fe08a8704
Author: Henrik Dick
Date:   Wed Dec 2 09:09:26 2020 -0300
Branches: master
https://developer.blender.org/rBec39d8de4adf46161d81fb525a73278fe08a8704

Transform: Correct Mirror for Object Mode along arbitrary axis

This fixes T68521, T82334.

The object are not properly mirrored in object mode.

For mirroring an object that has an arbitrary rotation along the X axis
this is the procedure:
1. mirror x location.
2. negate x scale of the
3. negate y and z component of the rotation (independent of which rotation mode is used).

This knowledge applies now for all angles and axes to finally make the
mirror operation work in object mode.

The new mirror function has the downside that it can not (in this form)
be used with proportional editing.

This is no problem since the old behavior can still be replicated by
scaling with -1 along any axis.

The solution to get perfect mirrors can not work for scaling in general,
because in that case there could be scew created.

Reviewed By: mano-wii

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

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

M	source/blender/editors/transform/transform_mode.c
M	source/blender/editors/transform/transform_mode.h
M	source/blender/editors/transform/transform_mode_mirror.c
M	source/blender/editors/transform/transform_ops.c

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

diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index af0a8e5e505..a4d999b868d 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -228,7 +228,7 @@ static void protectedAxisAngleBits(
   }
 }
 
-static void protectedSizeBits(short protectflag, float size[3])
+void protectedSizeBits(short protectflag, float size[3])
 {
   if (protectflag & OB_LOCK_SCALEX) {
     size[0] = 1.0f;
@@ -431,7 +431,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
   }
 }
 
-static void constraintSizeLim(TransInfo *t, TransData *td)
+void constraintSizeLim(TransInfo *t, TransData *td)
 {
   if (td->con && td->ext) {
     const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index df7d10d1028..7a05506e12c 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -44,7 +44,9 @@ int transform_mode_really_used(struct bContext *C, int mode);
 bool transdata_check_local_center(TransInfo *t, short around);
 bool transform_mode_is_changeable(const int mode);
 void protectedTransBits(short protectflag, float vec[3]);
+void protectedSizeBits(short protectflag, float size[3]);
 void constraintTransLim(TransInfo *t, TransData *td);
+void constraintSizeLim(TransInfo *t, TransData *td);
 void postInputRotation(TransInfo *t, float values[3]);
 void headerRotation(TransInfo *t, char *str, float final);
 void ElementRotation_ex(TransInfo *t,
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 1440553de51..3aa99975fda 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -24,8 +24,10 @@
 #include <stdlib.h>
 
 #include "BLI_math.h"
+#include "BLI_math_bits.h"
 #include "BLI_string.h"
 
+#include "BKE_armature.h"
 #include "BKE_context.h"
 
 #include "ED_screen.h"
@@ -41,9 +43,130 @@
 /** \name Transform (Mirror)
  * \{ */
 
+/**
+ * Mirrors an object by negating the scale of the object on the mirror axis, reflecting the
+ * location and adjusting the rotation.
+ *
+ * \param axis: Either the axis to mirror on (0 = x, 1 = y, 2 = z) in transform space or -1 for no
+ * axis mirror.
+ * \param flip: If true, a mirror on all axis will be performed additionally (point
+ * reflection).
+ */
+static void ElementMirror(TransInfo *t, TransDataContainer *tc, TransData *td, int axis, bool flip)
+{
+  if ((t->flag & T_V3D_ALIGN) == 0 && td->ext) {
+    /* Size checked needed since the 3D cursor only uses rotation fields. */
+    if (td->ext->size) {
+      float fsize[] = {1.0, 1.0, 1.0};
+
+      if (axis >= 0) {
+        fsize[axis] = -fsize[axis];
+      }
+      if (flip) {
+        negate_v3(fsize);
+      }
+
+      protectedSizeBits(td->protectflag, fsize);
+
+      mul_v3_v3v3(td->ext->size, td->ext->isize, fsize);
+
+      constraintSizeLim(t, td);
+    }
+
+    float rmat[3][3];
+    if (axis >= 0) {
+      float imat[3][3];
+      mul_m3_m3m3(rmat, t->spacemtx_inv, td->axismtx);
+      rmat[axis][0] = -rmat[axis][0];
+      rmat[axis][1] = -rmat[axis][1];
+      rmat[axis][2] = -rmat[axis][2];
+      rmat[0][axis] = -rmat[0][axis];
+      rmat[1][axis] = -rmat[1][axis];
+      rmat[2][axis] = -rmat[2][axis];
+      invert_m3_m3(imat, td->axismtx);
+      mul_m3_m3m3(rmat, rmat, imat);
+      mul_m3_m3m3(rmat, t->spacemtx, rmat);
+
+      ElementRotation_ex(t, tc, td, rmat, td->center);
+
+      if (td->ext->rotAngle) {
+        *td->ext->rotAngle = -td->ext->irotAngle;
+      }
+    }
+    else {
+      unit_m3(rmat);
+      ElementRotation_ex(t, tc, td, rmat, td->center);
+
+      if (td->ext->rotAngle) {
+        *td->ext->rotAngle = td->ext->irotAngle;
+      }
+    }
+  }
+
+  if ((td->flag & TD_NO_LOC) == 0) {
+    float center[3], vec[3];
+
+    /* Local constraint shouldn't alter center. */
+    if (transdata_check_local_center(t, t->around)) {
+      copy_v3_v3(center, td->center);
+    }
+    else if (t->options & CTX_MOVIECLIP) {
+      if (td->flag & TD_INDIVIDUAL_SCALE) {
+        copy_v3_v3(center, td->center);
+      }
+      else {
+        copy_v3_v3(center, tc->center_local);
+      }
+    }
+    else {
+      copy_v3_v3(center, tc->center_local);
+    }
+
+    /* For individual element center, Editmode need to use iloc. */
+    if (t->flag & T_POINTS) {
+      sub_v3_v3v3(vec, td->iloc, center);
+    }
+    else {
+      sub_v3_v3v3(vec, td->center, center);
+    }
+
+    if (axis >= 0) {
+      /* Always do the mirror in global space. */
+      if (t->flag & T_EDIT) {
+        mul_m3_v3(td->mtx, vec);
+      }
+      reflect_v3_v3v3(vec, vec, t->spacemtx[axis]);
+      if (t->flag & T_EDIT) {
+        mul_m3_v3(td->smtx, vec);
+      }
+    }
+    if (flip) {
+      negate_v3(vec);
+    }
+
+    add_v3_v3(vec, center);
+    if (t->flag & T_POINTS) {
+      sub_v3_v3(vec, td->iloc);
+    }
+    else {
+      sub_v3_v3(vec, td->center);
+    }
+
+    if (t->flag & (T_OBJECT | T_POSE)) {
+      mul_m3_v3(td->smtx, vec);
+    }
+
+    protectedTransBits(td->protectflag, vec);
+    if (td->loc) {
+      add_v3_v3v3(td->loc, td->iloc, vec);
+    }
+
+    constraintTransLim(t, td);
+  }
+}
+
 static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
 {
-  float size[3], mat[3][3];
   int i;
   char str[UI_MAX_DRAW_STR];
   copy_v3_v3(t->values_final, t->values);
@@ -54,12 +177,16 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
 
   /* if an axis has been selected */
   if (t->con.mode & CON_APPLY) {
-    size[0] = size[1] = size[2] = -1;
-
-    size_to_mat3(mat, size);
-
-    if (t->con.applySize) {
-      t->con.applySize(t, NULL, NULL, mat);
+    /* #special_axis is either the constraint plane normal or the constraint axis.
+     * Assuming that CON_AXIS0 < CON_AXIS1 < CON_AXIS2 and CON_AXIS2 is CON_AXIS0 << 2 */
+    BLI_assert(CON_AXIS2 == CON_AXIS0 << 2);
+    int axis_bitmap = (t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) / CON_AXIS0;
+    int special_axis_bitmap = 0;
+    int special_axis = -1;
+    int bitmap_len = count_bits_i(axis_bitmap);
+    if (LIKELY(!ELEM(bitmap_len, 0, 3))) {
+      special_axis_bitmap = (bitmap_len == 2) ? ~axis_bitmap : axis_bitmap;
+      special_axis = bitscan_forward_i(special_axis_bitmap);
     }
 
     BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text);
@@ -71,7 +198,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
           continue;
         }
 
-        ElementResize(t, tc, td, mat);
+        ElementMirror(t, tc, td, special_axis, bitmap_len >= 2);
       }
     }
 
@@ -80,10 +207,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
     ED_area_status_text(t->area, str);
   }
   else {
-    size[0] = size[1] = size[2] = 1;
-
-    size_to_mat3(mat, size);
-
     FOREACH_TRANS_DATA_CONTAINER (t, tc) {
       TransData *td = tc->data;
       for (i = 0; i < tc->data_len; i++, td++) {
@@ -91,7 +214,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
           continue;
         }
 
-        ElementResize(t, tc, td, mat);
+        ElementMirror(t, tc, td, -1, false);
       }
     }
 
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index aeb34e34d97..7282c35ea0f 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -1040,8 +1040,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
   ot->poll = ED_operator_screenactive;
   ot->poll_property = transform_poll_property;
 
-  Transform_Properties(
-      ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER);
+  Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_GPENCIL_EDIT | P_CENTER);
 }
 
 static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot)



More information about the Bf-blender-cvs mailing list