Modifier: Mirror learns to bisect on plane

D3966 by @kioku w/ edits.

This adds bisect and flip options to mirror modifier.
This commit is contained in:
Campbell Barton
2018-11-21 10:01:04 +11:00
parent 6aa7cea3c2
commit 19875439b5
4 changed files with 196 additions and 27 deletions

View 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)

View 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 {

View 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)");

View 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;
}