diff --git a/source/blender/editors/mesh/editmesh_mask_extract.cc b/source/blender/editors/mesh/editmesh_mask_extract.cc index bb80f607918..04ed5445de0 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.cc +++ b/source/blender/editors/mesh/editmesh_mask_extract.cc @@ -246,6 +246,10 @@ static void geometry_extract_tag_masked_faces(BMesh *bm, GeometryExtractParams * bool keep_face = true; BMVert *v; BMIter face_iter; + if (BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN)) { + BM_elem_flag_set(f, BM_ELEM_TAG, true); + continue; + }; BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) { const float mask = BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); if (mask < threshold) { @@ -417,6 +421,10 @@ static void slice_paint_mask(BMesh *bm, bool invert, bool fill_holes, float mask break; } } + if (BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN)) { + keep_face = false; + }; + /* This invert behavior is fragile, as it potentially marks faces which are hidden */ if (invert) { keep_face = !keep_face; } diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index 2c113e3fe71..2dda7b4a5b2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -672,9 +672,15 @@ static int create_op_exec(bContext *C, wmOperator *op) case CreateMode::Selection: { const VArraySpan select_poly = *attributes.lookup_or_default( ".select_poly", bke::AttrDomain::Face, false); + const VArraySpan hide_poly = *attributes.lookup(".hide_poly", + bke::AttrDomain::Face); + face_sets_update(object, nodes, [&](const Span indices, MutableSpan face_sets) { for (const int i : indices.index_range()) { if (select_poly[indices[i]]) { + if (!hide_poly.is_empty() && hide_poly[i]) { + continue; + } face_sets[i] = next_face_set; } } @@ -759,14 +765,24 @@ static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn) faces, corner_edges, edges.size(), ss.edge_to_face_offsets, ss.edge_to_face_indices); } + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArraySpan hide_poly = *attributes.lookup(".hide_poly", bke::AttrDomain::Face); + const Set hidden_face_sets = gather_hidden_face_sets(hide_poly, face_sets.span); + int next_face_set = 1; for (const int i : faces.index_range()) { + if (!hide_poly.is_empty() && hide_poly[i]) { + continue; + } if (visited_faces[i]) { continue; } std::queue queue; + while (hidden_face_sets.contains(next_face_set)) { + next_face_set += 1; + } face_sets.span[i] = next_face_set; visited_faces[i].set(true); queue.push(i); @@ -783,6 +799,9 @@ static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn) if (visited_faces[neighbor_i]) { continue; } + if (!hide_poly.is_empty() && hide_poly[neighbor_i]) { + continue; + } if (!test_fn(face_i, edge_i, neighbor_i)) { continue; } @@ -800,6 +819,22 @@ static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn) face_sets.finish(); } +Set gather_hidden_face_sets(const Span hide_poly, const Span face_sets) +{ + if (hide_poly.is_empty()) { + return {}; + } + + Set hidden_face_sets; + for (const int i : hide_poly.index_range()) { + if (hide_poly[i]) { + hidden_face_sets.add(face_sets[i]); + } + } + + return hidden_face_sets; +} + static int init_op_exec(bContext *C, wmOperator *op) { Object &ob = *CTX_data_active_object(C); @@ -851,8 +886,25 @@ static int init_op_exec(bContext *C, wmOperator *op) bke::SpanAttributeWriter face_sets = ensure_face_sets_mesh(ob); const VArraySpan material_indices = *attributes.lookup_or_default( "material_index", bke::AttrDomain::Face, 0); + const VArraySpan hide_poly = *attributes.lookup(".hide_poly", + bke::AttrDomain::Face); + const Set hidden_face_sets = gather_hidden_face_sets(hide_poly, face_sets.span); + + int prev_material = material_indices[0]; + int material_face_set = 1; for (const int i : IndexRange(mesh->faces_num)) { - face_sets.span[i] = material_indices[i] + 1; + if (!hide_poly.is_empty() && hide_poly[i]) { + continue; + } + if (prev_material != material_indices[i]) { + material_face_set += 1; + } + while (hidden_face_sets.contains(material_face_set)) { + material_face_set += 1; + } + + face_sets.span[i] = material_face_set; + prev_material = material_indices[i]; } face_sets.finish(); break; @@ -1656,7 +1708,7 @@ void SCULPT_OT_face_sets_edit(wmOperatorType *ot) ot->prop = RNA_def_boolean(ot->srna, "modify_hidden", - true, + false, "Modify Hidden", "Apply the edit operation to hidden geometry"); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index 5d0c362e29a..459e9cd23b4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -974,6 +974,7 @@ bool vert_has_unique_face_set(const SculptSession &ss, PBVHVertRef vertex); bke::SpanAttributeWriter ensure_face_sets_mesh(Object &object); int ensure_face_sets_bmesh(Object &object); Array duplicate_face_sets(const Mesh &mesh); +Set gather_hidden_face_sets(Span hide_poly, Span face_sets); }