From 39012146e142bf400c7140d90ecfd27c45b589ca Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sun, 8 Nov 2020 08:39:01 -0500 Subject: Fix T81651, exact boolean modifier incorrect if operand hidden. The code was trying to ignore hidden geometry when doing boolean, which is correct when used as a tool, but not when a modifier. Added a "keep_hidden" argument to bmesh_boolean to distinguish the two cases. Also fixed a bug when the tool is used with hidden geometry that is attached to unhidden geometry that is deleted by the operation. --- source/blender/blenlib/intern/mesh_boolean.cc | 4 ++- source/blender/bmesh/tools/bmesh_boolean.cc | 37 +++++++++++++++++++----- source/blender/bmesh/tools/bmesh_boolean.h | 4 ++- source/blender/editors/mesh/editmesh_intersect.c | 13 +++++++-- source/blender/editors/sculpt_paint/paint_mask.c | 2 +- source/blender/modifiers/intern/MOD_boolean.c | 5 ++-- 6 files changed, 49 insertions(+), 16 deletions(-) (limited to 'source') diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index c85adf835fe..4ff5afdb05f 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -428,7 +428,9 @@ class Cell { BoolOpType bool_optype) { std::copy(from_cell.winding().begin(), from_cell.winding().end(), winding_.begin()); - winding_[shape] += delta; + if (shape >= 0) { + winding_[shape] += delta; + } winding_assigned_ = true; in_output_volume_ = apply_bool_op(bool_optype, winding_); } diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index 7c3c37e35c3..4a36db3b353 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -116,6 +116,18 @@ static bool bmvert_attached_to_wire(const BMVert *bmv) return BM_vert_is_wire(bmv); } +static bool bmvert_attached_to_hidden_face(BMVert *bmv) +{ + BMIter iter; + for (BMFace *bmf = static_cast(BM_iter_new(&iter, NULL, BM_FACES_OF_VERT, bmv)); bmf; + bmf = static_cast(BM_iter_step(&iter))) { + if (BM_elem_flag_test(bmf, BM_ELEM_HIDDEN)) { + return true; + } + } + return false; +} + static bool face_has_verts_in_order(BMesh *bm, BMFace *bmf, const BMVert *v1, const BMVert *v2) { BMIter liter; @@ -139,17 +151,19 @@ constexpr uint KEEP_FLAG = (1 << 6); * Also, the #BM_ELEM_TAG header flag is set for those #BMEdge's that come from intersections * resulting from the intersection needed by the Boolean operation. */ -static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out) +static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out, bool keep_hidden) { bool any_change = false; m_out.populate_vert(); /* Initially mark all existing verts as "don't keep", except hidden verts - * and verts attached to wire edges. */ + * (if keep_hidden is true), and verts attached to wire edges. */ for (int v = 0; v < bm->totvert; ++v) { BMVert *bmv = BM_vert_at_index(bm, v); - if (BM_elem_flag_test(bmv, BM_ELEM_HIDDEN) || bmvert_attached_to_wire(bmv)) { + if ((keep_hidden && + (BM_elem_flag_test(bmv, BM_ELEM_HIDDEN) || bmvert_attached_to_hidden_face(bmv))) || + bmvert_attached_to_wire(bmv)) { BM_elem_flag_enable(bmv, KEEP_FLAG); } else { @@ -190,14 +204,14 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out) } } - /* Initially mark all existing faces as "don't keep", except hidden faces. + /* Initially mark all existing faces as "don't keep", except hidden faces (if keep_hidden). * Also, save current #BMFace pointers as creating faces will disturb the table. */ Array old_bmfs(bm->totface); BM_mesh_elem_index_ensure(bm, BM_FACE); for (int f = 0; f < bm->totface; ++f) { BMFace *bmf = BM_face_at_index(bm, f); old_bmfs[f] = bmf; - if (BM_elem_flag_test(bmf, BM_ELEM_HIDDEN)) { + if (keep_hidden && BM_elem_flag_test(bmf, BM_ELEM_HIDDEN)) { BM_elem_flag_enable(bmf, KEEP_FLAG); } else { @@ -334,6 +348,7 @@ static bool bmesh_boolean(BMesh *bm, int nshapes, const bool use_self, const bool use_separate_all, + const bool keep_hidden, const BoolOpType boolean_mode) { IMeshArena arena; @@ -363,7 +378,7 @@ static bool bmesh_boolean(BMesh *bm, } IMesh m_out = boolean_mesh( m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena); - bool any_change = apply_mesh_output_to_bmesh(bm, m_out); + bool any_change = apply_mesh_output_to_bmesh(bm, m_out, keep_hidden); if (use_separate_all) { /* We are supposed to separate all faces that are incident on intersection edges. */ BM_mesh_edgesplit(bm, false, true, false); @@ -400,6 +415,7 @@ bool BM_mesh_boolean(BMesh *bm, void *user_data, const int nshapes, const bool use_self, + const bool keep_hidden, const int boolean_mode) { return blender::meshintersect::bmesh_boolean( @@ -411,6 +427,7 @@ bool BM_mesh_boolean(BMesh *bm, nshapes, use_self, false, + keep_hidden, static_cast(boolean_mode)); } @@ -429,7 +446,8 @@ bool BM_mesh_boolean_knife(BMesh *bm, void *user_data, const int nshapes, const bool use_self, - const bool use_separate_all) + const bool use_separate_all, + const bool keep_hidden) { return blender::meshintersect::bmesh_boolean(bm, looptris, @@ -439,6 +457,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, nshapes, use_self, use_separate_all, + keep_hidden, blender::meshintersect::BoolOpType::None); } #else @@ -449,6 +468,7 @@ bool BM_mesh_boolean(BMesh *UNUSED(bm), void *UNUSED(user_data), const int UNUSED(nshapes), const bool UNUSED(use_self), + const bool UNUSED(keep_hidden), const int UNUSED(boolean_mode)) { UNUSED_VARS(looptris, test_fn); @@ -470,7 +490,8 @@ bool BM_mesh_boolean_knife(BMesh *UNUSED(bm), void *UNUSED(user_data), const int UNUSED(nshapes), const bool UNUSED(use_self), - const bool UNUSED(use_separate_all)) + const bool UNUSED(use_separate_all), + const bool UNUSED(keep_boolean)) { UNUSED_VARS(looptris, test_fn); return false; diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h index 04b5205ec84..2cc32e143fc 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.h +++ b/source/blender/bmesh/tools/bmesh_boolean.h @@ -31,6 +31,7 @@ bool BM_mesh_boolean(BMesh *bm, void *user_data, const int nshapes, const bool use_self, + const bool keep_hidden, const int boolean_mode); bool BM_mesh_boolean_knife(BMesh *bm, @@ -40,7 +41,8 @@ bool BM_mesh_boolean_knife(BMesh *bm, void *user_data, const int nshapes, const bool use_self, - const bool use_separate_all); + const bool use_separate_all, + const bool keep_hidden); #ifdef __cplusplus } diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index e2112f91060..ff4867454d6 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -204,8 +204,15 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) if (exact) { int nshapes = use_self ? 1 : 2; - has_isect = BM_mesh_boolean_knife( - em->bm, em->looptris, em->tottri, test_fn, NULL, nshapes, use_self, use_separate_all); + has_isect = BM_mesh_boolean_knife(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + nshapes, + use_self, + use_separate_all, + true); } else { has_isect = BM_mesh_intersect(em->bm, @@ -369,7 +376,7 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) if (use_exact) { has_isect = BM_mesh_boolean( - em->bm, em->looptris, em->tottri, test_fn, NULL, 2, use_self, boolean_operation); + em->bm, em->looptris, em->tottri, test_fn, NULL, 2, use_self, true, boolean_operation); } else { has_isect = BM_mesh_intersect(em->bm, diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 5ee38069fd9..f29a84a6eb7 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1293,7 +1293,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext) BLI_assert(false); break; } - BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, boolean_mode); + BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, boolean_mode); } MEM_freeN(looptris); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 1cf57669eb1..7fea06ba955 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -380,7 +380,8 @@ static void BMD_mesh_intersection(BMesh *bm, #endif if (use_exact) { - BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, bmd->operation); + BM_mesh_boolean( + bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, bmd->operation); } else { BM_mesh_intersect(bm, @@ -543,7 +544,7 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd, BM_mesh_elem_index_ensure(bm, BM_FACE); BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_nary, shape, num_shapes, true, bmd->operation); + bm, looptris, tottri, bm_face_isect_nary, shape, num_shapes, true, false, bmd->operation); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); -- cgit v1.2.3