Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_mirror.cc
- This file was moved from source/blender/blenkernel/intern/mesh_mirror.c.
| Show All 36 Lines | Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mmd, | ||||
| const float bisect_distance = mmd->bisect_threshold; | const float bisect_distance = mmd->bisect_threshold; | ||||
| Mesh *result; | Mesh *result; | ||||
| BMesh *bm; | BMesh *bm; | ||||
| BMIter viter; | BMIter viter; | ||||
| BMVert *v, *v_next; | BMVert *v, *v_next; | ||||
| bm = BKE_mesh_to_bmesh_ex(mesh, | BMeshCreateParams bmesh_create_params{0}; | ||||
| &(struct BMeshCreateParams){0}, | |||||
| &(struct BMeshFromMeshParams){ | BMeshFromMeshParams bmesh_from_mesh_params{}; | ||||
| .calc_face_normal = true, | bmesh_from_mesh_params.calc_face_normal = true; | ||||
| .calc_vert_normal = true, | bmesh_from_mesh_params.calc_vert_normal = true; | ||||
| .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, | bmesh_from_mesh_params.cd_mask_extra.vmask = CD_MASK_ORIGINDEX; | ||||
| .emask = CD_MASK_ORIGINDEX, | bmesh_from_mesh_params.cd_mask_extra.emask = CD_MASK_ORIGINDEX; | ||||
| .pmask = CD_MASK_ORIGINDEX}, | bmesh_from_mesh_params.cd_mask_extra.pmask = CD_MASK_ORIGINDEX; | ||||
| }); | |||||
| bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); | |||||
| /* Define bisecting plane (aka mirror plane). */ | /* Define bisecting plane (aka mirror plane). */ | ||||
| float plane[4]; | float plane[4]; | ||||
| if (!do_bisect_flip_axis) { | if (!do_bisect_flip_axis) { | ||||
| /* That reversed condition is a little weird, but for some reason that's how you keep | /* That reversed condition is a little weird, but for some reason that's how you keep | ||||
| * the part of the mesh which is on the non-mirrored side when flip option is disabled. | * the part of the mesh which is on the non-mirrored side when flip option is disabled. | ||||
| * I think this is the expected behavior. */ | * I think this is the expected behavior. */ | ||||
| negate_v3(plane_no); | negate_v3(plane_no); | ||||
| Show All 9 Lines | Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mmd, | ||||
| /* Delete verts across the mirror plane. */ | /* Delete verts across the mirror plane. */ | ||||
| BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { | ||||
| if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { | if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { | ||||
| BM_vert_kill(bm, v); | BM_vert_kill(bm, v); | ||||
| } | } | ||||
| } | } | ||||
| result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); | result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); | ||||
| BM_mesh_free(bm); | BM_mesh_free(bm); | ||||
| return result; | return result; | ||||
| } | } | ||||
| void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain, | void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| const int axis, | const int axis, | ||||
| const float dist) | const float dist) | ||||
| { | { | ||||
| BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, | BMeshCreateParams bmesh_create_params{}; | ||||
| &(struct BMeshCreateParams){ | bmesh_create_params.use_toolflags = 1; | ||||
| .use_toolflags = 1, | |||||
| }, | BMeshFromMeshParams bmesh_from_mesh_params{}; | ||||
| &(struct BMeshFromMeshParams){ | bmesh_from_mesh_params.calc_face_normal = true; | ||||
| .calc_face_normal = true, | bmesh_from_mesh_params.calc_vert_normal = true; | ||||
| .calc_vert_normal = true, | bmesh_from_mesh_params.cd_mask_extra.vmask = CD_MASK_SHAPEKEY; | ||||
| .cd_mask_extra = | |||||
| { | BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); | ||||
| .vmask = CD_MASK_SHAPEKEY, | |||||
| }, | |||||
| }); | |||||
| BMO_op_callf(bm, | BMO_op_callf(bm, | ||||
| (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), | (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), | ||||
| "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b", | "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b", | ||||
| axis, | axis, | ||||
| dist, | dist, | ||||
| true); | true); | ||||
| BM_mesh_bm_to_me(bmain, | BMeshToMeshParams bmesh_to_mesh_params{}; | ||||
| bm, | bmesh_to_mesh_params.calc_object_remap = true; | ||||
| mesh, | |||||
| (&(struct BMeshToMeshParams){ | |||||
| .calc_object_remap = true, | |||||
| })); | BM_mesh_bm_to_me(bmain, bm, mesh, &bmesh_to_mesh_params); | ||||
| BM_mesh_free(bm); | BM_mesh_free(bm); | ||||
| } | } | ||||
| Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, | Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, | ||||
| Object *ob, | Object *ob, | ||||
| const Mesh *mesh, | const Mesh *mesh, | ||||
| const int axis, | const int axis, | ||||
| const bool use_correct_order_on_merge) | const bool use_correct_order_on_merge) | ||||
| Show All 10 Lines | Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, | ||||
| 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]; | ||||
| float plane_co[3], plane_no[3]; | float plane_co[3], plane_no[3]; | ||||
| int i; | int i; | ||||
| int a, totshape; | int a, totshape; | ||||
| int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; | int *vtargetmap = nullptr, *vtmap_a = nullptr, *vtmap_b = nullptr; | ||||
| /* 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; | ||||
| Object *mirror_ob = mmd->mirror_ob; | Object *mirror_ob = mmd->mirror_ob; | ||||
| if (mirror_ob != NULL) { | if (mirror_ob != nullptr) { | ||||
| 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, mirror_ob->object_to_world); | invert_m4_m4(tmp, mirror_ob->object_to_world); | ||||
| mul_m4_m4m4(tmp, tmp, ob->object_to_world); | mul_m4_m4m4(tmp, tmp, ob->object_to_world); | ||||
| Show All 24 Lines | if (mirror_ob != nullptr) { | ||||
| } | } | ||||
| } | } | ||||
| else if (do_bisect) { | else if (do_bisect) { | ||||
| copy_v3_v3(plane_co, mtx[3]); | copy_v3_v3(plane_co, mtx[3]); | ||||
| /* Need to negate here, since that axis is inverted (for mirror transform). */ | /* Need to negate here, since that axis is inverted (for mirror transform). */ | ||||
| negate_v3_v3(plane_no, mtx[axis]); | negate_v3_v3(plane_no, mtx[axis]); | ||||
| } | } | ||||
| Mesh *mesh_bisect = NULL; | Mesh *mesh_bisect = nullptr; | ||||
| if (do_bisect) { | if (do_bisect) { | ||||
| mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier( | mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier( | ||||
| mmd, mesh, axis, plane_co, plane_no); | mmd, mesh, axis, plane_co, plane_no); | ||||
| mesh = mesh_bisect; | mesh = mesh_bisect; | ||||
| } | } | ||||
| const int maxVerts = mesh->totvert; | const int maxVerts = mesh->totvert; | ||||
| const int maxEdges = mesh->totedge; | const int maxEdges = mesh->totedge; | ||||
| Show All 26 Lines | Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, | ||||
| * copy from itself because this data may have been created in the checks above. */ | * copy from itself because this data may have been created in the checks above. */ | ||||
| CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); | CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); | ||||
| CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); | CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); | ||||
| /* loops are copied later */ | /* loops are copied later */ | ||||
| CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys); | CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys); | ||||
| if (do_vtargetmap) { | if (do_vtargetmap) { | ||||
| /* second half is filled with -1 */ | /* second half is filled with -1 */ | ||||
| vtargetmap = MEM_malloc_arrayN(maxVerts, sizeof(int[2]), "MOD_mirror tarmap"); | vtargetmap = static_cast<int *>( | ||||
| MEM_malloc_arrayN(maxVerts, sizeof(int[2]), "MOD_mirror tarmap")); | |||||
| vtmap_a = vtargetmap; | vtmap_a = vtargetmap; | ||||
| vtmap_b = vtargetmap + maxVerts; | vtmap_b = vtargetmap + maxVerts; | ||||
| } | } | ||||
| /* mirror vertex coordinates */ | /* mirror vertex coordinates */ | ||||
| mv_prev = BKE_mesh_verts_for_write(result); | mv_prev = BKE_mesh_verts_for_write(result); | ||||
| mv = mv_prev + maxVerts; | mv = mv_prev + maxVerts; | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (do_vtargetmap) { | ||||
| vtmap_a++; | vtmap_a++; | ||||
| vtmap_b++; | vtmap_b++; | ||||
| } | } | ||||
| } | } | ||||
| /* handle shape keys */ | /* handle shape keys */ | ||||
| totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY); | totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY); | ||||
| for (a = 0; a < totshape; a++) { | for (a = 0; a < totshape; a++) { | ||||
| float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a); | float(*cos)[3] = static_cast<float(*)[3]>( | ||||
| CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a)); | |||||
| for (i = maxVerts; i < result->totvert; i++) { | for (i = maxVerts; i < result->totvert; i++) { | ||||
| mul_m4_v3(mtx, cos[i]); | mul_m4_v3(mtx, cos[i]); | ||||
| } | } | ||||
| } | } | ||||
| /* adjust mirrored edge vertex indices */ | /* adjust mirrored edge vertex indices */ | ||||
| me = BKE_mesh_edges_for_write(result) + maxEdges; | me = BKE_mesh_edges_for_write(result) + maxEdges; | ||||
| for (i = 0; i < maxEdges; i++, me++) { | for (i = 0; i < maxEdges; i++, me++) { | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || | ||||
| const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; | const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; | ||||
| const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; | const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; | ||||
| /* If set, flip around center of each tile. */ | /* If set, flip around center of each tile. */ | ||||
| const bool do_mirr_udim = (mmd->flag & MOD_MIR_MIRROR_UDIM) != 0; | const bool do_mirr_udim = (mmd->flag & MOD_MIR_MIRROR_UDIM) != 0; | ||||
| const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); | const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); | ||||
| for (a = 0; a < totuv; a++) { | for (a = 0; a < totuv; a++) { | ||||
| MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a); | MLoopUV *dmloopuv = static_cast<MLoopUV *>( | ||||
| CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a)); | |||||
| int j = maxLoops; | int j = maxLoops; | ||||
| dmloopuv += j; /* second set of loops only */ | dmloopuv += j; /* second set of loops only */ | ||||
| for (; j-- > 0; dmloopuv++) { | for (; j-- > 0; dmloopuv++) { | ||||
| if (do_mirr_u) { | if (do_mirr_u) { | ||||
| float u = dmloopuv->uv[0]; | float u = dmloopuv->uv[0]; | ||||
| if (do_mirr_udim) { | if (do_mirr_udim) { | ||||
| dmloopuv->uv[0] = ceilf(u) - fmodf(u, 1.0f) + mmd->uv_offset[0]; | dmloopuv->uv[0] = ceilf(u) - fmodf(u, 1.0f) + mmd->uv_offset[0]; | ||||
| } | } | ||||
| Show All 16 Lines | if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || | ||||
| } | } | ||||
| } | } | ||||
| /* handle custom split normals */ | /* handle custom split normals */ | ||||
| if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && | if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && | ||||
| CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) { | CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) { | ||||
| const int totloop = result->totloop; | const int totloop = result->totloop; | ||||
| const int totpoly = result->totpoly; | const int totpoly = result->totpoly; | ||||
| float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__); | float(*loop_normals)[3] = static_cast<float(*)[3]>( | ||||
| MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__)); | |||||
| CustomData *ldata = &result->ldata; | CustomData *ldata = &result->ldata; | ||||
| short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); | short(*clnors)[2] = static_cast<short(*)[2]>(CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL)); | ||||
| MLoopNorSpaceArray lnors_spacearr = {NULL}; | MLoopNorSpaceArray lnors_spacearr = {nullptr}; | ||||
| /* The transform matrix of a normal must be | /* The transform matrix of a normal must be | ||||
| * the transpose of inverse of transform matrix of the geometry... */ | * the transpose of inverse of transform matrix of the geometry... */ | ||||
| float mtx_nor[4][4]; | float mtx_nor[4][4]; | ||||
| invert_m4_m4(mtx_nor, mtx); | invert_m4_m4(mtx_nor, mtx); | ||||
| transpose_m4(mtx_nor); | transpose_m4(mtx_nor); | ||||
| /* calculate custom normals into loop_normals, then mirror first half into second half */ | /* calculate custom normals into loop_normals, then mirror first half into second half */ | ||||
| BKE_mesh_normals_loop_split(BKE_mesh_verts(result), | BKE_mesh_normals_loop_split(BKE_mesh_verts(result), | ||||
| BKE_mesh_vertex_normals_ensure(result), | BKE_mesh_vertex_normals_ensure(result), | ||||
| result->totvert, | result->totvert, | ||||
| BKE_mesh_edges(result), | BKE_mesh_edges(result), | ||||
| result->totedge, | result->totedge, | ||||
| BKE_mesh_loops(result), | BKE_mesh_loops(result), | ||||
| loop_normals, | loop_normals, | ||||
| totloop, | totloop, | ||||
| BKE_mesh_polys(result), | BKE_mesh_polys(result), | ||||
| BKE_mesh_poly_normals_ensure(result), | BKE_mesh_poly_normals_ensure(result), | ||||
| totpoly, | totpoly, | ||||
| true, | true, | ||||
| mesh->smoothresh, | mesh->smoothresh, | ||||
| NULL, | nullptr, | ||||
| &lnors_spacearr, | &lnors_spacearr, | ||||
| clnors); | clnors); | ||||
| /* mirroring has to account for loops being reversed in polys in second half */ | /* mirroring has to account for loops being reversed in polys in second half */ | ||||
| MPoly *result_polys = BKE_mesh_polys_for_write(result); | MPoly *result_polys = BKE_mesh_polys_for_write(result); | ||||
| mp = result_polys; | mp = result_polys; | ||||
| for (i = 0; i < maxPolys; i++, mp++) { | for (i = 0; i < maxPolys; i++, mp++) { | ||||
| MPoly *mpmirror = result_polys + maxPolys + i; | MPoly *mpmirror = result_polys + maxPolys + i; | ||||
| Show All 13 Lines | if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && | ||||
| MEM_freeN(loop_normals); | MEM_freeN(loop_normals); | ||||
| BKE_lnor_spacearr_free(&lnors_spacearr); | BKE_lnor_spacearr_free(&lnors_spacearr); | ||||
| } | } | ||||
| /* handle vgroup stuff */ | /* handle vgroup stuff */ | ||||
| if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) { | if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) { | ||||
| MDeformVert *dvert = BKE_mesh_deform_verts_for_write(result) + maxVerts; | MDeformVert *dvert = BKE_mesh_deform_verts_for_write(result) + maxVerts; | ||||
| int *flip_map = NULL, flip_map_len = 0; | int *flip_map = nullptr, flip_map_len = 0; | ||||
| flip_map = BKE_object_defgroup_flip_map(ob, false, &flip_map_len); | flip_map = BKE_object_defgroup_flip_map(ob, false, &flip_map_len); | ||||
| if (flip_map) { | if (flip_map) { | ||||
| for (i = 0; i < maxVerts; dvert++, i++) { | for (i = 0; i < maxVerts; dvert++, i++) { | ||||
| /* merged vertices get both groups, others get flipped */ | /* merged vertices get both groups, others get flipped */ | ||||
| if (use_correct_order_on_merge && do_vtargetmap && (vtargetmap[i + maxVerts] != -1)) { | if (use_correct_order_on_merge && do_vtargetmap && (vtargetmap[i + maxVerts] != -1)) { | ||||
| BKE_defvert_flip_merged(dvert - maxVerts, flip_map, flip_map_len); | BKE_defvert_flip_merged(dvert - maxVerts, flip_map, flip_map_len); | ||||
| Show All 15 Lines | if (do_vtargetmap) { | ||||
| * users may leave this on and not realize there is nothing to merge - campbell */ | * users may leave this on and not realize there is nothing to merge - campbell */ | ||||
| if (tot_vtargetmap) { | if (tot_vtargetmap) { | ||||
| result = BKE_mesh_merge_verts( | result = BKE_mesh_merge_verts( | ||||
| result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED); | result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED); | ||||
| } | } | ||||
| MEM_freeN(vtargetmap); | MEM_freeN(vtargetmap); | ||||
| } | } | ||||
| if (mesh_bisect != NULL) { | if (mesh_bisect != nullptr) { | ||||
| BKE_id_free(NULL, mesh_bisect); | BKE_id_free(nullptr, mesh_bisect); | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||