Add deform axis for Simple Deform modifier
authorCampbell Barton <ideasman42@gmail.com>
Tue, 9 Jan 2018 03:59:45 +0000 (14:59 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 9 Jan 2018 04:09:55 +0000 (15:09 +1100)
D2989 by @dmarra w/ own edits

release/scripts/startup/bl_ui/properties_data_modifier.py
source/blender/blenloader/intern/versioning_270.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/modifiers/intern/MOD_simpledeform.c

index 7388dea215835a20648c3cd18fb05d7a31e4e771..9cd3b7435579d5b80f40c1e83758add04521b3fe 100644 (file)
@@ -848,10 +848,18 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         col.label(text="Axis, Origin:")
         col.prop(md, "origin", text="")
 
+        col.prop(md, "deform_axis")
+
         if md.deform_method in {'TAPER', 'STRETCH', 'TWIST'}:
-            col.label(text="Lock:")
-            col.prop(md, "lock_x")
-            col.prop(md, "lock_y")
+            row = col.row(align=True)
+            row.label(text="Lock:")
+            deform_axis = md.deform_axis
+            if deform_axis != 'X':
+                row.prop(md, "lock_x")
+            if deform_axis != 'Y':
+                row.prop(md, "lock_y")
+            if deform_axis != 'Z':
+                row.prop(md, "lock_z")
 
         col = split.column()
         col.label(text="Deform:")
index fa7bf0c7dee8c116dcc3bd1b449ce3d658349cf2..20475582bc96cadda49c6baa310783bdb9db1272 100644 (file)
@@ -1735,6 +1735,29 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
                }
        }
 
+       if (!MAIN_VERSION_ATLEAST(main, 279, 1)) {
+               /* Simple deform modifier no longer assumes Z axis (X for bend type).
+                * Must set previous defaults. */
+               if (!DNA_struct_elem_find(fd->filesdna, "SimpleDeformModifierData", "char", "deform_axis")) {
+                       for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+                               for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+                                       if (md->type == eModifierType_SimpleDeform) {
+                                               SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
+                                               switch (smd->mode) {
+                                                       case MOD_SIMPLEDEFORM_MODE_BEND:
+                                                               smd->deform_axis = 0;
+                                                               break;
+                                                       default:
+                                                               smd->deform_axis = 2;
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+
        {
                /* Fix for invalid state of screen due to bug in older versions. */
                for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
index fc0bf59518c76bd45404e57d66b9a17e256d4709..f7136e6e438b30d44f9b80f6a1dd1d924fcf2bc2 100644 (file)
@@ -868,8 +868,8 @@ typedef struct SimpleDeformModifierData {
 
        char mode;              /* deform function */
        char axis;              /* lock axis (for taper and strech) */
+       char deform_axis;       /* axis to perform the deform on (default is X, but can be overridden by origin */
        char flag;
-       char pad;
 
 } SimpleDeformModifierData;
 
@@ -889,6 +889,7 @@ enum {
 enum {
        MOD_SIMPLEDEFORM_LOCK_AXIS_X = (1 << 0),
        MOD_SIMPLEDEFORM_LOCK_AXIS_Y = (1 << 1),
+       MOD_SIMPLEDEFORM_LOCK_AXIS_Z = (1 << 2),
 };
 
 typedef struct ShapeKeyModifierData {
index a99c9f9d89ea28ee1990b59049c173dd8befe150..bc36af8d751adc85687592244a3fd3f33386cbea 100644 (file)
@@ -3239,6 +3239,11 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
        RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SimpleDeformModifier_vgroup_name_set");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
+       prop = RNA_def_property(srna, "deform_axis", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
+       RNA_def_property_ui_text(prop, "Axis", "Deform around local axis");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
        prop = RNA_def_property(srna, "origin", PROP_POINTER, PROP_NONE);
        RNA_def_property_ui_text(prop, "Origin", "Offset the origin and orientation of the deformation");
        RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -3268,12 +3273,17 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
 
        prop = RNA_def_property(srna, "lock_x", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_X);
-       RNA_def_property_ui_text(prop, "Lock X Axis", "Do not allow deformation along the X axis");
+       RNA_def_property_ui_text(prop, "X", "Do not allow deformation along the X axis");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
        prop = RNA_def_property(srna, "lock_y", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Y);
-       RNA_def_property_ui_text(prop, "Lock Y Axis", "Do not allow deformation along the Y axis");
+       RNA_def_property_ui_text(prop, "Y", "Do not allow deformation along the Y axis");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Z);
+       RNA_def_property_ui_text(prop, "Z", "Do not allow deformation along the Z axis");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
        prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
index 379eaea5b0c521007e8950af854e814d2f3107fd..00c1fc90d277d3a6894e56581ed5dba305b3c511 100644 (file)
@@ -32,7 +32,6 @@
  *  \ingroup modifiers
  */
 
-
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
 
 
 #define BEND_EPS 0.000001f
 
+/* Re-maps the indicies for X Y Z by shifting them up and wrapping, such that
+ * X = Y, Y = Z, Z = X (for X axis), and X = Z, Y = X, Z = Y (for Y axis). This
+ * exists because the deformations (excluding bend) are based on the Z axis.
+ * Having this helps avoid long, drawn out switches. */
+static const uint axis_map_table[3][3] = {
+       {1, 2, 0},
+       {2, 0, 1},
+       {0, 1, 2},
+};
+
+BLI_INLINE void copy_v3_v3_map(float a[3], const float b[3], const uint map[3])
+{
+       a[0] = b[map[0]];
+       a[1] = b[map[1]];
+       a[2] = b[map[2]];
+}
+
+BLI_INLINE void copy_v3_v3_unmap(float a[3], const float b[3], const uint map[3])
+{
+       a[map[0]] = b[0];
+       a[map[1]] = b[1];
+       a[map[2]] = b[2];
+}
+
 /* Clamps/Limits the given coordinate to:  limits[0] <= co[axis] <= limits[1]
  * The amount of clamp is saved on dcut */
-static void axis_limit(int axis, const float limits[2], float co[3], float dcut[3])
+static void axis_limit(const int axis, const float limits[2], float co[3], float dcut[3])
 {
        float val = co[axis];
        if (limits[0] > val) val = limits[0];
@@ -63,7 +86,7 @@ static void axis_limit(int axis, const float limits[2], float co[3], float dcut[
        co[axis] = val;
 }
 
-static void simpleDeform_taper(const float factor, const float dcut[3], float r_co[3])
+static void simpleDeform_taper(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3])
 {
        float x = r_co[0], y = r_co[1], z = r_co[2];
        float scale = z * factor;
@@ -72,14 +95,10 @@ static void simpleDeform_taper(const float factor, const float dcut[3], float r_
        r_co[1] = y + y * scale;
        r_co[2] = z;
 
-       {
-               r_co[0] += dcut[0];
-               r_co[1] += dcut[1];
-               r_co[2] += dcut[2];
-       }
+       add_v3_v3(r_co, dcut);
 }
 
-static void simpleDeform_stretch(const float factor, const float dcut[3], float r_co[3])
+static void simpleDeform_stretch(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3])
 {
        float x = r_co[0], y = r_co[1], z = r_co[2];
        float scale;
@@ -90,14 +109,10 @@ static void simpleDeform_stretch(const float factor, const float dcut[3], float
        r_co[1] = y * scale;
        r_co[2] = z * (1.0f + factor);
 
-       {
-               r_co[0] += dcut[0];
-               r_co[1] += dcut[1];
-               r_co[2] += dcut[2];
-       }
+       add_v3_v3(r_co, dcut);
 }
 
-static void simpleDeform_twist(const float factor, const float *dcut, float r_co[3])
+static void simpleDeform_twist(const float factor, const int UNUSED(axis), const float *dcut, float r_co[3])
 {
        float x = r_co[0], y = r_co[1], z = r_co[2];
        float theta, sint, cost;
@@ -110,32 +125,58 @@ static void simpleDeform_twist(const float factor, const float *dcut, float r_co
        r_co[1] = x * sint + y * cost;
        r_co[2] = z;
 
-       {
-               r_co[0] += dcut[0];
-               r_co[1] += dcut[1];
-               r_co[2] += dcut[2];
-       }
+       add_v3_v3(r_co, dcut);
 }
 
-static void simpleDeform_bend(const float factor, const float dcut[3], float r_co[3])
+static void simpleDeform_bend(const float factor, const int axis, const float dcut[3], float r_co[3])
 {
        float x = r_co[0], y = r_co[1], z = r_co[2];
        float theta, sint, cost;
 
        BLI_assert(!(fabsf(factor) < BEND_EPS));
 
-       theta = x * factor;
+       switch (axis) {
+               case 0:
+                       ATTR_FALLTHROUGH;
+               case 1:
+                       theta = z * factor;
+                       break;
+               default:
+                       theta = x * factor;
+       }
        sint = sinf(theta);
        cost = cosf(theta);
 
-       r_co[0] = -(y - 1.0f / factor) * sint;
-       r_co[1] =  (y - 1.0f / factor) * cost + 1.0f / factor;
-       r_co[2] = z;
-
-       {
-               r_co[0] += cost * dcut[0];
-               r_co[1] += sint * dcut[0];
-               r_co[2] += dcut[2];
+       switch (axis) {
+               case 0:
+                       r_co[0] =  x;
+                       r_co[1] =  (y - 1.0f / factor) * cost + 1.0f / factor;
+                       r_co[2] = -(y - 1.0f / factor) * sint;
+                       {
+                               r_co[0] += dcut[0];
+                               r_co[1] += sint * dcut[2];
+                               r_co[2] += cost * dcut[2];
+                       }
+                       break;
+               case 1:
+                       r_co[0] =  (x - 1.0f / factor) * cost + 1.0f / factor;
+                       r_co[1] =  y;
+                       r_co[2] = -(x - 1.0f / factor) * sint;
+                       {
+                               r_co[0] += sint * dcut[2];
+                               r_co[1] += dcut[1];
+                               r_co[2] += cost * dcut[2];
+                       }
+                       break;
+               default:
+                       r_co[0] = -(y - 1.0f / factor) * sint;
+                       r_co[1] =  (y - 1.0f / factor) * cost + 1.0f / factor;
+                       r_co[2] = z;
+                       {
+                               r_co[0] += cost * dcut[0];
+                               r_co[1] += sint * dcut[0];
+                               r_co[2] += dcut[2];
+                       }
        }
 
 }
@@ -145,16 +186,36 @@ static void simpleDeform_bend(const float factor, const float dcut[3], float r_c
 static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
                                     float (*vertexCos)[3], int numVerts)
 {
-       static const float lock_axis[2] = {0.0f, 0.0f};
+       const float base_limit[2] = {0.0f, 0.0f};
 
        int i;
-       int limit_axis = 0;
        float smd_limit[2], smd_factor;
        SpaceTransform *transf = NULL, tmp_transf;
-       void (*simpleDeform_callback)(const float factor, const float dcut[3], float co[3]) = NULL;  /* Mode callback */
+       void (*simpleDeform_callback)(const float factor, const int axis, const float dcut[3], float co[3]) = NULL;  /* Mode callback */
        int vgroup;
        MDeformVert *dvert;
 
+       /* This is historically the lock axis, _not_ the deform axis as the name would imply */
+       const int deform_axis = smd->deform_axis;
+       int lock_axis = smd->axis;
+       if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouln't have any lock axis */
+               lock_axis = 0;
+       }
+       else {
+               /* Don't lock axis if it is the chosen deform axis, as this flattens
+                * the geometry */
+               if (deform_axis == 0) {
+                       lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X;
+               }
+               if (deform_axis == 1) {
+                       lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y;
+               }
+               if (deform_axis == 2) {
+                       lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z;
+               }
+       }
+
+
        /* Safe-check */
        if (smd->origin == ob) smd->origin = NULL;  /* No self references */
 
@@ -169,11 +230,21 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
                BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin);
        }
 
-       /* Setup vars,
-        * Bend limits on X.. all other modes limit on Z */
-       limit_axis  = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2;
-
        /* Update limits if needed */
+       int limit_axis = deform_axis;
+       if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
+               /* Bend is a special case. */
+               switch (deform_axis) {
+                       case 0:
+                               ATTR_FALLTHROUGH;
+                       case 1:
+                               limit_axis = 2;
+                               break;
+                       default:
+                               limit_axis = 0;
+               }
+       }
+
        {
                float lower =  FLT_MAX;
                float upper = -FLT_MAX;
@@ -215,6 +286,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
 
        modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup);
        const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
+       const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2];
 
        for (i = 0; i < numVerts; i++) {
                float weight = defvert_array_find_weight_safe(dvert, i, vgroup);
@@ -232,14 +304,26 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
 
                        copy_v3_v3(co, vertexCos[i]);
 
-                       /* Apply axis limits */
-                       if (smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shoulnt have any lock axis */
-                               if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut);
-                               if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut);
+                       /* Apply axis limits, and axis mappings */
+                       if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
+                               axis_limit(0, base_limit, co, dcut);
+                       }
+                       if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
+                               axis_limit(1, base_limit, co, dcut);
+                       }
+                       if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
+                               axis_limit(2, base_limit, co, dcut);
                        }
                        axis_limit(limit_axis, smd_limit, co, dcut);
 
-                       simpleDeform_callback(smd_factor, dcut, co);  /* apply deform */
+                       /* apply the deform to a mapped copy of the vertex, and then re-map it back. */
+                       float co_remap[3];
+                       float dcut_remap[3];
+                       copy_v3_v3_map(co_remap, co, axis_map);
+                       copy_v3_v3_map(dcut_remap, dcut, axis_map);
+                       simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap);  /* apply deform */
+                       copy_v3_v3_unmap(co, co_remap, axis_map);
+
                        interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight);  /* Use vertex weight has coef of linear interpolation */
 
                        if (transf) {
@@ -257,6 +341,7 @@ static void initData(ModifierData *md)
 
        smd->mode = MOD_SIMPLEDEFORM_MODE_TWIST;
        smd->axis = 0;
+       smd->deform_axis = 0;
 
        smd->origin   =  NULL;
        smd->factor   =  DEG2RADF(45.0f);