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:
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user