Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2020-11-08 16:39:01 +0300
committerHoward Trickey <howard.trickey@gmail.com>2020-11-08 18:12:53 +0300
commit39012146e142bf400c7140d90ecfd27c45b589ca (patch)
tree2671e7fbc63c485fe15bb91737e2380326b27a2c
parent7be47dadea5066ae095c644e0b4f1f10d75f5ab3 (diff)
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.
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc4
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc37
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h4
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c13
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c5
6 files changed, 49 insertions, 16 deletions
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<BMFace *>(BM_iter_new(&iter, NULL, BM_FACES_OF_VERT, bmv)); bmf;
+ bmf = static_cast<BMFace *>(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<BMFace *> 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<blender::meshintersect::BoolOpType>(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);