Modifier: Mirror learns to bisect on plane
authorCampbell Barton <ideasman42@gmail.com>
Tue, 20 Nov 2018 23:01:04 +0000 (10:01 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 20 Nov 2018 23:01:04 +0000 (10:01 +1100)
D3966 by @kioku w/ edits.

This adds bisect and flip options to mirror modifier.

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

index 172fe07eab3ff7e19542ac14537db3fa74fad5b0..1dd3c545b791b2bf1812f18c653a9a66fe8d3e4c 100644 (file)
@@ -569,7 +569,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
             layout.operator("object.meshdeform_bind", text="Bind")
 
     def MIRROR(self, layout, ob, md):
-        split = layout.split(factor=0.25)
+        split = layout.split(factor=0.33)
 
         col = split.column()
         col.label(text="Axis:")
@@ -578,15 +578,66 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         col.prop(md, "use_z")
 
         col = split.column()
-        col.label(text="Options:")
-        col.prop(md, "use_mirror_merge", text="Merge")
-        col.prop(md, "use_clip", text="Clipping")
-        col.prop(md, "use_mirror_vertex_groups", text="Vertex Groups")
+        col.label(text="Bisect:")
+
+        col_x = col.column()
+        col_x.prop(md, "use_bisect_x")
+        col_x.active = md.use_x
+
+        col_y = col.column()
+        col_y.prop(md, "use_bisect_y")
+        col_y.active = md.use_y
+
+        col_z = col.column()
+        col_z.prop(md, "use_bisect_z")
+        col_z.active = md.use_z
 
         col = split.column()
+        col.label(text="Flip:")
+
+        col_fx = col.column()
+        col_fx.prop(md, "flip_x")
+        col_fx.active = md.use_bisect_x and md.use_x
+
+        col_fy = col.column()
+        col_fy.prop(md, "flip_y")
+        col_fy.active = md.use_bisect_y and md.use_y
+
+        col_fz = col.column()
+        col_fz.prop(md, "flip_z")
+        col_fz.active = md.use_bisect_z and md.use_z
+
+        layout.separator()
+
+        col = layout.column()
+        col.label(text="Mirror Object:")
+        col.prop(md, "mirror_object", text="")
+
+        layout.separator()
+
+        col = layout.column()
+        col.label(text="Options:")
+
+        row = layout.row()
+        row.prop(md, "use_mirror_vertex_groups", text="Vertex Groups")
+        row.prop(md, "use_clip", text="Clipping")
+        row = layout.row()
+        row.prop(md, "use_mirror_merge", text="Merge")
+
+        col = layout.column()
+        if md.use_mirror_merge is True:
+            col.prop(md, "merge_threshold")
+
+        layout.separator()
+        col = layout.column()
+
+
+        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
         col.label(text="Textures:")
-        col.prop(md, "use_mirror_u", text="Flip U")
-        col.prop(md, "use_mirror_v", text="Flip V")
+        row = layout.row()
+        row.prop(md, "use_mirror_u", text="Flip U")
+        row.prop(md, "use_mirror_v", text="Flip V")
 
         col = layout.column(align=True)
 
@@ -600,12 +651,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         col.prop(md, "offset_u")
         col.prop(md, "offset_v")
 
-        col = layout.column()
-
-        if md.use_mirror_merge is True:
-            col.prop(md, "merge_threshold")
-        col.label(text="Mirror Object:")
-        col.prop(md, "mirror_object", text="")
 
     def MULTIRES(self, layout, ob, md):
         layout.row().prop(md, "subdivision_type", expand=True)
index 4eb9f890be022959cbfecba76b1f60e64877ae77..e2f963b7a1b1ad92ffd72ec3cd0d06d065c8a8b4 100644 (file)
@@ -313,14 +313,20 @@ typedef struct MirrorModifierData {
 
 /* MirrorModifierData->flag */
 enum {
-       MOD_MIR_CLIPPING  = (1 << 0),
-       MOD_MIR_MIRROR_U  = (1 << 1),
-       MOD_MIR_MIRROR_V  = (1 << 2),
-       MOD_MIR_AXIS_X    = (1 << 3),
-       MOD_MIR_AXIS_Y    = (1 << 4),
-       MOD_MIR_AXIS_Z    = (1 << 5),
-       MOD_MIR_VGROUP    = (1 << 6),
-       MOD_MIR_NO_MERGE  = (1 << 7),
+       MOD_MIR_CLIPPING      = (1 << 0),
+       MOD_MIR_MIRROR_U      = (1 << 1),
+       MOD_MIR_MIRROR_V      = (1 << 2),
+       MOD_MIR_AXIS_X        = (1 << 3),
+       MOD_MIR_AXIS_Y        = (1 << 4),
+       MOD_MIR_AXIS_Z        = (1 << 5),
+       MOD_MIR_VGROUP        = (1 << 6),
+       MOD_MIR_NO_MERGE      = (1 << 7),
+       MOD_MIR_BISECT_AXIS_X = (1 << 8),
+       MOD_MIR_BISECT_AXIS_Y = (1 << 9),
+       MOD_MIR_BISECT_AXIS_Z = (1 << 10),
+       MOD_MIR_FLIP_AXIS_X   = (1 << 11),
+       MOD_MIR_FLIP_AXIS_Y   = (1 << 12),
+       MOD_MIR_FLIP_AXIS_Z   = (1 << 13),
 };
 
 typedef struct EdgeSplitModifierData {
index b633dd907ae6b659bb79734c599dc3e9811dd13d..c2fa89891b019a81fd6b2752c68a6198e270d724 100644 (file)
@@ -1561,6 +1561,36 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Clip", "Prevent vertices from going through the mirror during transform");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
+       prop = RNA_def_property(srna, "use_bisect_x", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_BISECT_AXIS_X);
+       RNA_def_property_ui_text(prop, "X", "Cuts the mesh across the mirrorplane");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "use_bisect_y", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_BISECT_AXIS_Y);
+       RNA_def_property_ui_text(prop, "Y", "Cuts the mesh across the mirrorplane");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "use_bisect_z", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_BISECT_AXIS_Z);
+       RNA_def_property_ui_text(prop, "Z", "Cuts the mesh across the mirrorplane");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "flip_x", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_FLIP_AXIS_X);
+       RNA_def_property_ui_text(prop, "X", "Flips the direction of the slice");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "flip_y", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_FLIP_AXIS_Y);
+       RNA_def_property_ui_text(prop, "Y", "Flips the direction of the slice");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "flip_z", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_FLIP_AXIS_Z);
+       RNA_def_property_ui_text(prop, "Z", "Flips the direction of the slice");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
        prop = RNA_def_property(srna, "use_mirror_vertex_groups", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_VGROUP);
        RNA_def_property_ui_text(prop, "Mirror Vertex Groups", "Mirror vertex groups (e.g. .R->.L)");
index d4e02a437d797537e24b10d3030ea94d642557d6..df08122aebf0db61039136e46f04031fb07b3947 100644 (file)
@@ -45,6 +45,9 @@
 #include "BKE_modifier.h"
 #include "BKE_deform.h"
 
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
 #include "MEM_guardedalloc.h"
 
 #include "DEG_depsgraph_build.h"
@@ -78,21 +81,90 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
        DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
 }
 
-static Mesh *doMirrorOnAxis(
+static Mesh *doBiscetOnMirrorPlane(
         MirrorModifierData *mmd,
         Object *ob,
         const Mesh *mesh,
-        int axis)
+        int axis,
+        float mirrormat[4][4])
+{
+       bool do_flip_axis = (
+               (axis == 0 && mmd->flag & MOD_MIR_FLIP_AXIS_X) ||
+               (axis == 1 && mmd->flag & MOD_MIR_FLIP_AXIS_Y) ||
+               (axis == 2 && mmd->flag & MOD_MIR_FLIP_AXIS_Z));
+
+       const float bisect_distance = 0.001;
+
+       Mesh *result;
+       BMesh *bm;
+       BMIter viter;
+       BMVert *v, *v_next;
+
+       bm = BKE_mesh_to_bmesh_ex(
+               mesh,
+               &(struct BMeshCreateParams){0},
+               &(struct BMeshFromMeshParams){
+                       .calc_face_normal = true,
+                       .cd_mask_extra = CD_MASK_ORIGINDEX,
+               });
+
+       /* prepare data for bisecting */
+       float plane[4];
+       float plane_co[3] = {0, 0, 0};
+       float plane_no[3];
+       copy_v3_v3(plane_no, mirrormat[axis]);
+
+       if (mmd->mirror_ob) {
+               float tmp[4][4];
+               invert_m4_m4(tmp, ob->obmat);
+               mul_m4_m4m4(tmp, tmp, mmd->mirror_ob->obmat);
+
+               copy_v3_v3(plane_no, tmp[axis]);
+               copy_v3_v3(plane_co, tmp[3]);
+       }
+
+       plane_from_point_normal_v3(plane, plane_co, plane_no);
+
+       BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+
+       /* Plane definitions for vert killing. */
+       float plane_offset[4];
+       copy_v3_v3(plane_offset, plane);
+       plane_offset[3] = plane[3] - bisect_distance;
+
+       if (do_flip_axis) {
+               negate_v3(plane_offset);
+       }
+
+       /* Delete verts across the mirror plane. */
+       BM_ITER_MESH_MUTABLE(v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
+               if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
+                       BM_vert_kill(bm, v);
+               }
+       }
+
+       result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
+       BM_mesh_free(bm);
+
+       return result;
+}
+
+static Mesh *doMirrorOnAxis(
+       MirrorModifierData *mmd,
+       Object *ob,
+       const Mesh *mesh,
+       int axis)
 {
        const float tolerance_sq = mmd->tolerance * mmd->tolerance;
        const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
        int tot_vtargetmap = 0;  /* total merge vertices */
 
+       const bool do_bisect = (
+               (axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
+               (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
+               (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
+
        Mesh *result;
-       const int maxVerts = mesh->totvert;
-       const int maxEdges = mesh->totedge;
-       const int maxLoops = mesh->totloop;
-       const int maxPolys = mesh->totpoly;
        MVert *mv, *mv_prev;
        MEdge *me;
        MLoop *ml;
@@ -125,6 +197,18 @@ static Mesh *doMirrorOnAxis(
                mul_m4_m4m4(mtx, itmp, mtx);
        }
 
+
+       Mesh *mesh_bisect = NULL;
+       if (do_bisect) {
+               mesh_bisect = doBiscetOnMirrorPlane(mmd, ob, mesh, axis, mtx);
+               mesh = mesh_bisect;
+       }
+
+       const int maxVerts = mesh->totvert;
+       const int maxEdges = mesh->totedge;
+       const int maxLoops = mesh->totloop;
+       const int maxPolys = mesh->totpoly;
+
        result = BKE_mesh_new_nomain_from_template(
                mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
 
@@ -290,6 +374,10 @@ static Mesh *doMirrorOnAxis(
                MEM_freeN(vtargetmap);
        }
 
+       if (mesh_bisect != NULL) {
+               BKE_id_free(NULL, mesh_bisect);
+       }
+
        return result;
 }