Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_mirror.c
| Show All 32 Lines | |||||
| */ | */ | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_utildefines_stack.h" | |||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_library_query.h" | #include "BKE_library_query.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_editmesh.h" | |||||
| #include "bmesh.h" | |||||
| #include "bmesh_tools.h" | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DEG_depsgraph_build.h" | #include "DEG_depsgraph_build.h" | ||||
| #include "MOD_modifiertypes.h" | #include "MOD_modifiertypes.h" | ||||
| #define ELE_NEW 1 | |||||
| #define ELE_CUT 2 | |||||
| static void initData(ModifierData *md) | static void initData(ModifierData *md) | ||||
| { | { | ||||
| MirrorModifierData *mmd = (MirrorModifierData *) md; | MirrorModifierData *mmd = (MirrorModifierData *) md; | ||||
| mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP); | mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP); | ||||
| mmd->tolerance = 0.001; | mmd->tolerance = 0.001; | ||||
| mmd->mirror_ob = NULL; | mmd->mirror_ob = NULL; | ||||
| } | } | ||||
| Show All 11 Lines | |||||
| { | { | ||||
| MirrorModifierData *mmd = (MirrorModifierData *)md; | MirrorModifierData *mmd = (MirrorModifierData *)md; | ||||
| if (mmd->mirror_ob != NULL) { | if (mmd->mirror_ob != NULL) { | ||||
| DEG_add_object_relation(ctx->node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); | DEG_add_object_relation(ctx->node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); | ||||
| } | } | ||||
| DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); | DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); | ||||
| } | } | ||||
| static Mesh *biscetAlongMirrorPlane( | |||||
| MirrorModifierData *mmd, | |||||
| Object *ob, | |||||
| const Mesh *mesh, | |||||
| int axis, | |||||
| float mirrormat[4][4]) | |||||
| { | |||||
| const float threshold = 0.0001; | |||||
campbellbarton: Might want this to be user editable, not essential for initial patch. | |||||
| 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)); | |||||
| Mesh *result; | |||||
| BMesh *bm; | |||||
| BMIter iter; | |||||
| BMVert *v; | |||||
| bm = BKE_mesh_to_bmesh_ex( | |||||
| mesh, | |||||
| &(struct BMeshCreateParams){ | |||||
| .use_toolflags = 0, | |||||
| }, | |||||
| &(struct BMeshFromMeshParams){ | |||||
| .calc_face_normal = true, | |||||
| .add_key_index = false, | |||||
| .use_shapekey = true, | |||||
| .active_shapekey = ob->shapenr, | |||||
| .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]); | |||||
| } | |||||
| else if (mmd->flag & MOD_MIR_WORLD_ORIGIN) { | |||||
| float tmp[4][4]; | |||||
| invert_m4_m4(tmp, 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, ELE_CUT, ELE_NEW, threshold); | |||||
| /* plane definitions for vert killing */ | |||||
| float plane_offset[4]; | |||||
| float plane_offset_flip[4]; | |||||
| copy_v3_v3(plane_offset, plane); | |||||
| copy_v3_v3(plane_offset_flip, plane); | |||||
| plane_offset[3] = plane[3] - threshold; | |||||
| plane_offset_flip[3] = plane[3] + threshold; | |||||
| /* delete verts across the mirror plane */ | |||||
| const int vert_arr_max = bm->totvert; | |||||
| BMVert **vert_arr = MEM_mallocN(sizeof(*vert_arr) * (size_t)vert_arr_max, __func__); | |||||
| STACK_DECLARE(vert_arr); | |||||
| STACK_INIT(vert_arr, vert_arr_max); | |||||
| BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { | |||||
campbellbartonUnsubmitted Done Inline ActionsIt's possible to avoid building an array and delete immediately using BM_ITER_MESH_MUTABLE. campbellbarton: It's possible to avoid building an array and delete immediately using `BM_ITER_MESH_MUTABLE`. | |||||
| if (do_flip_axis) { | |||||
| if (plane_point_side_v3(plane_offset_flip, v->co) < 0.0f) { | |||||
| STACK_PUSH(vert_arr, v); | |||||
| } | |||||
| } | |||||
| else if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { | |||||
| STACK_PUSH(vert_arr, v); | |||||
| } | |||||
| } | |||||
| while ((v = STACK_POP(vert_arr))) { | |||||
| BM_vert_kill(bm, v); | |||||
| } | |||||
| MEM_freeN(vert_arr); | |||||
| result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0); | |||||
| BM_mesh_free(bm); | |||||
| return result; | |||||
| } | |||||
| static Mesh *doMirrorOnAxis( | static Mesh *doMirrorOnAxis( | ||||
| MirrorModifierData *mmd, | MirrorModifierData *mmd, | ||||
| Object *ob, | Object *ob, | ||||
| const Mesh *mesh, | const Mesh *mesh, | ||||
| int axis) | int axis) | ||||
| { | { | ||||
| const float tolerance_sq = mmd->tolerance * mmd->tolerance; | const float tolerance_sq = mmd->tolerance * mmd->tolerance; | ||||
| const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0; | const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0; | ||||
| int tot_vtargetmap = 0; /* total merge vertices */ | 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; | 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; | MVert *mv, *mv_prev; | ||||
| MEdge *me; | MEdge *me; | ||||
| MLoop *ml; | MLoop *ml; | ||||
| MPoly *mp; | MPoly *mp; | ||||
| float mtx[4][4]; | float mtx[4][4]; | ||||
| int i; | int i; | ||||
| int a, totshape; | int a, totshape; | ||||
| int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; | int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; | ||||
| /* mtx is the mirror transformation */ | /* mtx is the mirror transformation */ | ||||
| unit_m4(mtx); | unit_m4(mtx); | ||||
| mtx[axis][axis] = -1.0f; | mtx[axis][axis] = -1.0f; | ||||
| if (mmd->mirror_ob || (mmd->flag & MOD_MIR_WORLD_ORIGIN)) { | |||||
| float mirror_obmat[4][4]; | |||||
| unit_m4(mirror_obmat); | |||||
| if (mmd->mirror_ob) { | if (mmd->mirror_ob) { | ||||
| copy_m4_m4(mirror_obmat, mmd->mirror_ob->obmat); | |||||
| } | |||||
| float tmp[4][4]; | float tmp[4][4]; | ||||
| float itmp[4][4]; | float itmp[4][4]; | ||||
| /* tmp is a transform from coords relative to the object's own origin, | /* tmp is a transform from coords relative to the object's own origin, | ||||
| * to coords relative to the mirror object origin */ | * to coords relative to the mirror object origin */ | ||||
| invert_m4_m4(tmp, mmd->mirror_ob->obmat); | invert_m4_m4(tmp, mirror_obmat); | ||||
| mul_m4_m4m4(tmp, tmp, ob->obmat); | mul_m4_m4m4(tmp, tmp, ob->obmat); | ||||
| /* itmp is the reverse transform back to origin-relative coordinates */ | /* itmp is the reverse transform back to origin-relative coordinates */ | ||||
| invert_m4_m4(itmp, tmp); | invert_m4_m4(itmp, tmp); | ||||
| /* combine matrices to get a single matrix that translates coordinates into | /* combine matrices to get a single matrix that translates coordinates into | ||||
| * mirror-object-relative space, does the mirror, and translates back to | * mirror-object-relative space, does the mirror, and translates back to | ||||
| * origin-relative space */ | * origin-relative space */ | ||||
| mul_m4_m4m4(mtx, mtx, tmp); | mul_m4_m4m4(mtx, mtx, tmp); | ||||
| mul_m4_m4m4(mtx, itmp, mtx); | mul_m4_m4m4(mtx, itmp, mtx); | ||||
| } | } | ||||
| if (do_bisect) | |||||
| { | |||||
| mesh = biscetAlongMirrorPlane(mmd, ob, mesh, axis, mtx); | |||||
| } | |||||
| 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( | result = BKE_mesh_new_nomain_from_template( | ||||
| mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); | mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); | ||||
| /*copy customdata to original geometry*/ | /*copy customdata to original geometry*/ | ||||
| CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); | CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); | ||||
| CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); | CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); | CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); | ||||
| CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); | CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); | ||||
| /* Subsurf for eg won't have mesh data in the custom data arrays. | /* Subsurf for eg won't have mesh data in the custom data arrays. | ||||
| ▲ Show 20 Lines • Show All 242 Lines • Show Last 20 Lines | |||||
Might want this to be user editable, not essential for initial patch.